🚀

[Bug #21391] File.join と Pathname#join に空文字列を渡したときの挙動が一貫しないバグ報告

に公開

[Bug #21391] Inconsistent trailing slash behavior of File.join and Pathname#join with empty strings

  • 次のように File.joinPathname#join で空文字列を渡したときに末尾に / が付く付かないで一貫性がないというバグ報告
require "pathname"

# これは末尾に / が付く
p File.join('/usr', '')
# => "/usr/"

# これは末尾に / が付かない
p Pathname.new('/usr').join('').to_s
# => "/usr"


# 空文字列出ない場合は両方とも / が付く
p File.join('/usr', ' ')
# => "/usr/ "

p Pathname.new('/usr').join(' ').to_s
# => "/usr/ "


p Pathname.new('/usr').join('/').to_s
  • パスの末尾に / を追加するのは一般的な使用例で現状だと式展開("#{Rails.root}/")や File.join を利用する(File.join(Rails.root, ''))必要があると書かれていますね
    • これを Rails.root.join("") で書きたい、ってことがモチベーションなのかな?
    • どちらかというと空文字列を渡した場合の挙動が明文化されておらず一貫性のない動作になっているのがこのチケットで話したいことみたい
    • その上で Pathname#join で末尾に / が追加できる明確な方法がほしいみたい
    • https://bugs.ruby-lang.org/issues/21391#note-3
  • コメントだとこれ以外のケースでもいくつか差異があると指摘されていますね
File.join("/usr","/var")               #=> "/usr/var"
Pathname.new("/usr").join("/var").to_s #=> "/var"

File.join("/usr","../var")               #=> "/usr/../var"
Pathname.new("/usr").join("../var").to_s #=> "/var"

File.join("/usr","/../var")               #=> "/usr/../var"
Pathname.new("/usr").join("/../var").to_s #=> "/../var"
  • これは File.join は単純に2つの文字列をセパレータ(/)で結合するだけなんですが Pathname#join は2つのパスに対して論理演算しているので違いがあるらしい
  • ここでいう 論理演算 っていうのがあんまりよくわからなかったんですが Pathname#join は『引数で cd した結果』と同等であることを期待しているみたいですね?
  • あとそもそもパスの末尾に / をつけることは OS間の移植性がなるのでやめたほうがよいともコメントされていますね
    • Pathname の挙動はそれを反映しているらしい
  • ただ、規格としてこのあたりの状況を修正しようとする動きもあるみたいですねー
GitHubで編集を提案

Discussion