Ruby(2.2.0)を使っていて自作したファイルを読み込み(require)する際にハマったのでメモ。
結論から言えば自作ファイルを読み込ませる際は相対パスで読み込むrequire_relativeを使うのが良さそう。
ファイル構成と読み込み
ファイル構成
/app
|- main.rb # <- 実行ファイル
|- controller.rb
|- /modules
| |- a.rb
| |- b.rb
| |- /dir
| |- e.rb
|- /lib
|- c.rb
|- d.rb
読み込み順
main.rb # <- 実行ファイル
|- controller.rb ... (1)
|- /modules/a.rb ... (2)
|- /modules/b.rb ... (3)
| |- /modules/dir/e.rb ... (4)
| |- /lib/d.rb ... (5)
|- /lib/c.rb ... (5)
1. 実行ファイルから同一階層のファイルの読み込み (main.rb -> controller.rb)
main.rbからcontroller.rbを読み込みます。
require は ./ が無いとエラーになる
require 'controller.rb' # => Loaderror
Ruby1.9.2から./が無いとエラーになる仕様になったらしい。
require './controller.rb' # => SUCCESS
※ただし、実行ファイルが別階層のものになると./有りでもエラーになる
require_relative で指定する場合 ./ 無しでもOKっぽい
require_relative 'controller.rb' # => SUCCESS
require_relative './controller.rb' # => SUCCESS
requireでもrequire_relativeでも/からファイルを指定するとエラーになる場合がある
/からファイルやディレクトリを指定すると、完全なルートからファイルを探すっぽいのでルートからのパスと一致してない場合はエラーになるっぽい。
require '/controller.rb' # => Loaderror cannot load such file -- /controller.rb
/app/controller.rbなので、/controller.rbは見つからないっぽい?
それとも仕様的にNGなのかちょっと不明。
require_relativeでも/からファイル指定するとルートからファイル検索するっぽい。
require_relative '/controller.rb' # => Loaderror cannot load such file -- /controller.rb
2. 同一階層のフォルダ内のファイルの読み込み (controller.rb -> /modules/a.rb)
main.rbで読み込むcontroller.rbで、同一階層にある/modulesフォルダ内のa.rbを読み込ませます
同一階層のファイルの読み込みと同じ
require 'modules/a.rb' # => Loaderror
require './modules/a.rb' # => SUCCESS
※ただし、実行ファイルが別階層のものになると./有りでもエラーになる
require_relative 'modules/a.rb' # => SUCCESS
require_relative './modules/a.rb' # => SUCCESS
3. 実行ファイルと同じ階層にあるフォルダ内でもファイル読み込み (/modules/a.rb -> /modules/b.rb)
先のcontroller.rbで読み込む/modules/a.rbから同じ/modulesディレクトリ内のファイルを読み込ませる
main.rb # 実行ファイル /modules |- a.rb # -> b.rb を読み込ませたい |- b.rb
require は 実行ファイルからの絶対パスでないとエラーになる
require 'b.rb' # => LoadError
./を付けてもa.rbからの相対パスなので読み込めない
require './b.rb' # => LoadError
main.rbからのパスを指定すればOK
require './modules/b.rb' # => SUCCESS
※ただし、実行ファイルが別階層のものになると、当然パスが変わるのでエラーになる
相対パス読み込み require_relative
require_relative 'b.rb' # => SUCCESS
require_relative './b.rb' # => SUCCESS
4. フォルダ内のファイルから同一フォルダに有るディレクトリ内のファイルの読み込み (/modules/b.rb -> /modules/dir/e.rb)
/modules/b.rbから/modules/dir/e.rbを読み込む
main.rb # 実行ファイル
/modules
|- b.rb # -> ./dir/e.rb を読み込ませたい
|- /dir
|- e.rb
requireなら実行ファイルからの絶対パスで指定する
require './modules/dir/e.rb' # => SUCCESS
※ただし、実行ファイルが別階層のものになると、当然パスが変わるのでエラーになる
require_relativeの場合は相対パスで指定する
require_relative 'dir/e.rb' # => SUCCESS
require_relative './dir/e.rb' # => SUCCESS
5. 別階層のディレクトリにあるファイルの読み込み (/modules/a.rb -> /lib/c.rb, /modules/b.rb -> /lib/d.rb)
/modules/a.rbから/lib/c.rbを読み込む
main.rb # 実行ファイル /modules |- a.rb # -> /lib/b.rb を読み込ませたい /lib |- c.rb
requireなら実行ファイルからの絶対パス、require_relativeなら読み込ませるファイル(a.rb)からの相対パスで指定すればOK。
/modules/b.rbから/lib/d.rbを読み込ませるのも同様。
require './lib/c.rb' # => SUCCESS
※ただし、実行ファイルが別階層のものになると、当然パスが変わるのでエラーになる
require_relative '../lib/c.rb' # => SUCCESS
まとめ
自作したファイルを読み込ませる場合は、
require_relativeで相対パスでファイル指定をする 方法が間違い無さそうだなと思いました。
[参考]

- 作者: Peter J.Jones
- 出版社/メーカー: 翔泳社
- 発売日: 2015/01/19
- メディア: Kindle版
- この商品を含むブログ (4件) を見る