質問: ruby で gem の開発をしているとします。 gem の開発なので、以下のようなスタンダードなフォルダ構成になっているとします。 ``` % tree . ├── Rakefile ├── bin │ └── hola ├── hola.gemspec ├── lib │ ├── hola │ │ └── translator.rb │ └── hola.rb └── test └── test_hola.rb ``` この際、 `lib/hola.rb` から `lib/hola/translator.rb` を require するときに、 `require_relative` を利用しない理由などありますか? とくに、 `lib` 内部の相対参照であるならば: * すべて自分が管理するコードなので、フォルダ構成もコントロールできる * 同一 LOAD_PATH エントリー内部の話なので、`bin/` や `test/` といった、プロジェクトとしてのフォルダ構成の変更の影響を受けることはあまり考えにくい ことに加え、特に、 `require_relative` することによって、 `$LOAD_PATH` から意図しないスクリプトが読み込まれる危険を避けることができます。なので、基本的に `require_relative` するべきだと思っています。 しかし一方で、 `require_relative` を利用するライブラリや、 `require_relative` の利用を推奨するような記事もあまり見掛けないので、自分の認識が違っているのかもりえない、と若干思ったりもします。 ### 質問 lib 内部など、同一`LOAD_PATH`エントリー上の、自分のファイルをロードするにあたり、 `require_relative` より `require` を利用するべき理由などあったりなどしますでしょうか。
回答: 推測です。もしかしたら、他の理由かも知れません。 【理由その1】過去とのの互換性 `require_relative`はRuby 1.8にはなく、Ruby 1.9からになります。該当のライブラリは1.8の頃からあり、一時は互換性を維持する必要があったライブラリにおいては`require_relative`が使えなかったという事情があります。その名残が今も残っているということです。また、その頃からの慣習として、原則`require`のみを使うとなっているのかも知れません。 【理由その2】ライブラリの分割に備える ライブラリが肥大化するなどすれば、どこかでライブラリの分割を検討するかも知れません。今はgemがあるので、gemで依存関係を書いておけば、一部を別のgemにしても、利用者側で何かを変更する必要もありません。互換性が維持しながらいつでも分割できるということです。 ここで問題になるのは、分離してしまったライブラリを読み込む部分です。もし、`require_relative`で書いてしまっていたら、分離した部分はもはやそのgem内にはないので、エラーになってしまうでしょう。しかし、`require`で書いてあって、ちゃんと依存したgemとして一緒にインストールされるのであれば、何も書き換えなくてもそのまま維持できます。 【理由その3】混ぜるな危険? 次のようなファイル構成を考えています。 ``` ./ ├─lib/ │ └─sub.rb ├─sub.rb └─test.rb ``` lib/sub.rb ``` puts 'lib/sub.rb' ``` sub.rb ``` puts 'sbu.rb' ``` test.rb ``` $: << File.join(__dir__, 'lib') pp(require 'sub') $: << File.join(__dir__) pp(require_relative 'sub') ``` すでにlib/sub.rbは読み込まれているけど、relativeなのでsub.rbも読み込みます。これは特に問題ないように思えますが、そうではありません。もし、subというgemがすでにあって、それを読み込んだ後に、このライブラリのgemを読み込んだ場合、subという名前が被っています。 Rubyではファイル名とその中身のモジュール名やクラス名に強制的な規則はありませんが、通常は、推奨される名前付けを行っています。きっとどちらも`Sub`というモジュールかクラスを使っていることでしょう。そして、後に読み込まれたものによって前者は上書きされてしまいます。 そもそもモジュール名が被ること自体が問題ですので、あまり起きないかも知れません。それに`require`に変えたら、逆にsubが読み込まれません。しかし、必要であったから`require`したのに想定している物が読み込まれなかった場合、すぐにエラーになって気づくことができるでしょう。逆に、二重読み込みは、クラスなら一時的にうまく動くかも知れません。この場合、**おかしな部分に対してエラーがすぐに起きないかもしれないことの方が問題**です。なぜなら、気づかず、そのままリリースしてしまう恐れがあるからです。 ということで、`require_reltaive`よりも`require`だけを使っていった方が安全と思われます。ただ、ちゃんと名前空間を設定しておけば良いだけの話なので、それほど問題にならない可能性はあります。