Project

General

Profile

Feature #16123 ยป 0001-Allow-calling-a-private-method-with-self.diff.txt

Allow calling a private method with `self.` - dylants (Dylan Thacker-Smith), 08/23/2019 08:44 PM

 
1
From 88e06fbf61c14c8f372637de5ebdd2ced10bf141 Mon Sep 17 00:00:00 2001
2
From: Dylan Thacker-Smith <Dylan.Smith@shopify.com>
3
Date: Tue, 2 Jul 2019 15:06:54 +0100
4
Subject: [PATCH] Allow calling a private method with `self.`
5

    
6
This makes it consistent with calling private attribute assignment
7
methods, which currently is allowed (e.g. `self.value =`).
8

    
9
Calling a private method in this way can be useful when trying to
10
assign the return value to a local variable with the same name.
11
---
12
 compile.c                       | 5 ++++-
13
 spec/ruby/language/send_spec.rb | 2 +-
14
 test/ruby/test_method.rb        | 2 +-
15
 test/ruby/test_module.rb        | 3 ++-
16
 test/ruby/test_refinement.rb    | 2 +-
17
 5 files changed, 9 insertions(+), 5 deletions(-)
18

    
19
diff --git a/compile.c b/compile.c
20
index 26b580b090..6a6eeb27cb 100644
21
--- a/compile.c
22
+++ b/compile.c
23
@@ -6609,7 +6609,10 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
24
             iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
25
             ADD_INSN2(recv, nd_line(node->nd_recv), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
26
         }
27
-        else {
28
+        else if (private_recv_p(node)) {
29
+            ADD_INSN(recv, nd_line(node), putself);
30
+            flag |= VM_CALL_FCALL;
31
+        } else {
32
             CHECK(COMPILE(recv, "recv", node->nd_recv));
33
         }
34
 
35
diff --git a/spec/ruby/language/send_spec.rb b/spec/ruby/language/send_spec.rb
36
index 4ba3dcc9c2..cce2e1acb9 100644
37
--- a/spec/ruby/language/send_spec.rb
38
+++ b/spec/ruby/language/send_spec.rb
39
@@ -260,7 +260,7 @@ def []=(*)
40
 describe "Invoking a private getter method" do
41
   it "does not permit self as a receiver" do
42
     receiver = LangSendSpecs::PrivateGetter.new
43
-    -> { receiver.call_self_foo }.should raise_error(NoMethodError)
44
+    -> { receiver.call_self_foo }.should_not raise_error(NoMethodError)
45
     -> { receiver.call_self_foo_or_equals(6) }.should raise_error(NoMethodError)
46
   end
47
 end
48
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
49
index ba425a4517..a2bb54dad3 100644
50
--- a/test/ruby/test_method.rb
51
+++ b/test/ruby/test_method.rb
52
@@ -667,7 +667,7 @@ def test_visibility
53
     assert_nothing_raised { mv3 }
54
 
55
     assert_nothing_raised { self.mv1 }
56
-    assert_raise(NoMethodError) { self.mv2 }
57
+    assert_nothing_raised { self.mv2 }
58
     assert_nothing_raised { self.mv3 }
59
 
60
     v = Visibility.new
61
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
62
index d56e63e4be..d4baa65dfb 100644
63
--- a/test/ruby/test_module.rb
64
+++ b/test/ruby/test_module.rb
65
@@ -2477,7 +2477,8 @@ def assert_top_method_is_private(method)
66
       assert_include(methods, :#{method}, ":#{method} should be private")
67
 
68
       assert_raise_with_message(NoMethodError, "private method `#{method}' called for main:Object") {
69
-        self.#{method}
70
+        recv = self
71
+        recv.#{method}
72
       }
73
     }
74
   end
75
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
76
index 87d60e41a4..4be0720983 100644
77
--- a/test/ruby/test_refinement.rb
78
+++ b/test/ruby/test_refinement.rb
79
@@ -538,7 +538,7 @@ def foo
80
 
81
   def test_main_using_is_private
82
     assert_raise(NoMethodError) do
83
-      eval("self.using Module.new", Sandbox::BINDING)
84
+      eval("recv = self; recv.using Module.new", Sandbox::BINDING)
85
     end
86
   end
87
 
88
-- 
89
2.21.0
90