かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Ruby (2.2.0) 自分で作成したファイルを読み込む(require)にハマる

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 ... 実行ファイルからの絶対パスで指定。必ず./から始める必要があるっぽい。
  • require_relative ... そのファイルからの相対パスで指定。

自作したファイルを読み込ませる場合は、
require_relativeで相対パスでファイル指定をする 方法が間違い無さそうだなと思いました。


[参考]

Effective Ruby

Effective Ruby