アインシュタインの電話番号
2011.05.31
Rubyでrbファイルをrequireするときはドットを打つと良さそう

記事タイトルがヘタなので、何言ってるのか伝わらなさそうだけど…。最近、Ruby 1.8.7で作ったWebアプリをRuby 1.9.2に移行させていて、その過程でつまずいて知ったことについて。Ruby 1.9.2からは、ロードパスにカレントディレクトリが含まれなくなったので、それによって起こるエラーを回避するための方法として、requireするパスにカレントディレクトリを示すドットを打つと良さそうという話。

実例

以下は説明用に簡略化した実例。まず、hoge.rbがあるとする。中身はこんな感じ。

puts 'hoge!'

同じディレクトリにapp.rbがあるとする。中身はこんな感じ。

require 'hoge.rb'

app.rbを実行すると、Ruby 1.8.7ではこう。期待通り。

$ ruby app.rb
hoge!

けど、Ruby 1.9.2ではロードパスにカレントディレクトリが含まれなくなったので、以下のようなエラーになる。

$ ruby app.rb
<internal:lib/rubygems/custom_require>:29:in `require': no such file to load -- hoge.rb (LoadError)
        from <internal:lib/rubygems/custom_require>:29:in `require'
        from app.rb:1:in `<main>'

解決策は2つあって、1つ目がおすすめ。簡単なので。

解決策1

app.rbrequireでカレントディレクトリを示すドットを打つことで、Ruby 1.9.2でも正常にrequireを実行できるようになる。この方法はこちらの記事のコメント欄で知った。

# require 'hoge.rb'
require './hoge.rb'  # カレントディレクトリを示すドットを打つ

これで、Ruby 1.8.7でも1.9.2でも正常動作してる。今のところ。ほんのちょびっとの労力で両対応できるので、自分はこれで行こうと思った。

解決策2

いちおうもうひとつの解決策も知ったので備忘録。最初はこちらしか知らなくて毎回書くのめんどうだなぁと思ってたけど、解決策1の方法を知って一安心。こっち方法は、requireを実行する前に、ロードパスにカレントディレクトリを追加する正攻法(?)

1箇所だけでなく、多くの場所で既にRuby 1.8.7的なrequireしてる場合はこちらの方が適してそう。この書き方はLokkaのコードをコピペさせてもらった。

$:.unshift File.dirname(__FILE__)  # ロードパスにカレントディレクトリを追加
require 'hoge.rb'

この1行目は、ロードパス($: または $LOAD_PATH)にカレントディレクトリを追加する処理で、これさえ書けば以降のrequireは今まで通りで問題ない。

個人的には、WebアプリはすべてSinatraで作って、ほとんどの場合がapp.rbの1ファイルで済んでいて、稀にrbファイルを外部化する(今回のような)程度なので、そのたびに解決策2の書き方を思い出すのはしんどいと思ったので、解決策1を使う予定。

だけど、もっと大きな、または、rbファイルがたくさんあるようなプロジェクト(上述のLokkaのような)では、1箇所でロードパスを指定しておいて、他のrequireには手を加えないほうが適していると言えそう。適材適所ですね。


Ruby 1.9.2から$LOAD_PATHにカレントディレクトリが含まれなくなった init.rb at master from komagata/lokka - GitHub