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

ruby-changes:26293

From: shugo <ko1@a...>
Date: Wed, 12 Dec 2012 18:36:00 +0900 (JST)
Subject: [ruby-changes:26293] shugo:r38344 (trunk): * class.c (rb_prepend_module): move refined methods from the origin

shugo	2012-12-12 18:35:50 +0900 (Wed, 12 Dec 2012)

  New Revision: 38344

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38344

  Log:
    * class.c (rb_prepend_module): move refined methods from the origin
      of a class to the class, because refinements should have priority
      over prepended modules.
    
    * test/ruby/test_refinement.rb: related test.

  Modified files:
    trunk/ChangeLog
    trunk/class.c
    trunk/test/ruby/test_refinement.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 38343)
+++ ChangeLog	(revision 38344)
@@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Wed Dec 12 18:30:29 2012  Shugo Maeda  <shugo@r...>
+
+	* class.c (rb_prepend_module): move refined methods from the origin
+	  of a class to the class, because refinements should have priority
+	  over prepended modules.
+
+	* test/ruby/test_refinement.rb: related test.
+
 Wed Dec 12 18:27:09 2012  Nobuyoshi Nakada  <nobu@r...>
 
 	* time.c (zone_str): lookup or insert by using st_update() at once.
Index: class.c
===================================================================
--- class.c	(revision 38343)
+++ class.c	(revision 38344)
@@ -731,6 +731,33 @@ include_modules_at(VALUE klass, VALUE c, https://github.com/ruby/ruby/blob/trunk/class.c#L731
     return changed;
 }
 
+static int
+move_refined_method(st_data_t key, st_data_t value, st_data_t data)
+{
+    rb_method_entry_t *me = (rb_method_entry_t *) value;
+    st_table *tbl = (st_table *) data;
+
+    if (me->def->type == VM_METHOD_TYPE_REFINED) {
+	if (me->def->body.orig_me) {
+	    rb_method_entry_t *orig_me = me->def->body.orig_me, *new_me;
+	    me->def->body.orig_me = NULL;
+	    new_me = ALLOC(rb_method_entry_t);
+	    *new_me = *me;
+	    st_add_direct(tbl, key, (st_data_t) new_me);
+	    *me = *orig_me;
+	    xfree(orig_me);
+	    return ST_CONTINUE;
+	}
+	else {
+	    st_add_direct(tbl, key, (st_data_t) me);
+	    return ST_DELETE;
+	}
+    }
+    else {
+	return ST_CONTINUE;
+    }
+}
+
 void
 rb_prepend_module(VALUE klass, VALUE module)
 {
@@ -754,6 +781,8 @@ rb_prepend_module(VALUE klass, VALUE mod https://github.com/ruby/ruby/blob/trunk/class.c#L781
 	RCLASS_ORIGIN(klass) = origin;
 	RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
 	RCLASS_M_TBL(klass) = st_init_numtable();
+	st_foreach(RCLASS_M_TBL(origin), move_refined_method,
+		   (st_data_t) RCLASS_M_TBL(klass));
     }
     changed = include_modules_at(klass, klass, module);
     if (changed < 0)
Index: test/ruby/test_refinement.rb
===================================================================
--- test/ruby/test_refinement.rb	(revision 38343)
+++ test/ruby/test_refinement.rb	(revision 38344)
@@ -755,6 +755,51 @@ class TestRefinement < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_refinement.rb#L755
                  PrependIntoRefinement::User.invoke_baz_on(x))
   end
 
+  module PrependAfterRefine
+    class C
+      def foo
+        "original"
+      end
+    end
+
+    module M
+      refine C do
+        def foo
+          "refined"
+        end
+
+        def bar
+          "refined"
+        end
+      end
+    end
+
+    module Mixin
+      def foo
+        "mixin"
+      end
+
+      def bar
+        "mixin"
+      end
+    end
+
+    class C
+      prepend Mixin
+    end
+  end
+
+  def test_prepend_after_refine
+    x = eval_using(PrependAfterRefine::M,
+                   "TestRefinement::PrependAfterRefine::C.new.foo")
+    assert_equal("refined", x)
+    assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.foo)
+    y = eval_using(PrependAfterRefine::M,
+                   "TestRefinement::PrependAfterRefine::C.new.bar")
+    assert_equal("refined", y)
+    assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.bar)
+  end
+
   private
 
   def eval_using(mod, s)

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

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