ruby-changes:64250
From: Rados=C5=82aw <ko1@a...>
Date: Fri, 18 Dec 2020 02:46:25 +0900 (JST)
Subject: [ruby-changes:64250] 81739ad4fd (master): Better cooperation between public/protected/private with attr* and alias_method
https://git.ruby-lang.org/ruby.git/commit/?id=81739ad4fd From 81739ad4fdfcc86a769056fec352f27c686fba1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Bu=C5=82at?= <radek.bulat@g...> Date: Mon, 9 Nov 2020 11:25:11 +0100 Subject: Better cooperation between public/protected/private with attr* and alias_method diff --git a/NEWS.md b/NEWS.md index 2e20e8d..613976b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -249,6 +249,16 @@ 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]] + + * Module#alias_method now returns the defined alias as symbol. + [[Feature #17314]] + * Mutex * `Mutex` is now acquired per-`Fiber` instead of per-`Thread`. This change @@ -691,3 +701,4 @@ end https://github.com/ruby/ruby/blob/trunk/NEWS.md#L701 [Feature #17371]: https://bugs.ruby-lang.org/issues/17371 [GH-2991]: https://github.com/ruby/ruby/pull/2991 [Bug #17030]: https://bugs.ruby-lang.org/issues/17030 +[Feature #17314]: https://bugs.ruby-lang.org/issues/17314 diff --git a/object.c b/object.c index 552b10b..4fe6b02 100644 --- a/object.c +++ b/object.c @@ -2255,37 +2255,42 @@ id_for_attr(VALUE obj, VALUE name) https://github.com/ruby/ruby/blob/trunk/object.c#L2255 /* * call-seq: - * attr_reader(symbol, ...) -> nil - * attr(symbol, ...) -> nil - * attr_reader(string, ...) -> nil - * attr(string, ...) -> nil + * attr_reader(symbol, ...) -> array + * attr(symbol, ...) -> array + * attr_reader(string, ...) -> array + * attr(string, ...) -> array * * Creates instance variables and corresponding methods that return the * value of each instance variable. Equivalent to calling * ``<code>attr</code><i>:name</i>'' on each name in turn. * String arguments are converted to symbols. + * Returns an array of defined methods names as symbols. */ static VALUE rb_mod_attr_reader(int argc, VALUE *argv, VALUE klass) { int i; + VALUE names = rb_ary_new2(argc); for (i=0; i<argc; i++) { - rb_attr(klass, id_for_attr(klass, argv[i]), TRUE, FALSE, TRUE); + ID id = id_for_attr(klass, argv[i]); + rb_attr(klass, id, TRUE, FALSE, TRUE); + rb_ary_push(names, ID2SYM(id)); } - return Qnil; + return names; } /** * call-seq: - * attr(name, ...) -> nil - * attr(name, true) -> nil - * attr(name, false) -> nil + * attr(name, ...) -> array + * attr(name, true) -> array + * attr(name, false) -> array * * The first form is equivalent to #attr_reader. * The second form is equivalent to <code>attr_accessor(name)</code> but deprecated. * The last form is equivalent to <code>attr_reader(name)</code> but deprecated. + * Returns an array of defined methods names as symbols. *-- * \private * \todo can be static? @@ -2295,47 +2300,57 @@ VALUE https://github.com/ruby/ruby/blob/trunk/object.c#L2300 rb_mod_attr(int argc, VALUE *argv, VALUE klass) { if (argc == 2 && (argv[1] == Qtrue || argv[1] == Qfalse)) { + ID id = id_for_attr(klass, argv[0]); + VALUE names = rb_ary_new(); + rb_warning("optional boolean argument is obsoleted"); - rb_attr(klass, id_for_attr(klass, argv[0]), 1, RTEST(argv[1]), TRUE); - return Qnil; + rb_attr(klass, id, 1, RTEST(argv[1]), TRUE); + rb_ary_push(names, ID2SYM(id)); + if (argv[1] == Qtrue) rb_ary_push(names, rb_str_intern(rb_sprintf("%"PRIsVALUE"=", ID2SYM(id)))); + return names; } return rb_mod_attr_reader(argc, argv, klass); } /* * call-seq: - * attr_writer(symbol, ...) -> nil - * attr_writer(string, ...) -> nil + * attr_writer(symbol, ...) -> array + * attr_writer(string, ...) -> array * * Creates an accessor method to allow assignment to the attribute * <i>symbol</i><code>.id2name</code>. * String arguments are converted to symbols. + * Returns an array of defined methods names as symbols. */ static VALUE rb_mod_attr_writer(int argc, VALUE *argv, VALUE klass) { int i; + VALUE names = rb_ary_new2(argc); for (i=0; i<argc; i++) { - rb_attr(klass, id_for_attr(klass, argv[i]), FALSE, TRUE, TRUE); + ID id = id_for_attr(klass, argv[i]); + rb_attr(klass, id, FALSE, TRUE, TRUE); + rb_ary_push(names, rb_str_intern(rb_sprintf("%"PRIsVALUE"=", ID2SYM(id)))); } - return Qnil; + return names; } /* * call-seq: - * attr_accessor(symbol, ...) -> nil - * attr_accessor(string, ...) -> nil + * attr_accessor(symbol, ...) -> array + * attr_accessor(string, ...) -> array * * Defines a named attribute for this module, where the name is * <i>symbol.</i><code>id2name</code>, creating an instance variable * (<code>@name</code>) and a corresponding access method to read it. * Also creates a method called <code>name=</code> to set the attribute. * String arguments are converted to symbols. + * Returns an array of defined methods names as symbols. * * module Mod - * attr_accessor(:one, :two) + * attr_accessor(:one, :two) #=> [:one, :one=, :two, :two=] * end * Mod.instance_methods.sort #=> [:one, :one=, :two, :two=] */ @@ -2344,11 +2359,17 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/object.c#L2359 rb_mod_attr_accessor(int argc, VALUE *argv, VALUE klass) { int i; + VALUE names = rb_ary_new2(argc * 2); for (i=0; i<argc; i++) { - rb_attr(klass, id_for_attr(klass, argv[i]), TRUE, TRUE, TRUE); + ID id = id_for_attr(klass, argv[i]); + VALUE idv = ID2SYM(id); + + rb_attr(klass, id, TRUE, TRUE, TRUE); + rb_ary_push(names, idv); + rb_ary_push(names, rb_str_intern(rb_sprintf("%"PRIsVALUE"=", idv))); } - return Qnil; + return names; } /* diff --git a/process.c b/process.c index dee565e..0b2fdeb 100644 --- a/process.c +++ b/process.c @@ -2075,12 +2075,11 @@ check_exec_redirect1(VALUE ary, VALUE key, VALUE param) https://github.com/ruby/ruby/blob/trunk/process.c#L2075 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param))); } else { - int i, n=0; + int i; for (i = 0 ; i < RARRAY_LEN(key); i++) { VALUE v = RARRAY_AREF(key, i); VALUE fd = check_exec_redirect_fd(v, !NIL_P(param)); rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param))); - n++; } } return ary; 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_metho (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/