mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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]
This commit is contained in:
parent
4171909695
commit
2322c94dd6
Notes:
git
2019-10-11 05:15:39 +09:00
2 changed files with 22 additions and 4 deletions
|
@ -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.
|
||||
|
|
|
@ -322,4 +322,12 @@ class TestDelegateClass < Test::Unit::TestCase
|
|||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue