[前][次][番号順一覧][スレッド一覧]

ruby-changes:64335

From: Rados=C5=82aw <ko1@a...>
Date: Sat, 19 Dec 2020 19:51:10 +0900 (JST)
Subject: [ruby-changes:64335] eb8ea336d3 (master): Feature 17314: allow to pass array to public, protected and private methods

https://git.ruby-lang.org/ruby.git/commit/?id=eb8ea336d3

From eb8ea336d33af7e1dec4c17964c671c33cf75ce1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rados=C5=82aw=20Bu=C5=82at?= <radek.bulat@g...>
Date: Fri, 18 Dec 2020 19:17:57 +0100
Subject: Feature 17314: allow to pass array to public, protected and private
 methods


diff --git a/NEWS.md b/NEWS.md
index f72e7f0..3e42459 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -249,6 +249,9 @@ Outstanding ones only. https://github.com/ruby/ruby/blob/trunk/NEWS.md#L249
         p C.ancestors #=> [C, M1, M2, Object, Kernel, BasicObject]
         ```
 
+    * Module#public, Module#protected and Module#private methods now accept single
+      array argument with a list of method names. [[Feature #17314]]
+
     * Module#attr_accessor, Module#attr_reader, Module#attr_writer and Module#attr
       methods now return array of defined methods names as symbols.
       [[Feature #17314]]
diff --git a/spec/ruby/core/main/fixtures/classes.rb b/spec/ruby/core/main/fixtures/classes.rb
index 6aba948..757cee4 100644
--- a/spec/ruby/core/main/fixtures/classes.rb
+++ b/spec/ruby/core/main/fixtures/classes.rb
@@ -13,6 +13,14 @@ def main_public_method https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/main/fixtures/classes.rb#L13
 end
 public :main_public_method
 
+def main_public_method2
+end
+public :main_public_method2
+
 def main_private_method
 end
 private :main_private_method
+
+def main_private_method2
+end
+private :main_private_method2
diff --git a/spec/ruby/core/main/private_spec.rb b/spec/ruby/core/main/private_spec.rb
index e34e0c7..78c5d28 100644
--- a/spec/ruby/core/main/private_spec.rb
+++ b/spec/ruby/core/main/private_spec.rb
@@ -4,20 +4,41 @@ require_relative 'fixtures/classes' https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/main/private_spec.rb#L4
 describe "main#private" do
   after :each do
     Object.send(:public, :main_public_method)
+    Object.send(:public, :main_public_method2)
   end
 
-  it "sets the visibility of the given method to private" do
-    eval "private :main_public_method", TOPLEVEL_BINDING
-    Object.should have_private_method(:main_public_method)
+  context "when single argument is passed and it is not an array" do
+    it "sets the visibility of the given methods to private" do
+      eval "private :main_public_method", TOPLEVEL_BINDING
+      Object.should have_private_method(:main_public_method)
+    end
+  end
+
+  context "when multiple arguments are passed" do
+    it "sets the visibility of the given methods to private" do
+      eval "private :main_public_method, :main_public_method2", TOPLEVEL_BINDING
+      Object.should have_private_method(:main_public_method)
+      Object.should have_private_method(:main_public_method2)
+    end
+  end
+
+  ruby_version_is "3.0" do
+    context "when single argument is passed and is an array" do
+      it "sets the visibility of the given methods to private" do
+        eval "private [:main_public_method, :main_public_method2]", TOPLEVEL_BINDING
+        Object.should have_private_method(:main_public_method)
+        Object.should have_private_method(:main_public_method2)
+      end
+    end
   end
 
   it "returns Object" do
     eval("private :main_public_method", TOPLEVEL_BINDING).should equal(Object)
   end
 
-  it "raises a NameError when given an undefined name" do
+  it "raises a NameError when at least one of given method names is undefined" do
     -> do
-      eval "private :main_undefined_method", TOPLEVEL_BINDING
+      eval "private :main_public_method, :main_undefined_method", TOPLEVEL_BINDING
     end.should raise_error(NameError)
   end
 end
diff --git a/spec/ruby/core/main/public_spec.rb b/spec/ruby/core/main/public_spec.rb
index afe25c7..bfc27a9e 100644
--- a/spec/ruby/core/main/public_spec.rb
+++ b/spec/ruby/core/main/public_spec.rb
@@ -4,11 +4,32 @@ require_relative 'fixtures/classes' https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/main/public_spec.rb#L4
 describe "main#public" do
   after :each do
     Object.send(:private, :main_private_method)
+    Object.send(:private, :main_private_method2)
   end
 
-  it "sets the visibility of the given method to public" do
-    eval "public :main_private_method", TOPLEVEL_BINDING
-    Object.should_not have_private_method(:main_private_method)
+  context "when single argument is passed and it is not an array" do
+    it "sets the visibility of the given methods to public" do
+      eval "public :main_private_method", TOPLEVEL_BINDING
+      Object.should_not have_private_method(:main_private_method)
+    end
+  end
+
+  context "when multiple arguments are passed" do
+    it "sets the visibility of the given methods to public" do
+      eval "public :main_private_method, :main_private_method2", TOPLEVEL_BINDING
+      Object.should_not have_private_method(:main_private_method)
+      Object.should_not have_private_method(:main_private_method2)
+    end
+  end
+
+  ruby_version_is "3.0" do
+    context "when single argument is passed and is an array" do
+      it "sets the visibility of the given methods to public" do
+        eval "public [:main_private_method, :main_private_method2]", TOPLEVEL_BINDING
+        Object.should_not have_private_method(:main_private_method)
+        Object.should_not have_private_method(:main_private_method2)
+      end
+    end
   end
 
   it "returns Object" do
diff --git a/spec/ruby/core/module/shared/set_visibility.rb b/spec/ruby/core/module/shared/set_visibility.rb
index a04b1a5..9f31e23 100644
--- a/spec/ruby/core/module/shared/set_visibility.rb
+++ b/spec/ruby/core/module/shared/set_visibility.rb
@@ -6,6 +6,40 @@ describe :set_visibility, shared: true do https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/module/shared/set_visibility.rb#L6
   end
 
   describe "with argument" do
+    describe "one or more arguments" do
+      it "sets visibility of given method names" do
+        visibility = @method
+        old_visibility = [:protected, :private].find {|vis| vis != visibility }
+
+        mod = Module.new {
+          send old_visibility
+          def test1() end
+          def test2() end
+          send visibility, :test1, :test2
+        }
+        mod.should send(:"have_#{visibility}_instance_method", :test1, false)
+        mod.should send(:"have_#{visibility}_instance_method", :test2, false)
+      end
+    end
+
+    ruby_version_is "3.0" do
+      describe "array as a single argument" do
+        it "sets visibility of given method names" do
+          visibility = @method
+          old_visibility = [:protected, :private].find {|vis| vis != visibility }
+
+          mod = Module.new {
+            send old_visibility
+            def test1() end
+            def test2() end
+            send visibility, [:test1, :test2]
+          }
+          mod.should send(:"have_#{visibility}_instance_method", :test1, false)
+          mod.should send(:"have_#{visibility}_instance_method", :test2, false)
+        end
+      end
+    end
+
     it "does not clone method from the ancestor when setting to the same visibility in a child" do
       visibility = @method
       parent = Module.new {
diff --git a/vm_method.c b/vm_method.c
index 1546722..1fbb481 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -1974,6 +1974,16 @@ rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1974
 }
 
 static void
+check_and_export_method(VALUE self, VALUE name, rb_method_visibility_t visi)
+{
+    ID id = rb_check_id(&name);
+    if (!id) {
+	rb_print_undef_str(self, name);
+    }
+    rb_export_method(self, id, visi);
+}
+
+static void
 set_method_visibility(VALUE self, int argc, const VALUE *argv, rb_method_visibility_t visi)
 {
     int i;
@@ -1985,13 +1995,19 @@ set_method_visibility(VALUE self, int argc, const VALUE *argv, rb_method_visibil https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1995
 	return;
     }
 
-    for (i = 0; i < argc; i++) {
-	VALUE v = argv[i];
-	ID id = rb_check_id(&v);
-	if (!id) {
-	    rb_print_undef_str(self, v);
+
+    VALUE v;
+
+    if (argc == 1 && (v = rb_check_array_type(argv[0])) != Qnil) {
+        long j;
+
+	for (j = 0; j < RARRAY_LEN(v); j++) {
+	    check_and_export_method(self, RARRAY_AREF(v, j), visi);
 	}
-	rb_export_method(self, id, visi);
+    } else {
+        for (i = 0; i < argc; i++) {
+            check_and_export_method(self, argv[i], visi);
+        }
     }
 }
 
@@ -2013,6 +2029,7 @@ set_visibility(int argc, const VALUE *argv, VALUE module, rb_method_visibility_t https://github.com/ruby/ruby/blob/trunk/vm_method.c#L2029
  *     public                 -> self
  *     public(symbol, ...)    -> self
  *     public(string, ...)    -> self
+ *     public(array)          -> self
  *
  *  With no arguments, sets the default visibility for subsequently
  *  defined methods to public. With arguments, sets the named methods to
@@ -2031,6 +2048,7 @@ rb_mod_public(int argc, VALUE *argv, VALUE module) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L2048
  *     protected                -> self
  *     protected(symbol, ...)   -> self
  *     protected(string, ...)   -> self
+ *     protected(array)         -> self
  *
  *  With no arguments, sets the default visibility for subsequently
  *  defined methods to protected. With arguments, sets the named methods
@@ -2058,6 +2076,7 @@ rb_mod_protected(int argc, VALUE *argv, VALUE module) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L2076
  *     private                 -> self
  *     private(symbol, ...)    -> self
  *     private(string, ...)    -> self
+ *     private(array)          -> self
  *
  *  With no arguments, sets the default visibility for subsequently
  *  defined methods to private. With arguments, sets the named methods
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]