忍者ブログ

ぢみへんプログラミング日誌

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

ActiveRecodeをもう少しSQLライクに使えるようにする

Rails4を使っていると、scopeメソッドを利用してActiveRecord(以下ARと略)を拡張することができると分かり、それならARで共通に使えるモジュールを作ったらいいじゃん、ということに。
module Scope
def self.included(klass)
klass.extend ActiveRecord::ConnectionAdapters::Quoting
klass.class_eval{
scope :eq, ->(h){ where("#{h.keys.first.to_s} = #{quote(h.values.first)}") }
scope :not_eq, ->(h){ where("#{h.keys.first.to_s} != #{quote(h.values.first)}") }
scope :lt, ->(h){ where("#{h.keys.first.to_s} < #{quote(h.values.first)}") }
scope :less_than, ->(h){ where("#{h.keys.first.to_s} < #{quote(h.values.first)}") }
scope :lt_eql, ->(h){ where("#{h.keys.first.to_s} <= #{quote(h.values.first)}") }
scope :less_than_eql, ->(h){ where("#{h.keys.first.to_s} <= #{quote(h.values.first)}") }
scope :gt, ->(h){ where("#{h.keys.first.to_s} > #{quote(h.values.first)}") }
scope :greater_than, ->(h){ where("#{h.keys.first.to_s} > #{quote(h.values.first)}") }
scope :gt_eql, ->(h){ where("#{h.keys.first.to_s} >= #{quote(h.values.first)}") }
scope :greater_than_eql, ->(h){ where("#{h.keys.first.to_s} >= #{quote(h.values.first)}") }
scope :like, ->(h){ where("#{h.keys.first.to_s} like #{quote(h.values.first)}") }
}
end
end



これを使うには
class Book < ActiveRecord::Base
include Scope
end



とAR側でincludeし、
# 「あした」で中間一致する書名を持つ本のレコードを取得
books = Book.like(name: '%あした%').to_a

# 「あした」で中間一致する書名を持ち、4日前以降に出版された本のレコードを取得
books = Book.like(name: '%あした%').gt(publication_date: (Date.today - 5)).to_a



という具合に使うことができる。

