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

ruby-changes:71541

From: Jeremy <ko1@a...>
Date: Wed, 30 Mar 2022 04:10:26 +0900 (JST)
Subject: [ruby-changes:71541] 173a6b6a80 (master): Make define_singleton_method always define a public method

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

From 173a6b6a802d80b8cf200308fd3653832b700b1c Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Wed, 9 Mar 2022 14:57:49 -0800
Subject: Make define_singleton_method always define a public method

In very unlikely cases, it could previously define a non-public method
starting in Ruby 2.1.

Fixes [Bug #18561]
---
 proc.c                   | 108 +++++++++++++++++++++++++----------------------
 test/ruby/test_method.rb |  11 +++++
 2 files changed, 69 insertions(+), 50 deletions(-)

diff --git a/proc.c b/proc.c
index 93b4013c31..4f43c56006 100644
--- a/proc.c
+++ b/proc.c
@@ -2165,61 +2165,14 @@ rb_mod_public_instance_method(VALUE mod, VALUE vid) https://github.com/ruby/ruby/blob/trunk/proc.c#L2165
     return mnew_unbound(mod, id, rb_cUnboundMethod, TRUE);
 }
 
-/*
- *  call-seq:
- *     define_method(symbol, method)     -> symbol
- *     define_method(symbol) { block }   -> symbol
- *
- *  Defines an instance method in the receiver. The _method_
- *  parameter can be a +Proc+, a +Method+ or an +UnboundMethod+ object.
- *  If a block is specified, it is used as the method body.
- *  If a block or the _method_ parameter has parameters,
- *  they're used as method parameters.
- *  This block is evaluated using #instance_eval.
- *
- *     class A
- *       def fred
- *         puts "In Fred"
- *       end
- *       def create_method(name, &block)
- *         self.class.define_method(name, &block)
- *       end
- *       define_method(:wilma) { puts "Charge it!" }
- *       define_method(:flint) {|name| puts "I'm #{name}!"}
- *     end
- *     class B < A
- *       define_method(:barney, instance_method(:fred))
- *     end
- *     a = B.new
- *     a.barney
- *     a.wilma
- *     a.flint('Dino')
- *     a.create_method(:betty) { p self }
- *     a.betty
- *
- *  <em>produces:</em>
- *
- *     In Fred
- *     Charge it!
- *     I'm Dino!
- *     #<B:0x401b39e8>
- */
-
 static VALUE
-rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
+rb_mod_define_method_with_visibility(int argc, VALUE *argv, VALUE mod, const struct rb_scope_visi_struct* scope_visi)
 {
     ID id;
     VALUE body;
     VALUE name;
-    const rb_cref_t *cref = rb_vm_cref_in_context(mod, mod);
-    const rb_scope_visibility_t default_scope_visi = {METHOD_VISI_PUBLIC, FALSE};
-    const rb_scope_visibility_t *scope_visi = &default_scope_visi;
     int is_method = FALSE;
 
-    if (cref) {
-	scope_visi = CREF_SCOPE_VISI(cref);
-    }
-
     rb_check_arity(argc, 1, 2);
     name = argv[0];
     id = rb_check_id(&name);
@@ -2280,12 +2233,66 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod) https://github.com/ruby/ruby/blob/trunk/proc.c#L2233
     return ID2SYM(id);
 }
 
+/*
+ *  call-seq:
+ *     define_method(symbol, method)     -> symbol
+ *     define_method(symbol) { block }   -> symbol
+ *
+ *  Defines an instance method in the receiver. The _method_
+ *  parameter can be a +Proc+, a +Method+ or an +UnboundMethod+ object.
+ *  If a block is specified, it is used as the method body.
+ *  If a block or the _method_ parameter has parameters,
+ *  they're used as method parameters.
+ *  This block is evaluated using #instance_eval.
+ *
+ *     class A
+ *       def fred
+ *         puts "In Fred"
+ *       end
+ *       def create_method(name, &block)
+ *         self.class.define_method(name, &block)
+ *       end
+ *       define_method(:wilma) { puts "Charge it!" }
+ *       define_method(:flint) {|name| puts "I'm #{name}!"}
+ *     end
+ *     class B < A
+ *       define_method(:barney, instance_method(:fred))
+ *     end
+ *     a = B.new
+ *     a.barney
+ *     a.wilma
+ *     a.flint('Dino')
+ *     a.create_method(:betty) { p self }
+ *     a.betty
+ *
+ *  <em>produces:</em>
+ *
+ *     In Fred
+ *     Charge it!
+ *     I'm Dino!
+ *     #<B:0x401b39e8>
+ */
+
+static VALUE
+rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
+{
+    const rb_cref_t *cref = rb_vm_cref_in_context(mod, mod);
+    const rb_scope_visibility_t default_scope_visi = {METHOD_VISI_PUBLIC, FALSE};
+    const rb_scope_visibility_t *scope_visi = &default_scope_visi;
+
+    if (cref) {
+        scope_visi = CREF_SCOPE_VISI(cref);
+    }
+
+    return rb_mod_define_method_with_visibility(argc, argv, mod, scope_visi);
+}
+
 /*
  *  call-seq:
  *     define_singleton_method(symbol, method) -> symbol
  *     define_singleton_method(symbol) { block } -> symbol
  *
- *  Defines a singleton method in the receiver. The _method_
+ *  Defines a public singleton method in the receiver. The _method_
  *  parameter can be a +Proc+, a +Method+ or an +UnboundMethod+ object.
  *  If a block is specified, it is used as the method body.
  *  If a block or a method has parameters, they're used as method parameters.
@@ -2315,8 +2322,9 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/proc.c#L2322
 rb_obj_define_method(int argc, VALUE *argv, VALUE obj)
 {
     VALUE klass = rb_singleton_class(obj);
+    const rb_scope_visibility_t scope_visi = {METHOD_VISI_PUBLIC, FALSE};
 
-    return rb_mod_define_method(argc, argv, klass);
+    return rb_mod_define_method_with_visibility(argc, argv, klass, &scope_visi);
 }
 
 /*
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index caf8bebd35..83e499913a 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -323,6 +323,17 @@ class TestMethod < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_method.rb#L323
     assert_equal(:foo, o.foo)
   end
 
+  PUBLIC_SINGLETON_TEST = Object.new
+  class << PUBLIC_SINGLETON_TEST
+    private
+    PUBLIC_SINGLETON_TEST.define_singleton_method(:dsm){}
+    def PUBLIC_SINGLETON_TEST.def; end
+  end
+  def test_define_singleton_method_public
+    assert_equal(true, PUBLIC_SINGLETON_TEST.method(:dsm).public?)
+    assert_equal(true, PUBLIC_SINGLETON_TEST.method(:def).public?)
+  end
+
   def test_define_singleton_method_no_proc
     o = Object.new
     assert_raise(ArgumentError) {
-- 
cgit v1.2.1


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

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