diff options
author | Jean Boussier <[email protected]> | 2020-02-03 12:29:37 +0100 |
---|---|---|
committer | Jeremy Evans <[email protected]> | 2020-02-03 08:16:22 -0800 |
commit | f2552216d43040cd42bbb9fd484eab6c70856fe6 (patch) | |
tree | 417634fff2c49a9e2cf6f68733053ac103b735be | |
parent | 11963da9e8e98821860fbb0c0f2adc118860c814 (diff) |
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?`.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/2875
-rw-r--r-- | lib/delegate.rb | 9 | ||||
-rw-r--r-- | test/test_delegate.rb | 14 |
2 files changed, 22 insertions, 1 deletions
diff --git a/lib/delegate.rb b/lib/delegate.rb index b7d48effb4..e3b3488c16 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -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 diff --git a/test/test_delegate.rb b/test/test_delegate.rb index 9c47743888..4a3445f121 100644 --- a/test/test_delegate.rb +++ b/test/test_delegate.rb @@ -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 |