ちなみにRails4からはActiveRecord::Relationというクラスが導入されていて、Rails3ではActiveRecordのwhereメソッド(正確にはActiveRecord::Base#where)の戻り値はARの配列だったが、4ではRelationが返ってくる。このクラスは言ってみればSQL生成器とでもいうべき機能を持っていて、#to_sql を呼び出すとその時点で蓄えている情報からSQL文を生成する。上記の例でいえばこんな感じだ。
irb > relation = Book.like(name: '%あした%')
irb > relation.to_sql
=> "SELECT \"books\".* FROM \"books\" WHERE (name like '%あした%')"



しかもチェーンしていけるので便利。
Book.where(name: 'あいうえお').where(auther: 'ほげ')




RelationからARの配列(複数レコード)が欲しければto_aメソッド、1レコードだけ欲しければtakeメソッドを使えば良い。

Rails4ではARに用意されたscopeメソッドを使うと頻繁使うwhereメソッドの記述を簡便化できるので、これは大いに使った方が良いと思える。特にwhereメソッドでハッシュ記法を使うとSQL文は等価比較しかできないのでlikeや < といった演算子はそのままでは使えない。そういった部分を補完する意味でも役に立つ。
なお、whereメソッドを使ってSQLの「in」を指定したい場合は、配列を使い、範囲(between)を使いたい場合はRangeクラスが利用できる。

# select * from books where author_name in (select name from authors where name = 'ほげ' の場合
Book.where(author_name: Author.where(name: 'ほげ').pluck(:name))

# 1年前から今日までの間を指定
# select * from books where publication_date between '2012-09-12' AND '2013-09-12'
# というSQL文を生成する
Book.where(publication_date: ((Date.today - 365)..Date.today))
PR

ruby-1.9.3-p392とrails3.2.13 を CentOS 6.4 にインストールするまで (その後)

Rails が入ったのはいいが、まだ一つ課題が残っていた。
それは…

DB

PostgreSQLを使用するRailsのプロジェクトなので、当然このRDBSを使用するようにまずはPostgreSQLをインストールしなければいけない。バージョンは9.2。
CentOS 6.4 が標準でyumに保持しているのはバージョン8までのpostgreSQLなので、その辺も乗り越えなければいけない。まあ、知っている人からすれば大したことじゃないんだろうけどね。

そうはいってもこちらはズブの素人であるからして、何をするにも不安なのは仕方ない。色々探してみて、ここのページにお世話になりました。
迷い家の白猫 技術部 CentOS 6.3にPostgreSQL9.2をインストール
ほぼここに書かれている通りのことをなぞったらうまく行った。ありがとうございます、先輩。
一応備忘録としてポイントを残しておく。


パッケージはPostgreSQLの提供するRPMリポジトリから入手


PostgreSQLは有難いことにRedhat系のLinuxOSに対してパッケージ(RPM)を用意してくれているようだ。[PostgreSQL RPM Building Project - Repository Packages]
そもそもRPMが何かということすら良く分かってない筆者が訳知り顔で言うのもおこがましいが、ここからRDBSをパッケージごと入手するのがベターのようだ。

> wget -P /tmp http://yum.postgresql.org/9.2/redhat/rhel-6-x86_64/pgdg-centos92-9.2-6.noarch.rpm
> rpm -ivh /tmp/pgdg-centos92-9.2-6.noarch.rpm
> yum list | grep postgresql92
postgresql92.x86_64 9.2.4-1PGDG.rhel6 pgdg92
postgresql92-contrib.x86_64 9.2.4-1PGDG.rhel6 pgdg92
postgresql92-devel.x86_64 9.2.4-1PGDG.rhel6 pgdg92
postgresql92-libs.x86_64 9.2.4-1PGDG.rhel6 pgdg92
postgresql92-server.x86_64 9.2.4-1PGDG.rhel6 pgdg92

yumは以下の通り

> yum install -y postgresql92-server.x86_64 postgresql92-devel.x86_64 postgresql92-contrib.x86_64
...
...
Installed:
postgresql92-contrib.x86_64 0:9.2.4-1PGDG.rhel6 postgresql92-devel.x86_64 0:9.2.4-1PGDG.rhel6 postgresql92-server.x86_64 0:9.2.4-1PGDG.rhel6

Dependency Installed:
postgresql92.x86_64 0:9.2.4-1PGDG.rhel6 postgresql92-libs.x86_64 0:9.2.4-1PGDG.rhel6 uuid.x86_64 0:1.6.1-10.el6

Complete!


インストール後の作業


インストールが完了したらシステムの初期化と利用する上での設定を行う。ファイル権限等で失敗することがあるので注意。ちなみにpostgresユーザーはシステムインストール時に勝手にできるもの?なのか既に存在していた。いなければ作らなければならないのだろうが、その設定は調べてない……

> vi /var/lib/pgsql/9.2/data/postgresql.conf
listen_addresses = '*' # この行だけこのように変更
# shift + zz で保存終了

#システムのスーパーユーザーをpostgres, 文字コードをUTF-8に設定
> /etc/rc.d/init.d/postgresql-9.2 initdb -E UTF-8 -U postgres

> /etc/rc.d/init.d/postgresql-9.2 start
postgresql-9.2 サービスを開始中: [ OK ]
> chkconfig --list postgresql-9.2
postgresql-9.2 0:off 1:off 2:off 3:off 4:off 5:off 6:off
> chkconfig postgresql-9.2 on # 自動起動設定
> su - postgres
-bash-4.1$ psql -l
データベース一覧
名前 | 所有者 | エンコーディング | 照合順序 | Ctype(変換演算子) | アクセス権
-----------+----------+------------------+-------------+-------------------+-----------------------
postgres | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 |
template0 | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres
: postgres=CTc/postgres
template1 | postgres | UTF8 | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres
: postgres=CTc/postgres

上記の作業でPostgreSQLの初期化が終わり、/var/lib/pgsql/9.2/data/にデータ領域が用意される。またコマンド類は/usr/pgsql-9.2/binに配置される。但しこのままだとPostgreSQL8のコマンド群が残っているので、パッケージごと削除する必要がある他、新しいコマンドを簡単に使えるようにユーザーpostgresには環境変数の調整が必要だ。

> yum remove postgresql.x86_64 postgresql-libs.x86_64 postgresql-odbc.x86_64
> su - postgres
$ cp .bash_profile .bash_profile.org
$ sed '3a\PATH="/usr/pgsql-9.2/bin:$PATH\nexport PATH"' .bash_profile.org > .bash_profile
$ exit
> su - postgres # 確認のため再度postgresユーザーでシェル起動
$ psql
psql (9.2.4)
"help" でヘルプを表示します.

postgres=# \q

ここまで行けば後はcreatedb コマンドで実際に開発するDBを追加していくだけだろう。


補足
実はこれでは終わらなかった。DBを作成後、新しいRailsアプリを作った後、bundler がエラーを起こした。RubyからpostgreSQLにアクセスするための「pg」というrubygemモジュールを使うようGemFile(Railsアプリをサクセスるとアプリのルートディレクトリに作成される)を修正し、「bundle update」を実行するとエラーになってしまう。
どうやらpostgreSQL9.2をインストールした際、通常の/usr/lib 等にあったバージョン8をきれいに置き換えず、/user/pgsql-9.2なるディレクトリにインストールしてしまったことが問題の根幹らしい。それによりpg_config というコマンドのパスが変わってしまい、それでpgの作成ができないようだった。
対処としては、一時的にrootの環境変数PATHに /usr/pgsql-9.2/bin を加える方法を取った。多分自分しか使わない仮想マシンだから許される手段ではないかと思う。

-- .bash_profile(修正前) --
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

# User specific environment and startup programs
PATH=$PATH:$HOME/bin:
export PATH

-- .bash_profile(修正後) --
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

# User specific environment and startup programs
PGDATA=/var/lib/pgsql/9.2/data
export PGDATA

PATH=$PATH:$HOME/bin:/usr/pgsql-9.2/bin
export PATH

この処置の後、「bundle update」を実行したところ問題なく処理を完了した。

ところがこの他にもDBの設定で引っかかってしまった。
WebRick を起動するために「rails server」と入力すると、DBエラーが発生する。Ident認証に失敗した、という旨のメッセージが表示されWebRick を起動できないのだ。
これも初期設定の見落としで、pg_hba.conf というファイルを修正しなければならなかった。このファイルは前述のinitdb を実行した際にpostgresql がデータファイルを作成する場所にある。筆者の場合は、/var/lib/pgsql/9.2/data にあった。
このファイルの説明については、マニュアルを参照するのがいいだろう。
PostgreSQL 9.2.4文書 第 19章クライアント認証
要するに、このファイルで ident とかpeer とか書かれれている部分を全部 trust にしてしまえばいいわけだ。勿論これは開発環境だからできることで本番稼働環境ではもっと権限に厳密な作業をしなければいけない。

-- pg_hba.conf (修正前:抜粋) --
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 ident
# IPv6 local connections:
host all all ::1/128 ident

-- pg_hba.conf (修正後:抜粋) --
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust

このようにファイルを編集した後にサービス再起動する。(/etc/rc.d/init.d/postgresql-9.2 restart)
それからRailsアプリのルートディレクトリに戻り再度WebRickを起動してみた。

# rails server
=> Booting WEBrick
=> Rails 3.2.13 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2013-05-01 14:36:11] INFO WEBrick 1.3.1
[2013-05-01 14:36:11] INFO ruby 1.9.3 (2013-02-22) [x86_64-linux]
[2013-05-01 14:36:11] INFO WEBrick::HTTPServer#start: pid=12947 port=3000

