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/