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]
This commit is contained in:
parent
f3b58e1d38
commit
173a6b6a80
Notes:
git
2022-03-30 04:10:34 +09:00
108
proc.c
108
proc.c
@ -2165,61 +2165,14 @@ rb_mod_public_instance_method(VALUE mod, VALUE vid)
|
|||||||
return mnew_unbound(mod, id, rb_cUnboundMethod, TRUE);
|
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
|
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;
|
ID id;
|
||||||
VALUE body;
|
VALUE body;
|
||||||
VALUE name;
|
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;
|
int is_method = FALSE;
|
||||||
|
|
||||||
if (cref) {
|
|
||||||
scope_visi = CREF_SCOPE_VISI(cref);
|
|
||||||
}
|
|
||||||
|
|
||||||
rb_check_arity(argc, 1, 2);
|
rb_check_arity(argc, 1, 2);
|
||||||
name = argv[0];
|
name = argv[0];
|
||||||
id = rb_check_id(&name);
|
id = rb_check_id(&name);
|
||||||
@ -2280,12 +2233,66 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
|
|||||||
return ID2SYM(id);
|
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:
|
* call-seq:
|
||||||
* define_singleton_method(symbol, method) -> symbol
|
* define_singleton_method(symbol, method) -> symbol
|
||||||
* define_singleton_method(symbol) { block } -> 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.
|
* 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 is specified, it is used as the method body.
|
||||||
* If a block or a method has parameters, they're used as method parameters.
|
* If a block or a method has parameters, they're used as method parameters.
|
||||||
@ -2315,8 +2322,9 @@ static VALUE
|
|||||||
rb_obj_define_method(int argc, VALUE *argv, VALUE obj)
|
rb_obj_define_method(int argc, VALUE *argv, VALUE obj)
|
||||||
{
|
{
|
||||||
VALUE klass = rb_singleton_class(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -323,6 +323,17 @@ class TestMethod < Test::Unit::TestCase
|
|||||||
assert_equal(:foo, o.foo)
|
assert_equal(:foo, o.foo)
|
||||||
end
|
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
|
def test_define_singleton_method_no_proc
|
||||||
o = Object.new
|
o = Object.new
|
||||||
assert_raise(ArgumentError) {
|
assert_raise(ArgumentError) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user