ruby-changes:58206
From: Jeremy <ko1@a...>
Date: Fri, 11 Oct 2019 05:15:39 +0900 (JST)
Subject: [ruby-changes:58206] 2322c94dd6 (master): Support delegates for BasicObject
https://git.ruby-lang.org/ruby.git/commit/?id=2322c94dd6 From 2322c94dd65c0247b103e2f91411e37458e1466d Mon Sep 17 00:00:00 2001 From: Jeremy Evans <code@j...> 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] diff --git a/lib/delegate.rb b/lib/delegate.rb index a1589ec..7a2ad50 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -79,10 +79,10 @@ class Delegator < BasicObject https://github.com/ruby/ruby/blob/trunk/lib/delegate.rb#L79 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 https://github.com/ruby/ruby/blob/trunk/lib/delegate.rb#L95 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. diff --git a/test/test_delegate.rb b/test/test_delegate.rb index 9634681..7f6e7c1 100644 --- a/test/test_delegate.rb +++ b/test/test_delegate.rb @@ -322,4 +322,12 @@ class TestDelegateClass < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/test_delegate.rb#L322 delegate.constants end end + + def test_basicobject + o = BasicObject.new + def o.bar; 1; end + delegate = SimpleDelegator.new(o) + assert_equal(1, delegate.bar) + assert_raise(NoMethodError, /undefined method `foo' for/) { delegate.foo } + end end -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/