RubyのFile.expand_path('相対パス', __FILE__)の意味
RailsなどのRubyライブラリのソースコードを見ていると、よく
File.expand_path('相対パス', __FILE__)
という一文を目にする。ちょっと調べてみた。
File.expand_pathとは
riコマンドで調べてみる
$ ri File.expand_path (from ruby core) ------------------------------------------------------------------------------ File.expand_path(file_name [, dir_string] ) -> abs_file_name ------------------------------------------------------------------------------ Converts a pathname to an absolute pathname. Relative paths are referenced from the current working directory of the process unless dir_string is given, in which case it will be used as the starting point. The given pathname may start with a ``~'', which expands to the process owner's home directory (the environment variable HOME must be set correctly). ``~user'' expands to the named user's home directory. File.expand_path("~oracle/bin") #=> "/home/oracle/bin" File.expand_path("../../bin", "/tmp/x") #=> "/bin"
・相対パスを絶対パスに変換した文字列を返す
・第2引数を指定しない場合「プロセスのカレントワーキングディレクトリ」を相対パスの基準にする
・第2引数を指定した場合「第2引数で指定したディレクトリ」を相対パスの基準にする
検証用ディレクトリ構造
検証用に、以下のディレクトリを作った。a.rbからlib/を参照することを想定して、検証する。
/ └── Users/ └── hidenorimaehara/ └── xxx/ └── yyy/ └── a.rb └── lib/
File.expand_path('./lib')
まずは第2引数を指定しないでやってみる。
a.rb
プロセスのカレントワーキングディレクトリを確認するため、Dir.pwdの結果も表示することにする。
puts Dir.pwd puts File.expand_path('./lib')
yyyディレクトリで実行
$ ruby a.rb /Users/hidenorimaehara/xxx/yyy /Users/hidenorimaehara/xxx/yyy/lib
File.expand_path('./lib', '/Users/hidenorimaehara/xxx/yyy/')
次に第2引数を与えてみる。yyyディレクトリの絶対パスを第2引数に指定してみる。
a.rb
さきほどのa.rbを以下のように変更。
puts Dir.pwd puts File.expand_path('./lib', '/Users/hidenorimaehara/xxx/yyy/')
yyyディレクトリで実行
$ ruby a.rb /Users/hidenorimaehara/xxx/yyy /Users/hidenorimaehara/xxx/yyy/lib
xxxディレクトリで実行
$ ruby ./yyy/a.rb /Users/hidenorimaehara/xxx /Users/hidenorimaehara/xxx/yyy/lib
第2引数に指定したディレクトリを基準として相対パスを解析していることがわかる。
__FILE__
ここで一旦脇道にそれて、__FILE__について調べる。__FILE__は、現在のソースファイル名を返す変数。実際にどのような値を返しているのか調べてみる。
a.rb
puts __FILE__
yyyディレクトリで
$ ruby a.rb a.rb
File.expand_path('./lib', __FILE__)
となるとFile.expand_pathの第2引数に__FILE__を指定すれば、現在のソースファイルを基点とできる。第1引数に'./lib'、第2引数に__FILE__を指定してみる。
a.rb
puts Dir.pwd puts File.expand_path('./lib', __FILE__)
yyyディレクトリで
$ ruby a.rb /Users/hidenorimaehara/xxx/yyy /Users/hidenorimaehara/xxx/yyy/a.rb/lib
xxxディレクトリで
$ ruby ./yyy/a.rb /Users/hidenorimaehara/xxx /Users/hidenorimaehara/xxx/yyy/a.rb/lib
ありゃ
./では、a.rb(ファイル名)自体もパスに入ってしまっている。
File.expand_path('../lib', __FILE__)
ということで、第1引数に../libにしてみる。
a.rb
puts Dir.pwd puts File.expand_path('../lib', __FILE__)
yyyディレクトリで
$ ruby a.rb /Users/hidenorimaehara/xxx/yyy /Users/hidenorimaehara/xxx/yyy/lib
xxxディレクトリで
$ ruby ./yyy/a.rb /Users/hidenorimaehara/xxx /Users/hidenorimaehara/xxx/yyy/lib
できた!
以下のように使う
こうすれば、プロセスのカレントワーキングディレクトリがどこであっても、相対的な位置関係を参照できる
# このソースファイルと同ディレクトリにあるb.rbをrequire require File.expand_path('../b', __FILE__) # このソースファイルと同ディレクトリにあるlibディレクトリをrequireのロードパスに追加 $: << File.expand_path('../lib', __FILE__)