akishin999の日記

調べた事などを書いて行きます。

1.8 の $LOAD_PATH でうっかりハマる

今日 1.8 系を触っていて、うっかり 1.9 との $LOAD_PATH の仕様の違いで小一時間ハマってしまいました。
1.8 系では $LOAD_PATH に自動でカレントディレクトリが含まれているんでしたね・・・。

具体的には以下のようなライブラリの検証コードをいくつか書いていた時に起きました。
(ちなみに以下の例で使っているライブラリはその時試していた grosser/parallel です。)

require 'rubygems'
require 'parallel'

Parallel.each([1, 2, 3, 4, 5, 6, 7, 8, 9], :in_threads => Parallel.processor_count) {|num|
  puts num
}

最初は問題なく動いていたのですが、しばらく検証を進めていくとある段階から以下のようなエラーが・・・。

% ruby parallel-test.rb
parallel-test.rb:4: uninitialized constant Parallel (NameError)

gem list で確認しても問題なくライブラリはインストールされているし、ディレクトリにもファイルは存在しています。
一体何故急に動かなくなったのか、かなり焦ってしまいましたが、結果が分かってしまうとなんという事はない単純ミスでした。

適当なファイル名でサンプルコードをいくつか書いているうちに、ライブラリと同名のファイルを作ってしまっていた事が原因です。
1.8 系ではカレントディレクトリが $LOAD_PATH に含まれているため、カレントディレクトリ内にライブラリと同名のファイルが存在する場合、require でそちらのファイルが読み込まれてしまいます。

試しに以下のように上記のコードと同じディレクトリに parallel.rb というファイルを作成すると簡単に現象は再現できます。

% echo >> parallel.rb
% ruby parallel-test.rb
parallel-test.rb:4: uninitialized constant Parallel (NameError)

この仕様は Ruby 1.9.2 で $LOAD_PATH にカレントディレクトリが含まれなくなったので、それ以降のバージョンを使っている場合は発生しません。

% rbenv local 1.9.3-p286
% ruby -v
ruby 1.9.3p286 (2012-10-12 revision 37165) [i686-linux]
% gem install parallel --no-rdoc --no-ri
Fetching: parallel-0.6.1.gem (100%)
Successfully installed parallel-0.6.1
1 gem installed
% ruby parallel-test.rb
1
2
3
4
5
6
7
8
9

カレントディレクトリが含まれなくなった事で今まで動作していたスクリプトがエラーになった、という記事はいくつか目にしていたのでこの変更自体は知ってはいたのですが、古いバージョンの Ruby を触っている時に逆に含まれている事を失念していてハマるとは思いませんでした・・・orz

当たり前の事ですが、バージョンが異なる Ruby を扱う時には気をつけないといけないですね。
以後気をつけたいと思います。

参考

Ruby 1.9.2リリース
http://www.ruby-lang.org/ja/news/2010/08/18/ruby-1-9-2-is-released/#label-8

Rubyでrbファイルをrequireするときはドットを打つと良さそう - アインシュタインの電話番号☎
http://blog.ruedap.com/entry/20110531/ruby_require_load_path

Ruby 1.9.2から$LOAD_PATHにカレントディレクトリが含まれなくなった - ぬいぐるみライフ(仮)
http://d.hatena.ne.jp/mickey24/20100907/1283869273