Ruby 2.7 の変更点 - StringScanner / open-uri / CSV

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

qiita.com

StringScanner とか CSV は Ruby の標準ライブラリだけど本体の外で開発されているやつで、NEWSを見ても詳しくは書いてなかったので、調べてみました。

StringScanner

fixed anchor モード

StringScanner.new 時に fixed_anchor: true を指定すると、\A が現在の位置ではなく文字列の先頭にマッチするようになります。

require 'strscan'

ss = StringScanner.new("hogefuga")
ss.fixed_anchor?   #=> false
ss.scan(/hoge/)    #=> "hoge"
ss.scan(/\Afuga/)  #=> "fuga"

ss = StringScanner.new("hogefuga", fixed_anchor: true)
ss.fixed_anchor?   #=> true
ss.scan(/hoge/)    #=> "hoge"
ss.scan(/\Afuga/)  #=> nil

open-uri

Kernel.open で warning

open-uri ライブラリが拡張する Kernel.open メソッド(URI.open じゃなくてただの open)で URL を開く時に warning が表示されるようになりました。 URI.open を使いましょう。

require 'open-uri'

open("http://example.com")
#=> warning: calling URI.open via Kernel#open is deprecated, call URI.open directly or use URI#open

URI.open("http://example.com")
#=> warning が出ない

text/* のデフォルトの charset が UTF-8 に

open-uri で、Content-Type が text/* で charset 持たないデータを読んだ時に、エンコーディングが ASCII-8BIT になっていたのが UTF-8 になりました。

試してみます。

テキトーなテキストファイルを作って、

% echo abcdefg > a.txt
% ruby -run -e httpd
[2019-12-24 22:03:40] INFO  WEBrick 1.4.2
[2019-12-24 22:03:40] INFO  ruby 2.6.5 (2019-10-01) [x86_64-linux]
[2019-12-24 22:03:40] INFO  WEBrick::HTTPServer#start: pid=19499 port=8080

HTTP でアクセスすると charset を返さない状態で、

% curl -D- http://127.0.0.1:8080/a.txt
HTTP/1.1 200 OK
Etag: 721245-8-5e020c13
Content-Type: text/plain
Content-Length: 8
Last-Modified: Tue, 24 Dec 2019 13:01:07 GMT
Server: WEBrick/1.4.2 (Ruby/2.6.5/2019-10-01)
Date: Tue, 24 Dec 2019 13:05:09 GMT
Connection: Keep-Alive

abcdefg

open-uri でアクセスすると、

require 'open-uri'

URI.open("http://127.0.0.1:8080/a.txt").read.encoding
# 2.6 => #<Encoding:ASCII-8BIT>
# 2.7 => #<Encoding:UTF-8>

2.6 では ASCII-8BIT、2.7 では UTF-8 になってます。

CSV

quote_empty オプション

真の場合は空の値を " で括ります。偽の場合は括りません。デフォルトは true

require 'csv'
CSV.new($stdout).puts ["a", "", "z"]
#=> a,"",z
CSV.new($stdout, quote_empty: true).puts ["a", "", "z"]
#=> a,"",z
CSV.new($stdout, quote_empty: false).puts ["a", "", "z"]
#=> a,,z

write_converters オプション

Procオブジェクトを指定すると、それを使用して値を変換します。配列で複数の Proc を指定することができます。

require 'csv'
CSV.new($stdout, write_converters: ->(s){s.upcase}).puts ["a", "b", "c"]
#=> A,B,C

CSV.new($stdout, write_converters: [->(s){s.upcase}, ->(s){s*2}]).puts ["a", "b", "c"]
#=> AA,BB,CC

write_nil_value オプション

値が nil の場合に出力する文字列を指定します。

require 'csv'
CSV.new($stdout, write_nil_value: "NULL").puts ["a", nil, "z"]
#=> a,NULL,z

write_empty_value オプション

値が空の場合に出力する文字列(またはnil)を指定します。

require 'csv'
CSV.new($stdout).puts ["a", "", "z"]
#=> a,"",z
CSV.new($stdout, write_empty_value: "---").puts ["a", "", "z"]
#=> a,---,z
CSV.new($stdout, write_empty_value: nil).puts ["a", "", "z"]
#=> a,,z

strip オプション

真を指定すると " \t\f\v" を削除します。文字を指定するとその文字を削除します。

require 'csv'

CSV.parse(" value1 , value2 ")
#=> [[" value1 ", " value2 "]]

CSV.parse(" value1 , value2 ", strip: true)
#=> [["value1", "value2"]]

CSV.parse("===value1===,===value2===", strip: "=")
#=> [["value1", "value2"]]