diff options
author | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-12-12 09:35:50 +0000 |
---|---|---|
committer | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-12-12 09:35:50 +0000 |
commit | 75bed271f0719642f1866bdbbfa3c9940aad9abb (patch) | |
tree | a2c8cf81bbb39582504a6d104d2a4148c9d2a57e /class.c | |
parent | a773539d3af48a8e95960fa1c98d0be790a6e529 (diff) | |
download | ruby-75bed271f0719642f1866bdbbfa3c9940aad9abb.tar.gz |
* 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
Diffstat (limited to 'class.c')
-rw-r--r-- | class.c | 29 |
1 files changed, 29 insertions, 0 deletions
@@ -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) |