どうやら今度こそ上手くいったらしい……

と思ったら、まだ続きがあんのかよ!? 笑
何べんブラウザでアクセスしても当該アプリのトップページが表示できない。「このページは表示できない」となるので、恐らくステータスコード404とか500あたりでhttp接続が終わってしまってるんだろう。覚えたてのnetstat コマンドを使ってみたが、何が何だかわからず。

# netstat -at
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 *:sunrpc *:* LISTEN
tcp 0 0 *:40561 *:* LISTEN
tcp 0 0 *:ssh *:* LISTEN
tcp 0 0 localhost:ipp *:* LISTEN
tcp 0 0 *:hbci *:* LISTEN
tcp 0 0 *:postgres *:* LISTEN
tcp 0 0 localhost:smtp *:* LISTEN
tcp 0 308 192.168.1.24:ssh 192.168.1.20:59725 ESTABLISHED
tcp 0 0 192.168.1.24:ssh 192.168.1.20:59804 ESTABLISHED
tcp 0 0 *:sunrpc *:* LISTEN
tcp 0 0 *:ssh *:* LISTEN
tcp 0 0 localhost:ipp *:* LISTEN
tcp 0 0 *:postgres *:* LISTEN
tcp 0 0 localhost:smtp *:* LISTEN
tcp 0 0 *:43777 *:* LISTEN
tcp 0 0 localhost:postgres localhost:54429 ESTABLISHED
tcp 0 0 localhost:54429 localhost:postgres ESTABLISHED

