Ruby 2.7 の変更点 - Dir / File / IO / Pathname

Ruby 2.7 アドベントカレンダーの15日目の記事です。

qiita.com

Dir

Dir.glob / Dir.[] : NUL文字を含むとエラー

文字列中の NUL を区切り文字として扱わなくなりました。

2.6 では warning が出てましたが、2.7 ではエラーになります。

Ruby 2.6

Dir.glob("*.txt\0*.rb")  #=> ["a.txt", "b.rb"]
#=> warning: use glob patterns list instead of nul-separated patterns

Ruby 2.7

Dir.glob("*.txt\0*.rb")
#=> in `glob': nul-separated glob pattern is deprecated (ArgumentError)

複数のパターンを指定したい場合は配列を指定しましょう。

Dir.glob(["*.txt", "*.rb"])  #=> ["a.txt", "b.rb"]

File

File.extname : 「.」で終わる文字列が「.」を返す

. で終わる文字列で . を返すようになりました。

Ruby 2.6

File.extname("hoge.")  #=> ""

Ruby 2.7

File.extname("hoge.")  #=> "."

IO

IO.set_encoding_by_bom 追加

バイナリモードの IO が BOM で始まる場合に外部エンコーディングを設定し、その Encoding を返します。

File.write("hoge.txt", "\u{FEFF}abc")
f = File.open("hoge.txt", "rb")
f.external_encoding    #=> #<Encoding:ASCII-8BIT>
f.set_encoding_by_bom  #=> #<Encoding:UTF-8>
f.external_encoding    #=> #<Encoding:UTF-8>

File.write("hoge.txt", "\xFE\xFF\x00\x41")
f = File.open("hoge.txt", "rb")
f.external_encoding    #=> #<Encoding:ASCII-8BIT>
f.set_encoding_by_bom  #=> #<Encoding:UTF-16BE>
f.external_encoding    #=> #<Encoding:UTF-16BE>

BOM で始まらない場合は nil を返します。

File.write("hoge.txt", "abc")
f = File.open("hoge.txt", "rb")
f.external_encoding    #=> #<Encoding:ASCII-8BIT>
f.set_encoding_by_bom  #=> nil
f.external_encoding    #=> #<Encoding:ASCII-8BIT>

バイナリモードでない場合は例外が発生します。

File.write("hoge.txt", "abc")
f = File.open("hoge.txt", "r")
f.external_encoding    #=> #<Encoding:UTF-8>
f.set_encoding_by_bom  #=> ASCII incompatible encoding needs binmode (ArgumentError)

Pathname

Pathname.glob : 引数追加

Dir.glob はキーワード引数を受けつけるのに Pathname.glob が受け付けなかったので修正されました。

Pathname 関数 : 引数が Pathname の場合にそのまま返す

Pathname が引数として渡された時に、新しい Pathname オブジェクトを生成するのではなく、引数をそのまま返すようになりました。

p1 = Pathname("hoge.txt")
p2 = Pathname(p1)
p1.object_id == p2.object_id  #=> true (2.6 では false)

新しいオブジェクトが生成されることを期待して戻り値を変更しているコードは、元の Pathname オブジェクトを壊してしまうので注意。