TransWikia.com

require_relative はなぜあまり使われない?

スタック・オーバーフロー Asked on December 24, 2021

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 を利用するべき理由などあったりなどしますでしょうか。

One Answer

推測です。もしかしたら、他の理由かも知れません。

【理由その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だけを使っていった方が安全と思われます。ただ、ちゃんと名前空間を設定しておけば良いだけの話なので、それほど問題にならない可能性はあります。

Answered by raccy on December 24, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP