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

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/

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