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

今週は Enumerable#take_while_afterEnumerable#detect_only といったメソッドの提案がありました

[Feature #18136] take_while_after

tokens = [
  {text: 'Ruby', type: :word},
  {text: 'is', type: :word},
  {text: 'cool', type: :word},
  {text: '.', type: :punctuation, ends_sentence: true},
  {text: 'Rust', type: :word},
  # ...
]

# _1[:ends_sentence] が真になるまでの要素を返す
sentence = tokens.take_while_after { _1[:ends_sentence] }
pp sentence
# => [{:text=>"Ruby", :type=>:word},
#     {:text=>"is", :type=>:word},
#     {:text=>"cool", :type=>:word},
#     {:text=>".", :type=>:punctuation, :ends_sentence=>true}]

# これは slice_after.first と同じ挙動
sentence = tokens.slice_after { _1[:ends_sentence] }.first
pp sentence
# => [{:text=>"Ruby", :type=>:word},
#     {:text=>"is", :type=>:word},
#     {:text=>"cool", :type=>:word},
#     {:text=>".", :type=>:punctuation, :ends_sentence=>true}]

[Feature #18135] Introduce Enumerable#detect_only

  • #detect で要素が見つからなかった場合に例外を返す Enumerable#detect_only メソッドの提案ぽい?
  • #detect で要素が1個だけ見つかった場合は成功し、それ以外は例外を返す Enumerable#detect_only メソッドの提案
  • 次のようなコードを
matches = array.select { |elem| some_method(elem) }
raise if matches.size != 1
match = matches.first
  • 以下のようにかけるようにする提案らしい
match = array.detect_only { |elem| some_method(elem) }

[Bug #18126] Process termination three seconds after thread termination dumps core

  • 次のようなコードを実行するとランダムで segv することがあるらしい
3000.times{Thread.new{}}
sleep 2.99
$ ruby test.rb
[BUG] Segmentation fault at 0x0000000000000440
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86_64-linux]

$
  • これは
    • Ruby のスレッドが終了し、3分以内に新しい Ruby のスレッドが作成されると、その内部の pthread が別のRuby のスレッドによって再利用される
    • しかし、pthread が3分待機している間に Ruby のプロセスプロセスが RubyVM と GC が破棄される
    • その後、xfreeは使用できなくなり、セグメンテーション違反が発生する
  • らしい

[Misc #18125] A strange behavior when same name variable/method coexist issue.

  • 次のように同名のメソッドと変数を定義した時に奇妙な動作になるけどこれは期待する動作?という質問
def deploy_to
  "deploy_to"
end

deploy_to = "#{deploy_to} new place"
#              ^ これがメソッドではなくて変数を参照している

p defined? deploy_to # => local_varible
p deploy_to  # => " new place"
  • これは期待する動作でこの場合は変数が定義され値が割り当てられる前のローカル変数 deploy_to を参照する
  • メソッドを参照したい場合は () を付けてメソッド呼び出しだと明示化する必要がある
def deploy_to
  "deploy_to"
end

deploy_to = "#{deploy_to()} new place"
#              ^ これはメソッド呼び出しになる
p deploy_to  # => "deploy_to new place"