зеркало из https://github.com/github/ruby.git
proc.c: Kernel#singleton_method
* proc.c (rb_obj_singleton_method): new method Kernel#singleton_method which returns a Method object of the singleton method. non-singleton method causes NameError, but not aliased or zsuper method, right now. [ruby-core:54914] [Feature #8391] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40684 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
3048508014
Коммит
0824f9f224
|
@ -1,4 +1,10 @@
|
|||
Mon May 13 14:51:12 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
Mon May 13 14:51:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* proc.c (rb_obj_singleton_method): new method Kernel#singleton_method
|
||||
which returns a Method object of the singleton method.
|
||||
non-singleton method causes NameError, but not aliased or zsuper
|
||||
method, right now.
|
||||
[ruby-core:54914] [Feature #8391]
|
||||
|
||||
* vm_method.c (rb_method_entry_at): return the method entry for id at
|
||||
klass, without ancestors.
|
||||
|
|
61
proc.c
61
proc.c
|
@ -933,18 +933,18 @@ rb_obj_is_method(VALUE m)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||||
mnew_from_me(rb_method_entry_t *me, VALUE defined_class, VALUE klass,
|
||||
VALUE obj, ID id, VALUE mclass, int scope)
|
||||
{
|
||||
VALUE method;
|
||||
VALUE rclass = klass, defined_class;
|
||||
VALUE rclass = klass;
|
||||
ID rid = id;
|
||||
struct METHOD *data;
|
||||
rb_method_entry_t *me, meb;
|
||||
rb_method_entry_t meb;
|
||||
rb_method_definition_t *def = 0;
|
||||
rb_method_flag_t flag = NOEX_UNDEF;
|
||||
|
||||
again:
|
||||
me = rb_method_entry_without_refinements(klass, id, &defined_class);
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||
ID rmiss = idRespond_to_missing;
|
||||
VALUE sym = ID2SYM(id);
|
||||
|
@ -988,6 +988,7 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
|||
if (def && def->type == VM_METHOD_TYPE_ZSUPER) {
|
||||
klass = RCLASS_SUPER(defined_class);
|
||||
id = def->original_id;
|
||||
me = rb_method_entry_without_refinements(klass, id, &defined_class);
|
||||
goto again;
|
||||
}
|
||||
|
||||
|
@ -1019,6 +1020,15 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
|||
return method;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||||
{
|
||||
VALUE defined_class;
|
||||
rb_method_entry_t *me =
|
||||
rb_method_entry_without_refinements(klass, id, &defined_class);
|
||||
return mnew_from_me(me, defined_class, klass, obj, id, mclass, scope);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
|
@ -1272,6 +1282,48 @@ rb_obj_public_method(VALUE obj, VALUE vid)
|
|||
return mnew(CLASS_OF(obj), obj, id, rb_cMethod, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.singleton_method(sym) -> method
|
||||
*
|
||||
* Similar to _method_, searches singleton method only.
|
||||
*
|
||||
* class Demo
|
||||
* def initialize(n)
|
||||
* @iv = n
|
||||
* end
|
||||
* def hello()
|
||||
* "Hello, @iv = #{@iv}"
|
||||
* end
|
||||
* end
|
||||
*
|
||||
* k = Demo.new(99)
|
||||
* def k.hi
|
||||
* "Hi, @iv = #{@iv}"
|
||||
* end
|
||||
* m = k.singleton_method(:hi)
|
||||
* m.call #=> "Hi, @iv = 99"
|
||||
* m = k.singleton_method(:hello) #=> NameError
|
||||
*/
|
||||
|
||||
VALUE
|
||||
rb_obj_singleton_method(VALUE obj, VALUE vid)
|
||||
{
|
||||
rb_method_entry_t *me;
|
||||
VALUE klass;
|
||||
ID id = rb_check_id(&vid);
|
||||
if (!id) {
|
||||
rb_name_error_str(vid, "undefined singleton method `%"PRIsVALUE"' for `%"PRIsVALUE"'",
|
||||
QUOTE(vid), obj);
|
||||
}
|
||||
if (NIL_P(klass = rb_singleton_class_get(obj)) ||
|
||||
!(me = rb_method_entry_at(klass, id))) {
|
||||
rb_name_error(id, "undefined singleton method `%"PRIsVALUE"' for `%"PRIsVALUE"'",
|
||||
QUOTE_ID(id), obj);
|
||||
}
|
||||
return mnew_from_me(me, klass, klass, obj, id, rb_cMethod, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* mod.instance_method(symbol) -> unbound_method
|
||||
|
@ -2372,6 +2424,7 @@ Init_Proc(void)
|
|||
rb_define_method(rb_cMethod, "parameters", rb_method_parameters, 0);
|
||||
rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
|
||||
rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1);
|
||||
rb_define_method(rb_mKernel, "singleton_method", rb_obj_singleton_method, 1);
|
||||
|
||||
/* UnboundMethod */
|
||||
rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject);
|
||||
|
|
|
@ -629,4 +629,16 @@ class TestMethod < Test::Unit::TestCase
|
|||
end
|
||||
assert_raise(Timeout::Error, bug8100) {raise e if e}
|
||||
end
|
||||
|
||||
def test_singleton_method
|
||||
feature8391 = '[ruby-core:54914] [Feature #8391]'
|
||||
c1 = Class.new
|
||||
c1.class_eval { def foo; :foo; end }
|
||||
o = c1.new
|
||||
def o.bar; :bar; end
|
||||
assert_nothing_raised(NameError) {o.method(:foo)}
|
||||
assert_raise(NameError, feature8391) {o.singleton_method(:foo)}
|
||||
m = assert_nothing_raised(NameError, feature8391) {break o.singleton_method(:bar)}
|
||||
assert_equal(:bar, m.call, feature8391)
|
||||
end
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче