diff --git a/lib/delegate.rb b/lib/delegate.rb index b5224ea..d725a93 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -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 __getobj__ # :nodoc: 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 diff --git a/test/test_delegate.rb b/test/test_delegate.rb index ca170e3..903265a 100644 --- a/test/test_delegate.rb +++ b/test/test_delegate.rb @@ -93,15 +93,21 @@ def test_override 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 @@ def test_DelegateClass_public_instance_method 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