2022/04/21 今回の気になった bugs.ruby のチケット

今週はレシーバに対して Kernel#p が呼び出せるようにする提案がありました。

[Feature #18736] self-p for method chain

  • 次のようにメソッドチェーンの間にレシーバを出力したいという要望チケット
class Object
  def sp(method=nil, *args, &block)
    if method
        Kernel.p self.public_send(method, *args, &block)
    elsif block_given?
        Kernel.p block.call(self)
    else
      Kernel.p self
    end
    return self
  end
end

# sp のレシーバを標準出力する
p [1,2,3].map{|x| x**2}.sp.map{|x| x**2}
# output:
# [1, 4, 9]
# [1, 16, 81]

# ブロックの結果を出力する
[1,2,3].sp{|x| "my List = #{x}"}
# output:
# "my List = [1, 2, 3]"

# レシーバに対して sum(-10) を呼び出した結果を出力する
[1,2,3].sp(:sum,-10)
# output:
# -4
  • #tap すると以下のように書くことができる
# sp のレシーバを標準出力する
p [1,2,3].map{|x| x**2}.tap(&method(:p)).map{|x| x**2}
# output:
# [1, 4, 9]
# [1, 16, 81]

# ブロックの結果を出力する
[1,2,3].tap{|x| p "my List = #{x}"}
# output:
# "my List = [1, 2, 3]"

# レシーバに対して sum(-10) を呼び出した結果を出力する
[1,2,3].tap { p _1.sum(-10) }
# output:
# -4

[Bug #18729] Method#owner and UnboundMethod#owner are incorrect after using Module#public/protected/private

  • 次のように public / protected / private を呼び出した後に #owner が変わってないというバグ報告
class A
  protected def foo
    :A
  end
end

class B < A
  p [instance_method(:foo), instance_method(:foo).owner, instance_methods(false), A.instance_methods(false)]
  public :foo
  p [instance_method(:foo), instance_method(:foo).owner, instance_methods(false), A.instance_methods(false)]
end
# outptu:
# [#<UnboundMethod: B(A)#foo() owner.rb:2>, A, [], [:foo]]
# [#<UnboundMethod: B(A)#foo() owner.rb:2>, A, [:foo], [:foo]]
  • Bfoo が再定義されているのに ownerB(A)#foo() のままになっている
  • 期待する挙動は以下の通り
[#<UnboundMethod: B(A)#foo() owner.rb:2>, A, [], [:foo]]
[#<UnboundMethod: B#foo() owner.rb:2>, B, [:foo], [:foo]]

[Bug #18741] Slicing an Array using index out of range inconsistent return type

  • 範囲外の値を Array#[] に渡したときの挙動が一貫していないというバグ報告
 def test_slicing_arrays
   array = [:peanut, :butter, :and, :jelly]

   assert_equal [:peanut], array[0,1]
   assert_equal [:peanut, :butter], array[0,2]
   assert_equal [:and, :jelly], array[2,2]
   assert_equal [:and, :jelly], array[2,20]
   assert_equal [], array[4,0] # 範囲外を指定した時にこっちは [] を返す
   assert_equal [], array[4,100]
   assert_equal nil, array[5,0] # 同様に範囲外を指定しているがこっちは nil を返す
 end

[Feature #18742] Introduce a way to tell if a method invokes the super keyword

  • メソッド内で super を呼び出しているかどうかを判定するメソッドを追加する提案
class X
  def a
  end; p instance_method(:a).calls_super? #=> false

  def b
    super
  end; p instance_method(:b).calls_super? #=> true

  def c
    super if false
  end; p instance_method(:c).calls_super? #=> true

  def d
    eval 'super'
  end; p instance_method(:d).calls_super? #=> false (I doubt there's a reasonable way for this to return true)
end