summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2020-02-03 12:29:37 +0100
committerJeremy Evans <code@jeremyevans.net>2020-02-03 08:16:22 -0800
commitf2552216d43040cd42bbb9fd484eab6c70856fe6 (patch)
tree417634fff2c49a9e2cf6f68733053ac103b735be
parent11963da9e8e98821860fbb0c0f2adc118860c814 (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.rb9
-rw-r--r--test/test_delegate.rb14
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