From 88e06fbf61c14c8f372637de5ebdd2ced10bf141 Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Tue, 2 Jul 2019 15:06:54 +0100 Subject: [PATCH] Allow calling a private method with `self.` This makes it consistent with calling private attribute assignment methods, which currently is allowed (e.g. `self.value =`). Calling a private method in this way can be useful when trying to assign the return value to a local variable with the same name. --- compile.c | 5 ++++- spec/ruby/language/send_spec.rb | 2 +- test/ruby/test_method.rb | 2 +- test/ruby/test_module.rb | 3 ++- test/ruby/test_refinement.rb | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compile.c b/compile.c index 26b580b090..6a6eeb27cb 100644 --- a/compile.c +++ b/compile.c @@ -6609,7 +6609,10 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) { ADD_INSN2(recv, nd_line(node->nd_recv), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level)); } - else { + else if (private_recv_p(node)) { + ADD_INSN(recv, nd_line(node), putself); + flag |= VM_CALL_FCALL; + } else { CHECK(COMPILE(recv, "recv", node->nd_recv)); } diff --git a/spec/ruby/language/send_spec.rb b/spec/ruby/language/send_spec.rb index 4ba3dcc9c2..cce2e1acb9 100644 --- a/spec/ruby/language/send_spec.rb +++ b/spec/ruby/language/send_spec.rb @@ -260,7 +260,7 @@ def []=(*) describe "Invoking a private getter method" do it "does not permit self as a receiver" do receiver = LangSendSpecs::PrivateGetter.new - -> { receiver.call_self_foo }.should raise_error(NoMethodError) + -> { receiver.call_self_foo }.should_not raise_error(NoMethodError) -> { receiver.call_self_foo_or_equals(6) }.should raise_error(NoMethodError) end end diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index ba425a4517..a2bb54dad3 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -667,7 +667,7 @@ def test_visibility assert_nothing_raised { mv3 } assert_nothing_raised { self.mv1 } - assert_raise(NoMethodError) { self.mv2 } + assert_nothing_raised { self.mv2 } assert_nothing_raised { self.mv3 } v = Visibility.new diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index d56e63e4be..d4baa65dfb 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -2477,7 +2477,8 @@ def assert_top_method_is_private(method) assert_include(methods, :#{method}, ":#{method} should be private") assert_raise_with_message(NoMethodError, "private method `#{method}' called for main:Object") { - self.#{method} + recv = self + recv.#{method} } } end diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index 87d60e41a4..4be0720983 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -538,7 +538,7 @@ def foo def test_main_using_is_private assert_raise(NoMethodError) do - eval("self.using Module.new", Sandbox::BINDING) + eval("recv = self; recv.using Module.new", Sandbox::BINDING) end end -- 2.21.0