ruby-changes:28632
From: nobu <ko1@a...>
Date: Mon, 13 May 2013 14:54:02 +0900 (JST)
Subject: [ruby-changes:28632] nobu:r40684 (trunk): proc.c: Kernel#singleton_method
nobu 2013-05-13 14:52:03 +0900 (Mon, 13 May 2013) New Revision: 40684 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=40684 Log: 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] Modified files: trunk/ChangeLog trunk/proc.c trunk/test/ruby/test_method.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 40683) +++ ChangeLog (revision 40684) @@ -1,4 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 -Mon May 13 14:51:12 2013 Nobuyoshi Nakada <nobu@r...> +Mon May 13 14:51:59 2013 Nobuyoshi Nakada <nobu@r...> + + * 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. Index: proc.c =================================================================== --- proc.c (revision 40683) +++ proc.c (revision 40684) @@ -933,18 +933,18 @@ rb_obj_is_method(VALUE m) https://github.com/ruby/ruby/blob/trunk/proc.c#L933 } 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, VALU https://github.com/ruby/ruby/blob/trunk/proc.c#L988 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, VALU https://github.com/ruby/ruby/blob/trunk/proc.c#L1020 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); +} + /********************************************************************** * @@ -1274,6 +1284,48 @@ rb_obj_public_method(VALUE obj, VALUE vi https://github.com/ruby/ruby/blob/trunk/proc.c#L1284 /* * 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 * * Returns an +UnboundMethod+ representing the given @@ -2372,6 +2424,7 @@ Init_Proc(void) https://github.com/ruby/ruby/blob/trunk/proc.c#L2424 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); Index: test/ruby/test_method.rb =================================================================== --- test/ruby/test_method.rb (revision 40683) +++ test/ruby/test_method.rb (revision 40684) @@ -629,4 +629,16 @@ class TestMethod < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_method.rb#L629 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/