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:そういうケースがあるのかは知らないが。