良く分からないが、一番可能性があるのが小耳に挟んだことのある「パケットフィルタリング」の結果であろうと筆者は推測し、例によって書籍とWeb検索の力を借りて現在の状況を確認してみた。

# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT icmp -- anywhere anywhere
ACCEPT all -- anywhere anywhere
ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh
REJECT all -- anywhere anywhere reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
target prot opt source destination
REJECT all -- anywhere anywhere reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

むぅ……
確かにこの設定では3000番ポートを開けても駄目だろう。それで素人なりに色々やってはみるのだが、何を勘違いしているのかこれがどうもうまくいかない。
しかたなく「パケットフィルタリングそのものを無効化」することにした。

> /etc/init.d/iptables stop
> chkconfig iptables off # 自動起動もさせない

勿論こんなことは開発用のOSだからできることなので、通常の運用にはこうしたことはやるべきではないのは言うまでもないことだ。根本的なところを解決する方策を理解して進みたかったが時間がない中での作業なので仕方なかった。
少し残念な課題を残したが、以上の作業を経て無事WEBrickで起動したRailsアプリを確認できたので、次回はこの辺の課題も解決できるようになりたい。


まだあった(5/2 追記) 笑
rails console コマンドが使えなくなっていたので、その解決方法をば。GemFile の rb-readlineの行を以下のように修正した後に、「bundle update」を実行する。

-- GemFile ---
#gem 'rb-readline'
gem 'rb-readline', '~> 0.4.2'

ruby-1.9.3-p392とrails3.2.13 を CentOS 6.4 にインストールするまで (2)

Railsインストールを再開
前回の記事で無事、Rubyをインストールできた(と思っていた)筆者は、すかさず立て続けにrails のインストールを開始した。

> gem install rails

しかし結果は

no such file to load -- zlib (LoadError)

訳の分からんエラーが出て全く先に進まなくなってしまったではないか。なんじゃこれは?
ひとしきり焦った挙句、どうやらファイル圧縮/解凍ツールのライブラリであるzlibが呼び出せないらしいということまでは理解できた。
とりあえずyum で片っ端からzlib 関連のライブラリのインストールを試してみる。こんな当てずっぽうでこの手の問題が解決したことがないが、とにかくやってみた。

> yum list | grep zlib
zlib.x86_64 1.2.3-29.el6 @anaconda-CentOS-201303020151.x86_64/6.4
zlib-devel.x86_64 1.2.3-29.el6 base
zlib-static.x86_64 1.2.3-29.el6 base
...
...
> yum install zlib.x86_64 #既にインストール済みなので無駄
> yum install zlib-devel.x86_64
> yum install zlib-static.x86_64

やるだけやってみたが、結果は何も変わらない。経験則が正しかったと言う以外には特に得るものがなかった。
そこで一旦、考えを整理してみた。
zlibというのは、rubyの標準添付ライブラリだが、元々はrubyとは関係のないC言語で作成された外部ライブラリである。それをrubyから使えるのは、恐らくはスタティックリンクかダイナミックリンクで結合しているに違いない。従って、
no such file to load -- zlib (LoadError)
というエラーはライブラリをメモリ上にロードできなかったということを意味する。要するに、ライブラリ参照エラーだ。zlibライブラリ本体がないか、それともライブラリの存在をconfigureスクリプトが認識してないか、ということだ。もしこの推測が正しいなら他の外部ライブラリ参照系のruby側ライブラリもいくつかは構築に失敗しているはずだ。
前の記事ではlibyaml をインストールした後、そのライブラリをconfigureスクリプトに認識させるために、敢えて--with-opt-dir=というオプションをつけて、ライブラリのパスを指定していた。それならzlib本体の場所もこれと同じ方法で教えたらどうだろう? 

./configure --with-opt-dir=/usr/local --with-opt-dir=/usr/lib64 --enable-shared --enable-option-checking

すると上記の推測は見事に(?)当たり、以下のコマンドがすんなり実行されるようになった。

# gem list --remote rails
*** REMOTE GEMS ***
rails (3.2.13)
rails-3-settings (0.1.1)
rails-action-args (0.1.1)
....
....

どうやら、/usr/lib64 というディレクトリ構成をRubyのインストーラ作者がフォローしきれなかったか、CentOSが独自に作っているパスのために認識できなかったんだろう。

