[ruby/delegate] Reapply "Merge pull request #46 from byroot/use-forward-send"

This reverts commit https://github.com/ruby/delegate/commit/fc2bd0498af0.

https://github.com/ruby/delegate/commit/7d5c1e0842

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
This commit is contained in:
Hiroshi SHIBATA 2025-12-17 12:56:19 +09:00
parent bdf99bf0dc
commit a21fe2adfe
Notes: git 2025-12-18 07:47:15 +00:00
2 changed files with 35 additions and 8 deletions

View File

@ -405,6 +405,17 @@ def DelegateClass(superclass, &block)
protected_instance_methods -= ignores
public_instance_methods = superclass.public_instance_methods
public_instance_methods -= ignores
normal, special = public_instance_methods.partition { |m| m.match?(/\A[a-zA-Z]\w*[!\?]?\z/) }
source = normal.map do |method|
"def #{method}(...); __getobj__.#{method}(...); end"
end
protected_instance_methods.each do |method|
source << "def #{method}(...); __getobj__.__send__(#{method.inspect}, ...); end"
end
klass.module_eval do
def __getobj__ # :nodoc:
unless defined?(@delegate_dc_obj)
@ -413,18 +424,21 @@ def DelegateClass(superclass, &block)
end
@delegate_dc_obj
end
def __setobj__(obj) # :nodoc:
__raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
@delegate_dc_obj = obj
end
protected_instance_methods.each do |method|
define_method(method, Delegator.delegating_block(method))
protected method
end
public_instance_methods.each do |method|
class_eval(source.join(";"), __FILE__, __LINE__)
special.each do |method|
define_method(method, Delegator.delegating_block(method))
end
protected(*protected_instance_methods)
end
klass.define_singleton_method :public_instance_methods do |all=true|
super(all) | superclass.public_instance_methods
end

View File

@ -93,15 +93,21 @@ class TestDelegateClass < Test::Unit::TestCase
end
class Parent
def parent_public; end
def parent_public
:public
end
protected
def parent_protected; end
def parent_protected
:protected
end
private
def parent_private; end
def parent_private
:private
end
end
class Child < DelegateClass(Parent)
@ -157,6 +163,13 @@ class TestDelegateClass < Test::Unit::TestCase
assert_instance_of UnboundMethod, Child.public_instance_method(:to_s)
end
def test_call_visibiltiy
obj = Child.new(Parent.new)
assert_equal :public, obj.parent_public
assert_equal :protected, obj.__send__(:parent_protected)
assert_raise(NoMethodError) { obj.__send__(:parent_private) }
end
class IV < DelegateClass(Integer)
attr_accessor :var