From db051011d68950cd1261f91e724513282d419d9e Mon Sep 17 00:00:00 2001 From: shugo Date: Sat, 8 Dec 2012 02:37:16 +0000 Subject: * eval.c (rb_mod_refine), vm_eval.c (rb_yield_refine_block): Module#refine activates all refinements defined in that module only in a given block. * string.c (sym_to_proc, sym_call): don't use refinements. * test/ruby/test_refinement.rb: related test. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38269 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- eval.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 15 deletions(-) (limited to 'eval.c') diff --git a/eval.c b/eval.c index 20d59541e8..e7da8a63e2 100644 --- a/eval.c +++ b/eval.c @@ -1148,6 +1148,38 @@ refinement_module_include(int argc, VALUE *argv, VALUE module) return result; } +static void +add_activated_refinement(VALUE activated_refinements, + VALUE klass, VALUE refinement) +{ + VALUE iclass, c, superclass = klass; + + if (!NIL_P(c = rb_hash_lookup(activated_refinements, klass))) { + superclass = c; + while (c && TYPE(c) == T_ICLASS) { + if (RBASIC(c)->klass == refinement) { + /* already used refinement */ + return; + } + c = RCLASS_SUPER(c); + } + } + FL_SET(refinement, RMODULE_IS_OVERLAID); + c = iclass = rb_include_class_new(refinement, superclass); + RCLASS_REFINED_CLASS(c) = klass; + refinement = RCLASS_SUPER(refinement); + while (refinement) { + FL_SET(refinement, RMODULE_IS_OVERLAID); + c = RCLASS_SUPER(c) = + rb_include_class_new(refinement, RCLASS_SUPER(c)); + RCLASS_REFINED_CLASS(c) = klass; + refinement = RCLASS_SUPER(refinement); + } + rb_hash_aset(activated_refinements, klass, iclass); +} + +VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements); + /* * call-seq: * refine(klass) { block } -> module @@ -1160,10 +1192,10 @@ refinement_module_include(int argc, VALUE *argv, VALUE module) static VALUE rb_mod_refine(VALUE module, VALUE klass) { - NODE *cref = rb_vm_cref(); - VALUE mod; - ID id_refinements, id_refined_class, id_defined_at; - VALUE refinements; + VALUE refinement; + ID id_refinements, id_activated_refinements, + id_refined_class, id_defined_at; + VALUE refinements, activated_refinements; if (!rb_block_given_p()) { rb_raise(rb_eArgError, "no block given"); @@ -1175,21 +1207,28 @@ rb_mod_refine(VALUE module, VALUE klass) refinements = hidden_identity_hash_new(); rb_ivar_set(module, id_refinements, refinements); } - mod = rb_hash_lookup(refinements, klass); - if (NIL_P(mod)) { - mod = rb_module_new(); - FL_SET(mod, RMODULE_IS_REFINEMENT); + CONST_ID(id_activated_refinements, "__activated_refinements__"); + activated_refinements = rb_attr_get(module, id_activated_refinements); + if (NIL_P(activated_refinements)) { + activated_refinements = hidden_identity_hash_new(); + rb_ivar_set(module, id_activated_refinements, + activated_refinements); + } + refinement = rb_hash_lookup(refinements, klass); + if (NIL_P(refinement)) { + refinement = rb_module_new(); + FL_SET(refinement, RMODULE_IS_REFINEMENT); CONST_ID(id_refined_class, "__refined_class__"); - rb_ivar_set(mod, id_refined_class, klass); + rb_ivar_set(refinement, id_refined_class, klass); CONST_ID(id_defined_at, "__defined_at__"); - rb_ivar_set(mod, id_defined_at, module); - rb_define_singleton_method(mod, "include", + rb_ivar_set(refinement, id_defined_at, module); + rb_define_singleton_method(refinement, "include", refinement_module_include, -1); - rb_using_refinement(cref, klass, mod); - rb_hash_aset(refinements, klass, mod); + rb_hash_aset(refinements, klass, refinement); + add_activated_refinement(activated_refinements, klass, refinement); } - rb_mod_module_eval(0, NULL, mod); - return mod; + rb_yield_refine_block(refinement, activated_refinements); + return refinement; } static int -- cgit v1.2.3