さてこれでようやく後はRails をインストールするだけというところまできた。だが、筆者はここまでの作業を通じてこの手のインストールトラブルの類が他にもあるのではないかという気がしていた。似たような問題で一見解決方法が分からなくなるようなトラブルに関しては事前に避けておきたいものだ。
調べてみると、open-ssl (の開発環境)の存在が webrickの動作に依存関係を持っているという記事を見つけた。[Rails]railsで、opensslのモジュールが無いと怒られたら
webrickは良く使うプログラムなので後ではまる前にopen-ssl-devel をインストール後、再度前回でのやり方を踏まえてRubyをインストールしなおした。

> yum install openssl-devel
...
...
Complete!
> cd /tmp/ruby-1.9.3-p392
> make clean
> ./configure --with-opt-dir=/usr/local/lib --with-opt-dir=/usr/lib64 --enable-shared --enable-option-checking
> make
....
....
configuring openssl
...
configuring zlib
...
...
linking shared-object openssl.so
installing default openssl libraries
...
...
compiling zlib.c
linking shared-object zlib.so
installing default zlib libraries
...
....
Files: 772

Classes: 1374 ( 708 undocumented)
Modules: 306 ( 152 undocumented)
Constants: 2258 ( 828 undocumented)
Attributes: 1020 ( 440 undocumented)
Methods: 10478 (3096 undocumented)

Total: 15436 (5224 undocumented)
66.16% documented

Elapsed: 214.8s

> ruby -v
ruby 1.9.3p392 (2013-02-22) [x86_64-linux]

が、実際にopensslが使えるかどうか、irbで試してみると駄目と言われてしまう。何かが足りないらしい。

