疑問に思った点
Dir.glob
やPathname.glob
でワイルドカード(*
)を指定し、なおかつFile::FNM_DOTMATCH
オプションを渡すと、.
や..
が含まれるパスが返ってきます。
require 'pathname'
pathname = Pathname.pwd
#=> #<Pathname:/Users/jnito/dev>
# Dir.glob は "." と ".." を保持する
Dir.glob(pathname.join('*'), File::FNM_DOTMATCH).sort[0..1]
#=> ["/Users/jnito/dev/.", "/Users/jnito/dev/.."]
# Pathname.glob も "." と ".." を保持する
Pathname.glob(pathname.join('*'), File::FNM_DOTMATCH).sort[0..1]
#=> [#<Pathname:/Users/jnito/dev/.>, #<Pathname:/Users/jnito/dev/..>]
しかし、Pathname#glob
(インスタンスメソッドのglob
)を使うと.
や..
が消えて、カレントディレクトリや親ディレクトリそのものが返ってきます。
require 'pathname'
pathname = Pathname.pwd
#=> #<Pathname:/Users/jnito/dev>
# Dir.globやPathname.globと異なり、インスタンスメソッドのglobは"."や".."ではなく、カレントディレクトリや親ディレクトリが返ってくる
pathname.glob('*', File::FNM_DOTMATCH).sort[0..1]
#=> [#<Pathname:/Users/jnito>, #<Pathname:/Users/jnito/dev>]
僕としてはクラスメソッドのPathname.glob
を呼びだしたときと同じように#<Pathname:/Users/jnito/dev/.>
や#<Pathname:/Users/jnito/dev/..>
が返ってきてほしかったのですが、この挙動の違いはどういう理由で発生するのでしょうか?その理由を以下にまとめます。
結果が異なる理由
Pathname.glob
はDir.glob
の結果をそのままPathnameオブジェクトに変換します。イメージとしては以下のような感じです。(実際はCで実装されています)
class Pathname
# クラスメソッドのglobの実装イメージ
def self.glob(pattern, flags=0)
Dir.glob(pattern, flags).map do |path|
Pathname(path)
end
end
end
一方、インスタンスメソッドのPathname#glob
はDir.glob
のbase
オプションに自分自身のパスを設定し、Dir.glob
の結果と自分自身を表すパスを+
で結合します。イメージとしては以下のような感じです。(こちらも実際はCで実装されています)
class Pathname
# インスタンスメソッドのglobの実装イメージ
def glob(pattern, flags=0)
Dir.glob(pattern, flags, base: self).map do |path|
self + path
end
end
end
ポイントとなるのはself + path
の部分です。
base
オプションを指定すると、Dir.glob
は.
や..
という文字列を返します(=base
からの相対パスを返す)。そしてこれらの文字列をPathnameオブジェクトに+
で結合すると、.
や..
が消えて、カレントディレクトリや親ディレクトリのパスが返ります。
pathname = Pathname.pwd
#=> #<Pathname:/Users/jnito/dev>
# "."を結合すると、"."が消えてカレントディレクトリのパスになる
pathname + '.'
#=> #<Pathname:/Users/jnito/dev>
# ".."を結合すると、".."が消えて親ディレクトリのパスになる
pathname + '..'
#=> #<Pathname:/Users/jnito>
# "."や".."でなければ、素直にパスが結合される
pathname + 'foo'
#=> #<Pathname:/Users/jnito/dev/foo>
インスタンスメソッドのPathname#glob
は内部的に以下のような処理が行われているため、File::FNM_DOTMATCH
オプションを渡しても.
や..
が保持されず、カレントディレクトリや親ディレクトリが返ってくる、というわけです。