Rails 2.1.0のconfig.gemに失敗する件
手元のRailsアプリケーションを2.1.0に移行する際にちょっと躓いた。
2.1.0への移行
移行手順はいつも通り。次のサイトが詳しい。gettextが文句を言ってくるという、日本語圏Railsプログラマが十中八九ひっかかる問題もサポート。すばらしい。
Rails2.0から2.1への移行を試してみる - ザリガニが見ていた...。
で、俺ももちろんそこに引っかかったのだが、同時に他の件にもやられた。2.1.0で追加された、Railsのgem依存を定義する機能である。
依存関係の定義
Rails2.1.0から、config/environment.rbでRailsアプリケーションが依存するgemを定義しておけるようになった。
Rails::Initializer.run do |config| ... config.gem 'gettext', :version => '~> 1.9' config.gem 'mislav-will_paginate', :version => '~> 2.3' ... end
こうしておくと、rake gemsで必要なgemが環境に揃っているか調べられるし、sudo rake gems:installとすれば、不足するgemのインストールまで行ってくれる。これは便利だ。
が、うまくいかなかった。なぜかmislav-will_paginateを読み込めないのだ。もちろん、環境にインストールし忘れている、といった間抜けなミスではない。
他のgemも試してみた。
config.gem 'fastthread'
これはOK。
config.gem 'sqlite3-ruby'
NG。名前にハイフンが入ったらいかんのか?まさかねぇ。
Railsのコードやらドキュメントやらを読んでみたのだが、どうやらgemの名称と読み込みたいライブラリの名称が一致しない場合は、ちゃんとライブラリ名を指定してあげないといけないらしい。
つまり、こうだ。
#config.gem 'mislav-will_paginate', :version => '~> 2.3' config.gem 'mislav-will_paginate', :lib => 'will_paginate', :version => '~> 2.3'
gemの名称は"mislav-will_paginate"だが、必要なライブラリは"will_paginate"である、という点を明確にしている。
これでうまくいった。
$ rake gems (in /Users/idesaku/sandbox/git/bbs) [I] gettext ~> 1.9 [I] mislav-will_paginate ~> 2.3 I = Installed F = Frozen $
Rails内の該当箇所のコードは以下(gem_dependency.rb)。
def load return if @loaded || @load_paths_added == false require(@lib || @name) @loaded = true rescue LoadError puts $!.to_s $!.backtrace.each { |b| puts b } end
まずは:lib、それが無ければgem名称の順でrequireしようとしている。なるほど、ちゃんと:libを与えておかないと、require 'mislav-will_paginate'しようとするが、そんなもん存在しない(require 'will_paginate'が正しい)からエラーになるわけだ。
確かに、さきほど同様に失敗したsqlite3-rubyも、実際に使うときはrequire 'sqlite3'だ。なるほどねぇ。
ここまで書いて、http://blog.poqu.org/2008/04/11/edge-rails-gem-dependencies/で同様の事柄がすでに説明されていることに気づいたorz ええい、書いてしまったから、かまわずポストするわい!
おまけ
まてよ、そこでrequireしてるってことは、config.gemで依存関係を定義したgemについては自分でrequireしなくてよいってこと?
つまり、こう書けばrequireを自分で書かなくても動いたりする?
config.gem 'gettext', :lib => 'gettext/rails', :version => '~> 1.9' config.gem 'mislav-will_paginate', :lib => 'will_paginate', :version => '~> 2.3'
こうしたうえで、require 'will_paginate'と、require 'gettext/rails'を削除してみたのだが…動くじゃないか。いいね、gemの依存とライブラリの依存を同時に片付けられるのは実にスマートだと思う。
しかし、この書き方は正しいのだろうか、お作法的な意味で。mislav-will_paginateはともかく、gettextのgemには、gettext.rbが存在する。つまり、gettextと言っているのに、require 'gettext'ではなくrequire 'gettext/rails'しかしていないという気持ち悪さがある。
それに、一つのgemの中から複数のライブラリをrequireしたい場合はどう書けばいいのだろう*1?同じ名前で:libだけ違うconfig.gemを書いてもいいのだが、それだと後でrake gemsしたときに同じ名前が並んでしまう。後の保守担当者がそれを見て苦い顔をするのが目に浮かぶ。
*1:そういうケースがあるのかは知らないが。