📘
[Bug #21125] 意図せずに Kernel のメソッドが優先して呼び出されてしまうバグ報告
[Bug #21125] Kernel is called first
- 次のコードが Ruby 3.4 からエラーになってしまうというバグ報告
class ObjectifiedHash
def initialize(hash)
@hash = hash
end
private
attr_reader :hash
def method_missing(method_name, *args, &block)
if hash.key?(method_name.to_sym)
hash[method_name.to_sym]
else
super
end
end
end
class Foo
def system(...)
# (...) がない場合は ObjectifiedHash#system が呼ばれる
# raw.system
# (...) がある場合は Kernel#system が呼ばれエラーになる
# error: wrong number of arguments (given 0, expected 1+) (ArgumentError)
raw.system(...)
end
def initialize(raw)
@raw = raw
end
def get_system
system
end
private
attr_reader :raw
end
class Test
def self.run
obj = ObjectifiedHash.new({
system: 'system'
})
foo = Foo.new(obj)
foo.get_system
end
end
Test.run
- ちょっと分かりづらいんですが
ObjectifiedHash#method_missing
経由で#system
メソッドを呼び出そうとした場合にKernel#system
のほうが呼び出されてしまい、意図する挙動にならなくなっています - またこれは転送引数を渡したときに再現するみたいですね
- これなんですがもう少し簡略化すると以下でも再現します
class ObjectifiedHash
def method_missing(method_name, *args, &block)
"ObjectifiedHash#method_missing"
end
private
def system
"ObjectifiedHash#system"
end
end
def test(...)
# 本来であれば private メソッドをレシーバ付きで呼び出したときは #method_missing が優先して呼び出される
# しかし、転送引数を渡した場合は意図せずに private メソッドが呼びされてしまう
ObjectifiedHash.new.system(...)
end
pp test
# => "ObjectifiedHash#system"
- この不具合は開発版の Ruby 3.5-dev で修正済みで
ObjectifiedHash#method_missing
が優先して呼び出されるようになります
Discussion