From 2322c94dd65c0247b103e2f91411e37458e1466d Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Sun, 25 Aug 2019 00:04:14 -0700 Subject: Support delegates for BasicObject For BasicObject, bind the Kernel respond_to? instance method to the object and call it instead of calling the method directly. Also, use bind_call(recv, ...) for better performance. Fixes [Bug #16127] --- lib/delegate.rb | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'lib/delegate.rb') diff --git a/lib/delegate.rb b/lib/delegate.rb index a1589ecd08..7a2ad50ac3 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -79,10 +79,10 @@ class Delegator < BasicObject r = true target = self.__getobj__ {r = false} - if r && target.respond_to?(m) + if r && target_respond_to?(target, m, false) target.__send__(m, *args, &block) elsif ::Kernel.method_defined?(m) || ::Kernel.private_method_defined?(m) - ::Kernel.instance_method(m).bind(self).(*args, &block) + ::Kernel.instance_method(m).bind_call(self, *args, &block) else super(m, *args, &block) end @@ -95,14 +95,24 @@ class Delegator < BasicObject def respond_to_missing?(m, include_private) r = true target = self.__getobj__ {r = false} - r &&= target.respond_to?(m, include_private) - if r && include_private && !target.respond_to?(m, false) + r &&= target_respond_to?(target, m, include_private) + if r && include_private && !target_respond_to?(target, m, false) warn "delegator does not forward private method \##{m}", uplevel: 3 return false end r end + # 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) + end + end + # # Returns the methods available to this delegate object as the union # of this object's and \_\_getobj\_\_ methods. -- cgit v1.2.3