irb(main):001:0> require 'openssl'
LoadError: cannot load such file -- openssl
from /usr/local/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /usr/local/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from (irb):1
from /usr/local/bin/irb:12:in `
'
irb(main):002:0> require 'zlib'
=> true # zlibは問題ない

ここでopensslのスタティックライブラリをyumからインストールしてみる他、rubyのmake時にffi というモジュールが上手くリンクできていなかったのを思い出し、その両方を試してみることにした。確かにコンパイル後Linking という表示がでるのはスタティックリンクも想起させるので怪しいといえば怪しいし、ffiにしてもどうやらダイナミックリンクの仕組みを担う部品かもしれない。Githubを参照すると、ffi-devel というライブラリに依存関係があると記されている(https://github.com/ffi/ffi)

> yum install openssl-static.x86_64
> yum install libffi-devel.x86_64

上記インストール後、再度configure から始めてみたところ、遂に irb で require 'openssl'が通るようになった。

> irb
irb(main):001:0> require 'openssl'
=> true

ここまでくればrailsまでは一気である。

>gem install rails
....
....
> rails -v
Rails 3.2.13

どうやら上手いこと、インストールできたようだ。

ruby-1.9.3-p392とrails3.2.13 を CentOS 6.4 にインストールするまで (1)

VMware Playerですら他人が用意してくれたものしか使ったことがない筆者が、必要に迫られRuby on Rails の環境を自前で用意しなければいけなくなった。
そこで今回は仮想マシン(VMware Player)をまともに動かせるようになるところから始めて、ruby-1.9.3-p392とRails3.2.13をインストールするところまでを今回の話題にしたい。


VMWare Player を入手
vmware player の入手自体はvmware社のページより簡単に行える。各自の環境に合わせたインストーラをダウンロード・実行し、手引きに沿ってインストールを進めればよい。筆者はWindows7の64bit環境を使っているので「VMware Player for Windows 32-bit and 64-bit」を選択した。Windows版は32bitでも64bitでも気にする必要はないようだ。

ゲストOSを入手
vmware player をインストールし終わったら次は、ゲストOSを作成する必要がある(ゲストOSの語義についてはこちら。OSの優劣等は詳しくないが、単純に開発プロジェクトでよく目にするという理由から筆者はCentOSを選択することにした。
CentOS: http://www.centos.org/

このOSを選ぶという単純な行為ですら、もしWindowsを使っているのだとしたら、すんなりは行かせてくれない事情がある。それはCPUだ。OSはCPUを選ぶので当然、ゲストOSにする予定のCentOSにもCPUの型によって違いがある。問題はそれが「x86/x64」なのか「i386」と呼ばれる形式のものなのか、という点にある。linuxであればコンソールに「uname -a」と入力すればすぐに分かる情報なのに、Windowsにどっぷり浸かってしまうとそんな情報の引き出し方も分からなくなってしまう。
実際、Windows7でコントロールパネルからデバイスマネージャーを開き、プロセッサと書かれた箇所をクリックしてみたとしよう。そこで見るのはせいぜい自分のPCがCeleron かそれ以外か、という程度の話で、x86なんて文字はどこにも出てこない。
筆者のような者がこんな問題を自力で解けるはずもなく、すぐにgoogleで「x86 x64 確認」とキーワードを打ち込んだ。すると実に適切な過去の質問と答えが載っているページが見つかった。
【CPUはX86であるか否かを確認する方法】http://okwave.jp/qa/q3477130.html

CPUの問題を解決するとどのOSをダウンロードすればよいかは殆ど間違いようがないので、後は安心してCentOSの最新版をダウンロードする。ダウンロードサイト一覧:http://www.centos.org/modules/tinycontent/index.php?id=30
余談だが、容量がギガバイト級のため、筆者の環境では数時間がダウンロードに費やされた。もしこれが光ファイバ等の高速環境だったらどのくらいの速さで実行できるのだろう?……やはりこれもgoogle様に聞いてみれば分かってしまうのか?

ゲストOSを作成
OSのダウンロードが済んだらいよいよゲストOSを作成する段に移る。すること自体は多いような少ないような、慣れてしまえば少ないと思える程度の作業を行う。
①VMware Playerを起動 - 「VMware Playerへようこそ」と書かれた画面が表示される
②新規仮想マシンの作成:細かい手順は省くが「後でOSをインストール」を選択すること
③②で作成した仮想マシンを左側のリストから選択すると画面右側に「仮想マシンの設定」というメニューが出てくるので、それを選択する
④「仮想マシン設定」というタイトルのウィンドウが表示されるので左側のデバイスリストから「CD/DVD」を選択し、それと同時に画面右側に表示される「接続」欄で「ISOイメージファイルを使用する」を選択する。このとき先ほどダウンロードしたOSのISOファイルを指定すること。
⑤「OK」ボタンを押すと「仮想マシン設定」が閉じるので、③で選択した仮想マシンを再選択し、今度は画面右側のメニューから「仮想マシンの再生」を選択する。
⑥CentOSのブートが始まる。途中でキーボードの設定や言語の設定、ディスクの割り当て等を聞かれるが、使用しているPCの空き容量が30GB以上あり、メモリも1から2GB積んでいる状態ならデフォルト設定のまま進んで良いと思われる。但し、最後にインストールモードについてきかれるので、そこで最終的にインストールするプログラムの大枠を選ぶことになるので、そこでは多少慎重に考えた方が良いかもしれない。この最後の部分は、人によって選択が異なるだろう。サーバー設定に慣れていれば余計なプログラムを入れたくないはずだから「minimum」を選ぶだろうし、別の理由から別のインストール設定を選択することもありうる。筆者はweb serverにしておいた。

インストールモードを選ぶとあとは基本的に待つだけでインストールは完了するが、その仮想マシンを再起動した後に、ネットワークの設定をしなければならない。
⑦ /etc/sysconfig/network の内容を以下に変更
NETWORKING=yes
GATEWAY=xxx.xxx.xxx.xxx # 自分の環境に合わせてください
⑧/etc/sysconfig/network-scripts/ifcfg-eth0 を編集
ONBOOT=yes
BOOTPROTO=dhcp # 固定IPアドレスを割り当てたい場合はこの設定では駄目
⑨一旦仮想マシンを停止し、仮想マシン設定からネットワーク設定を行う。ネットワークアダプタがNAT接続になっているはずなので、「ブリッジ接続」に変える。
⑩仮想マシン再起動

以上で仮想マシンがホストOSを介して外部ネットワークに接続できるようになる(はず)。
これ以後、ついにRuby をインストールするわけだが、どういうわけだかオープンソースの世界というかUNIXの世界というのは、ソフトウェアのインストールごときでも手間暇取らすのが好きならしい。ということを思い知らされた。恐らくWindowsやMacと異なり、ディレクトリ構成などに前提が設けられない等の不都合はあるんだろうな、などとも思いつつ。

Rubyをインストール
デフォルト環境ではCentOSにRubyはインストールされていない。CentOSのパッケージマネージャyumを使ってインストールしてもいいが、yumでサポートしているのは1.8系のみなので1.9系以降を使うなら、Ruby本家のFTPサイトよりダウンロードする必要がある。
勿論CentOS上にダウンロードする必要があるので、wget 等のツールを使う(筆者はwgetを使用)。コマンドも良し悪しあるが、この程度のことであればコマンドでサクッと済ませるのも悪くない。

cd /tmp
wget ftp://core.ring.gr.jp/pub/lang/ruby/1.9/ruby-1.9.3-p392.tar.gz
tar xzf ruby-1.9.3-p392.tar.gz # ダウンロード後にファイル解凍

次はファイルのメイク(プログラムのビルド)……といきたいところだが、実際にやってみるとできなかった。「./configure」とコマンドを実行させた直後に、gccがインストールされていないと警告が表示され処理が中断したからだ。
まぁgcc程度であればインストールすれば済む話なので、そこはyumを使ってさっさと終わらせる。

> yum list|grep gcc
gcc.x86_64 4.4.7-3.el6 base
gcc-c++.x86_64 4.4.7-3.el6 base
libgcc.x86_64 4.4.7-3.el6 base
....
> yum install gcc.x86_64
> yum install gcc-c++.x86_64

よし、じゃあビルドだーーー……

cd ruby-1.9.3-p392
./configure
make
make test
make install

ビルドそのものは実に簡単であった。実質、./configure と make だけ。この程度で済むならRubyはほぼソースから構築した方が、OSの環境に合わせたものが手に入る分、良い選択だと言えるだろう。

そしてRailsへ、のはずが……
後は gem install rails とコマンドを打てばDB構築とWebサーバー構築を除けばほとんどの作業は終わる。
はずだった。
実際にgem install rails と入力すると、libyamlがない、という意味のエラーが出てrubygemが全く動かないのである。railsに限らず全く機能しない。
調べてみて分かったのだが、libyaml というライブラリをCentOSが持っておらず、rubyよりも先にそれをインストールせねばならんということらしい。

wget http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz
tar zxvf yaml-0.1.4.tar.gz
cd yaml-0.1.4
./configure
make
make install

libyaml をインストール終、Rubyのインストールを再度開始した。

cd ruby-1.9.3-p392
./configure --with-opt-dir=/usr/local --enable-shared --enable-option-checking
make
make test
make install

(--with-opt-dir の参照先は libyaml の配置場所であり、それは whereis コマンドで知ることができる。)
インストール後のRubyバージョーン確認は問題なし。

> ruby -v
> ruby 1.9.3p392 (2013-02-22) [x86_64-linux]

よし、これでRailsインストール再開できる。おめでとう、俺!

だが。

この後も訳の分からぬトラブルが筆者を待っていた…… 笑

(つづく)

エラー箇所を簡単に特定できるログのスマートな(?)出力方法

C言語には #define というキーワードがある。

#define ONE 1
#define TWO 2


Rubyで言えば定数の定義を行っているのに似ているが、Rubyはあくまでも頭文字が大文字で示される定数のオブジェクトに値を代入しているのにたいし、C言語ではコンパイラ処理の前にプリプロセッサというツールが「#define」の後に続く2つの文字列に対し、左側の文字列を右側の文字列にソースコード上で変換するという違いがある。

(プリプロセッサによる返還後)

#define ONE 1
....
....
a = ONE;

(プリプロセッサによる返還後)

....
....
a = 1;

見ての通り、ONEが1に置き換えられてしまう。
このようなプリプロセッサを使った文字の置き換えはC言語では一般にマクロと呼ばれ、同様の機能はRubyに存在しない。

このマクロを推し進めた特殊マクロというものがC言語にはいくつかあるのだが、その中でもRubyと同じく __FILE__ と __LINE__ というキーワードはデバッグに大変役に立つ。これらのマクロをソースコード中に埋め込むと、プリプロセッサがそのマクロの書かれたファイル名と書かれている位置(行番号)に変換してくれるからだ。

(ファイル名: abc.c)
printf("THIS IS A TEST %s line %d", __FILE__, __LINE__);

上記のコードが実行されるとコンソールには
「THIS IS A TEST abc.c line 24」
という感じの出力が行われる。
このようにしてソースコード中にログを埋め込んでおけば、どのファイルの何行目まで処理が進んだのかを知るのに大変便利だ。

さらに推し進めると、以下のようなマクロを書くことになる。

#define log( msg ) printf("%s,%d:%s", msg, __FILE__,__LINE__)


このマクロをソースコード中に埋め込み、例えば「log("ERROR");」と書いて埋め込んでおくとその該当箇所全てが、プリプロセッサによりコンパイルの直前に「printf("%s %s %d", "ERROR", __FILE__, LINE__);」という表現に置き換えられる。その結果、このマクロが埋め込まれたプログラム箇所が実行されるたび
「ERROR ファイル名 行番号」
という表示がコンソールに表示されることとなる。こんなうまい手を使わないことがあるだろうか?!
そういう性質のテクニックなので、C言語を使う者であれば比較的初級者でもこの方法を知っていることが少なくない。

ではこれを、Rubyでも行おうとしたらどうすれば良いだろうか? 前述したとおり、Rubyにプリプロセッサなどというものはない。まず安直に考えて以下のコードはとりあえず、機能はする。

print "ERROR #{__FILE__} #{__LINE__}"

__FILE__ と __LINE__ はRubyでは擬似変数とい扱いとされている。これを先ほどのC言語のように、いちいち __FILE__, __LINE__ と書かないでも出力されるようにしたい。

だが結論から言うと、__FILE__, __LINE__ をそのまま使う方法では大変厳しく、恐らく不可能に近いだろう。なぜならこの2つの擬似変数は上述したC言語のマクロのように、ソースコードに現れた箇所のファイル名と行番号をそのまま返すので、ソースコード上に直接埋め込む以外に原則、使いようがない。だからプリプロセッサのないRubyで__FILE__, __LINE__ を書かずにファイル名と行番号を出そうとしても無理だ。

そこで発想を変えてみる必要がある。Rubyにおいて実行中のファイルや行番号といった情報はどこから手に入るのか? それらの一つにKernelモジュールのcaller というメソッドがある。caller を用いて適当なメソッドを書くとすれば大概以下のようなものではないだろうか。

def print_message( msg )
p "#{msg} #{caller[0]}"
end

Kernel.#callerメソッドはその名の通り、callerメソッド自身を呼び出しているメソッドを再帰的に表現した配列を返す。言い換えればスタックトレースを入手するためのメソッドで、戻り値の配列を添え字の小さい方から大きい方へと走査することで、丁度スタックを巻き戻すように呼び出し元メソッドの情報(ファイルと呼び出し行番号)を得ることができる。

仮に以下の内容のファイル abc.rb を用意したとしよう。(※左端の数字は行番号)

1 # coding: utf-8
2
3 def aaa
4 puts caller[0]
5 end
6
7 def bbb
8 aaa
9 end
10
11 def ccc
12 puts caller[0]
13 end
14
15 def ddd
16 ccc
17 end
18
19 aaa
20
21 bbb
22
23 ccc
24
25 ddd
26

これを実行すると以下の実行結果が得られるはずだ。

> ruby abc.rb
abc.rb:19:in `
'
abc.rb:8:in `bbb'
abc.rb:23:in `
'
abc.rb:16:in `ddd'

caller[0] は「メソッド自身(caller)を呼び出しているメソッドの呼び出されている場所」を示している。だから19行目でメソッドaaa が呼び出されると、aaa内部のcaller[0]はaaaが呼び出された場所、すなわち abc.rb の19行目という情報を返す。

こうしたKernel.#callerの応用は独自定義の例外クラスを定義する際にも用いることができる。initializeメソッドの内部でcallerを使うことで例外の送出位置を知ることができれば、例外が起きたときの調査・分析にかかる時間を短縮できるだろう。

class MyException < Exception
attr_reader :raised_at
def initialize(*args)
super
@raised_at = caller[0]
end
end


全てのクラスに何らかの位置捕捉情報を持たせたければObjectクラスを再定義すればよい。

# coding: utf-8

class Object
def source_location
caller[0]
end
end


h = {a:1, b:2}
p h # => {:a=>1, :b=>2}
p h.source_location # => "aaa.rb:12:in `
'"


ここに挙げたコードは思いついたままのほんの一例に過ぎないが、アイディア次第ではデバッグ等に重宝するのではないだろうか。
  

カレンダー

04 2024/05 06
S M T W T F S
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

フリーエリア

最新CM

バーコード

ブログ内検索

Copyright ©  -- ぢみへんプログラミング日誌 --  All Rights Reserved

Design by CriCri / Material by petit sozai emi / powered by NINJA TOOLS / 忍者ブログ / [PR]