зеркало из https://github.com/github/ruby.git
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38344 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
a773539d3a
Коммит
75bed271f0
|
@ -1,3 +1,11 @@
|
|||
Wed Dec 12 18:30:29 2012 Shugo Maeda <shugo@ruby-lang.org>
|
||||
|
||||
* 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@ruby-lang.org>
|
||||
|
||||
* time.c (zone_str): lookup or insert by using st_update() at once.
|
||||
|
|
29
class.c
29
class.c
|
@ -731,6 +731,33 @@ include_modules_at(VALUE klass, VALUE c, VALUE module)
|
|||
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 module)
|
|||
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)
|
||||
|
|
|
@ -755,6 +755,51 @@ class TestRefinement < Test::Unit::TestCase
|
|||
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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче