1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Fix SimpleDelegator respond_to? regression

In 2.6, SimpleDelegator would always use the target `respond_to?`

In 2.7.0 it doesn't if the target does not inherit from Object.

This breaks compatibility for delegated objects that inherit
from BasicObject and redefine `respond_to?`.
This commit is contained in:
Jean Boussier 2020-02-03 12:29:37 +01:00 committed by Jeremy Evans
parent 11963da9e8
commit f2552216d4
Notes: git 2020-02-04 01:16:53 +09:00
2 changed files with 22 additions and 1 deletions

View file

@ -103,13 +103,20 @@ class Delegator < BasicObject
r
end
KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?)
private_constant :KERNEL_RESPOND_TO
# Handle BasicObject instances
private def target_respond_to?(target, m, include_private)
case target
when Object
target.respond_to?(m, include_private)
else
::Kernel.instance_method(:respond_to?).bind_call(target, m, include_private)
if KERNEL_RESPOND_TO.bind_call(target, :respond_to?)
target.respond_to?(m, include_private)
else
KERNEL_RESPOND_TO.bind_call(target, m, include_private)
end
end
end

View file

@ -344,6 +344,20 @@ class TestDelegateClass < Test::Unit::TestCase
assert_raise(NoMethodError, /undefined method `foo' for/) { delegate.foo }
end
def test_basicobject_respond_to
o = BasicObject.new
def o.bar
nil
end
def o.respond_to?(method, include_private=false)
return false if method == :bar
::Kernel.instance_method(:respond_to?).bind_call(self, method, include_private)
end
delegate = SimpleDelegator.new(o)
refute delegate.respond_to?(:bar)
end
def test_keyword_argument
k = EnvUtil.labeled_class("Target") do
def test(a, k:) [a, k]; end