2021/05/18 今週の気になった bugs.ruby のチケット

内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
あくまでも『わたしが気になったチケット』で全ての bugs.ruby のチケットを載せているわけではありません。

[PR psych #487] Use Psych.safe_load by default

  • Psych.loadPsych.safe_load に置き換えようという PR
    • PsychYAML のバックエンドとなるライブラリ
  • Psych.safe_loadYAML データを安全に読み込むためのメソッド
  • 例えば特定のクラスのみ変換し、指定しないとエラーになる
    • 再帰的なデータ構造はデフォルトでは許可されていない
require "yaml"
require "date"

# String は問題ない
p Psych.safe_load("name: homu")
# => {"name"=>"homu"}

# Date は変換できずにエラーになる
# error: `find': Tried to load unspecified class: Date (Psych::DisallowedClass)
p Psych.safe_load("date: 2020-01-01")

# 明示的に Date を指定することで変換できる
p Psych.safe_load("date: 2020-01-01", [Date])
# => {"date"=>#<Date: 2020-01-01 ((2458850j,0s,0n),+0s,2299161j)>}

# .load であれば問題ない
p Psych.load("date: 2020-01-01")
# => {"date"=>#<Date: 2020-01-01 ((2458850j,0s,0n),+0s,2299161j)>}
  • 他には &default みたいなエイリアスもデフォルトでは許可されていないらしい
    • これもオプションで制御可能
    • Psych.safe_load yaml, [], [], true みたいに第4引数を true にする
  • デフォルトが .safe_load になるとありとあらゆるところで影響しそう
  • ちなみに Rubocop には Psych.loadPsych.safe_load にする Cop がある

[Bug #17857] when 0r and when 0i do not match with case 0

  • 0r === 00i === 0true を返すが case-when でマッチしないというバグ報告
# これは true を返す
p 0r === 0  # => true
p 0i === 0  # => true

# しかし case-when では 0r などにマッチしない
case 0
when 0r
  p :hoge
when 0i
  p :foo
else
  p :bar
end
#=> :bar
  • これは最適化のバグらしく、最適化を無効にして実行すると問題なく動作する
# 最適化を無効にして Ruby のコードを実行する
RubyVM::InstructionSequence.compile(<<END, specialized_instruction: false).eval
case 0
when 0r
  p :hoge
when 0i
  p :foo
else
  p :bar
end
# => :hoge
END

[Feature #17856] ary.member? is slower than ary.include?

  • ary.member?ary.include? よりも遅いというチケット
$ time ruby -e 'a = (0..100000).to_a; 1000.times { a.member?(100000) }'

real    0m1.722s
user    0m1.721s
sys     0m0.000s

$ time ruby -e 'a = (0..100000).to_a; 1000.times { a.include?(100000) }'

real    0m0.524s
user    0m0.523s
sys     0m0.000s
  • 現状 #include?Array で実装されているが #member?Enumerable のものを使用している
pp [].method(:include?).owner  # => Array
pp [].method(:member?).owner   # => Enumerable
  • #member?Array#include? に置き換える提案されている

[Feature #17398] SyntaxError in endless method

  • 以下のようにエンドレスメソッド定義の本体が statement だった場合にエラーになる、というチケット
# OK
def foo() = puts("bar")

# syntax error, unexpected string literal, expecting `do' or '{' or '('
def hoge() = puts "bar"
# OK
def print(value) = puts value

print(42)
# => 42
  • ただし、次のように def の戻り値を他のメソッドに渡す場合はシンタックスエラーになるので注意
# syntax error, unexpected local variable or method, expecting `do' or '{' or '('
private def hoge(value) = puts value

# () を付けると OK
private def foo(value) = puts(value)

[Feature #17859] Start IRB when running just ruby

  • ruby コマンドだけを実行した場合に irb が起動するようにする提案
  • python コマンドがこんな感じの挙動になっているんだけど、間違って REPL が起動した時に終了のさせ方がわからなくて困ったことが多いので個人的にはちょっと否定的…
  • 便利なんですかねえ