From 4439ed8e84fd2af49f0df45fa21d7daf887b93ce Mon Sep 17 00:00:00 2001 From: Igor Springer Date: Tue, 11 Feb 2020 17:47:49 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20Check=20only=20object's=20private=20meth?= =?UTF-8?q?od=20when=20preventing=20delegati=E2=80=A6=20(#875)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/drapergem/draper/pull/849 introduced a valid fix to prevent calling object's public method when a decorator overwrites it through a private one. There is one caveat, though. `private_methods` methods has `all` parameter set to `true` by default (https://ruby-doc.org/core-2.7.0/Object.html#method-i-private_methods)`. As a result all private methods are returned, instead of only the ones defined on the object. This commit fixes the above issue by setting the `all` parameter to `false`. --- lib/draper/automatic_delegation.rb | 2 +- spec/draper/decorator_spec.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/draper/automatic_delegation.rb b/lib/draper/automatic_delegation.rb index 8d62faf..bd78884 100644 --- a/lib/draper/automatic_delegation.rb +++ b/lib/draper/automatic_delegation.rb @@ -20,7 +20,7 @@ module Draper # @private def delegatable?(method) - return if private_methods.include?(method) + return if private_methods(false).include?(method) object.respond_to?(method) end diff --git a/spec/draper/decorator_spec.rb b/spec/draper/decorator_spec.rb index 0f50aa4..9517ee3 100644 --- a/spec/draper/decorator_spec.rb +++ b/spec/draper/decorator_spec.rb @@ -684,6 +684,18 @@ module Draper expect{ decorator.hello_world }.to raise_error NoMethodError end end + + context 'when delegated method has the same name as private method defined on another object' do + let(:decorator_class) { Class.new(Decorator) } + let(:object) { Class.new { def print; end }.new } + + it 'delegates the public method defined on the object' do + decorator = decorator_class.new(object) + + # `print` private method is defined on `Object` + expect{ decorator.print }.not_to raise_error NoMethodError + end + end end context ".method_missing" do