From e8c710b11a02c6ab82b358fc671a14f378cb1974 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Thu, 23 May 2019 21:10:40 -0700 Subject: [PATCH] Fix visibility of some methods when using DelegateClass Public instance methods added to a delegated class after the creation of the delegate class were not returned by the public_instance_methods class method of the delegate class. Protected instance methods in the delegated class when the delegate class is created were returned by the public_methods instance method of the delegate class. Patch mostly from Kenichi Kamiya in GitHub pull request 926. Minor changes to get it to apply, and to fix tests after applying by me. Fixes [Bug #11512] --- lib/delegate.rb | 16 +++++++++++----- test/test_delegate.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/lib/delegate.rb b/lib/delegate.rb index 859cc2ed84..1e4ab5f145 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -393,9 +393,11 @@ end # def DelegateClass(superclass, &block) klass = Class.new(Delegator) - methods = superclass.instance_methods - methods -= ::Delegator.public_api - methods -= [:to_s, :inspect, :=~, :!~, :===] + ignores = [*::Delegator.public_api, :to_s, :inspect, :=~, :!~, :===] + protected_instance_methods = superclass.protected_instance_methods + protected_instance_methods -= ignores + public_instance_methods = superclass.public_instance_methods + public_instance_methods -= ignores klass.module_eval do def __getobj__ # :nodoc: unless defined?(@delegate_dc_obj) @@ -408,12 +410,16 @@ def DelegateClass(superclass, &block) __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj) @delegate_dc_obj = obj end - methods.each do |method| + protected_instance_methods.each do |method| + define_method(method, Delegator.delegating_block(method)) + protected method + end + public_instance_methods.each do |method| define_method(method, Delegator.delegating_block(method)) end end klass.define_singleton_method :public_instance_methods do |all=true| - super(all) - superclass.protected_instance_methods + super(all) | superclass.public_instance_methods end klass.define_singleton_method :protected_instance_methods do |all=true| super(all) | superclass.protected_instance_methods diff --git a/test/test_delegate.rb b/test/test_delegate.rb index 8ed3342afa..38e38ad781 100644 --- a/test/test_delegate.rb +++ b/test/test_delegate.rb @@ -85,6 +85,37 @@ class TestDelegateClass < Test::Unit::TestCase assert_equal(:m, bar.send(:delegate_test_m), bug) end + class Parent + def parent_public; end + + protected + + def parent_protected; end + end + + class Child < DelegateClass(Parent) + end + + class Parent + def parent_public_added; end + + protected + + def parent_protected_added; end + end + + def test_public_instance_methods + ignores = Object.public_instance_methods | Delegator.public_instance_methods + assert_equal([:parent_public, :parent_public_added], (Child.public_instance_methods - ignores).sort) + assert_equal([:parent_public, :parent_public_added], (Child.new(Parent.new).public_methods - ignores).sort) + end + + def test_protected_instance_methods + ignores = Object.protected_instance_methods | Delegator.protected_instance_methods + assert_equal([:parent_protected, :parent_protected_added], (Child.protected_instance_methods - ignores).sort) + assert_equal([:parent_protected, :parent_protected_added], (Child.new(Parent.new).protected_methods - ignores).sort) + end + class IV < DelegateClass(Integer) attr_accessor :var