Ruby 2.7 の変更点 - Encoding / Fiber / FrozenError

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

qiita.com

Encoding::CESU_8 追加

自分は知らなかったのですが、Unicode の文字エンコーディングに UTF-8 の亜種で CESU-8 というのがあるらしく、2.7 でそれに対応しました。

通信用語の基礎知識 より:

UTF-8の亜種の一つで、Oracleが使っている不届き千万な仕様の一つ。

本来UTF-8(RFC 2279 [外部リンク] )では、サロゲートペアは適時解釈してから符号化せねばならない。 しかしこのCESU-8は、サロゲートの各ペアを機械的にUTF-8に変換するのみであり、supplementary characterは6バイトで表現される。これはUTF-8の仕様から外れた手法であるばかりか、公害ともなりうる実装である。

Wikipedia より:

現在のOracle Databaseでも、CESU-8を「UTF8」として、「普通のUTF-8」を「AL32UTF8」として扱っているため注意を要する。

へー、Oracle にはそんな罠があるのか。

"".encode("UTF-8").unpack("H*")   #=> ["e38182"]
"".encode("CESU-8").unpack("H*")  #=> ["e38182"]
"🍣".encode("UTF-8").unpack("H*")   #=> ["f09f8da3"]
"🍣".encode("CESU-8").unpack("H*")  #=> ["eda0bcedbda3"]

Fiber#raise 追加

最後に Fiber.yield した地点で例外を発生させます。

f = Fiber.new do
  10.times do |i|
    Fiber.yield i
  end
rescue
  999
end

f.resume  #=> 0
f.resume  #=> 1
f.resume  #=> 2
f.raise   #=> 999

FrozenError#receiver 追加

frozen オブジェクトに変更を加えようとした時に FrozenError が発生しますが、receiver で発生原因のオブジェクトを取得できるようになりました。

s = "hoge".freeze
begin
  s.upcase!
rescue FrozenError => e
  e.receiver  #=> "hoge"
end