【一人 bugs.ruby Advent Calendar 2021】[Bug #17866] Incompatible changes with Psych 4.0.0【23日目】

一人 bugs.ruby Advent Calendar 2021 23日目の記事になります。
今日は Psych4.0.0 にメジャーアップデートすることで非互換になる話です。

[Bug #17866] Incompatible changes with Psych 4.0.0

Psych.loadPsych.safe_load に置き換える PR がマージされて Psych 4.0.0 がリリースされました。
このチケットは Psych 4.0.0 が非互換になるのでそれの対応をするチケットになります。
問題点は大まかに2つあり、1つはデフォルトだとエイリアスが許可されていない問題です。
なので次のように &default を使用している YAML ファイルを読み込むと Psych 4.0.0 ではエラーになってしまいます。

require "psych"
require "date"

data = <<~EOS
default: &default
  aaa: aaa
development:
  <<: *default
EOS

# Psych 4.0.0 以前 => OK 読み込める
# Psych 4.0.0 以降 => NG 読み込めない
pp Psych.load(data)

これの影響でいくつかの gem が対応を行っています。

このエイリアスがデフォルトで不許可になったのは再帰的なエイリアスになった場合に安全ではないケースがあるのが理由になります。
例えば以下のようなデータを読み込んだ際にの場合にクラッシュしてしまうのを防ぐためです。

require "psych"

def process thing
  thing.each do |item|
    case item
    when Array
      process item
    when Hash
      # ...
    when String
      # ...
    end
  end
end

user_input = <<~EOS
--- &1
- *1
EOS

# error: stack level too deep (SystemStackError)
process Psych.load(user_input)

また Psych.load は『キーに Symbol を定義できることを許容している』が YAML.load_file に反映されていない問題があるようです。

# :text: という書き方が許可されてほしいが許可されていない
require "psych"
require "tempfile"
require "yaml"

Tempfile.open "example" do |file|
  file.write %(:text: "Hello.")
  file.rewind
  # load は OK
  puts "YAML Contents: #{YAML.load file}"
  # load_file は NG
  puts "YAML Contents: #{YAML.load_file file}"
end

この Psych 4.0.0Ruby 3.1 からバンドルされる予定なので Ruby 3.1 にアップデートする際は注意する必要があります。