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

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

[Bug #9542] Delegator does not delegate protected methods

  • 以下のコードが Ruby 2.0 と 2.1 で差異がある、というバグ報告
require "delegate"
class Cow
  def unprotected_moo
    "mooooo!"
  end

  protected

  def protected_moo
    "guarded mooooo!"
  end
end
my_cow = Cow.new
puts SimpleDelegator.new(my_cow).unprotected_moo
# => "mooooo!"

# protected_moo は protected なのに呼び出すことができる
puts SimpleDelegator.new(my_cow).protected_moo
# 2.0      => "guarded mooooo!"
# 2.1 以降 => undefined method `protected_moo' (NoMethodError)

puts my_cow.unprotected_moo
# => "mooooo!"
puts my_cow.protected_moo
# 2.0      => "guarded mooooo!"
# 2.1 以降 => protected method `protected_moo' called (NoMethodError)
  • これ自体は期待する挙動なので Reject されている
    • そもそもチケット自体が7年前のやつだった

[Bug #17814] inconsistent Array.zip behavior

  • 以下のように Array#zip だとイテレーションが1回余計に呼ばれているというバグ報告
i = 0
# 1 ずつ増えるカウンタ
e = Enumerator.produce { i += 1 }

# 1つ余計にイテレーションが発生する
p [0, 0, 0, 0].zip e
# => [[0, 1], [0, 2], [0, 3], [0, 4]]
p i
# => 5

# Enumerable#zip だと再現しない
p [0, 0, 0, 0].each.zip e
# => [[0, 6], [0, 7], [0, 8], [0, 9]]
p i
# => 9

[Feature #17785] Allow named parameters to be keywords

  • 先週も書いてた キーワード_ という名前で変数参照できるようにしよう、という提案
def check(arg, class:)
  # _ を付けて参照できるようにする
  arg.is_a?(class_)
end

check(42, class: Integer) # => true
  • __params__ みたいな値で受け取れるようにしようという提案があってこれは普通にほしいと思った
def check(arg, class:)
  arg.is_a?(__params__[:class])
end

check(42, class: Integer) # => true
  • ただし、キーワード引数以外の引数をどうするかの課題がある
    • __params__ というよりかは __keyword_params__ みたいな?

[Feature #17718] a method paramaters object that can be pattern matched against

  • 次のようにキーワード引数を一括で返すメソッドを追加する提案
    • パターンマッチで利用することを想定している
def get_perdiem(city: nil, state: nil, zip:nil)

  case parameters_match  # (return an object of the parameters we can pattern match on)
  in {zip: zip}
     find_perdiem_by_zip(zip)
  in {state: s, city: c}
     find_perdiem_by_state_and_city(s, c)
  in { state: s}
     find_perdiem_by_state(s)
  else
     raise 'need combination of zip, city,state'
  end
end
def getParam(**args)
  case args
  in {zip: zip}
    p "zip"
  in {state: s, city: c}
    p "state+city"
  in { state: s}
    p "state"
  else
    raise 'need combination of zip, city, state'
  end
end

[Bug #4443] odd evaluation order in a multiple assignment

def foo
  p :foo
  []
end
def bar
  p :bar
end

# bar -> foo という順に評価される
x, foo[0] = bar, 0
# output:
# :bar
# :foo

# これは foo -> bar という順になる
foo[0] = bar
# output:
# :foo
# :bar
def foo
  p :foo
  []
end
def bar
  p :bar
end

# 最新版だと foo -> bar と評価されるようになった
x, foo[0] = bar, 0
# output:
# :foo
# :bar

[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"
# current: SyntaxError
# patch: Allow
def foo() = puts "bar"

# current: SyntaxError
# patch: SyntaxError
private def foo() = puts "bar"

[Feature #15198] Array#intersect?

  • Array#intersect? を追加する提案
  • これは以下の動作と同じ意味
    • Array#&
    • [1, 1, 2, 3] & [3, 1, 4] #=> [1, 3]
(a1 & a2).any?