[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]