ruby-changes:26212
From: shugo <ko1@a...>
Date: Sat, 8 Dec 2012 11:37:28 +0900 (JST)
Subject: [ruby-changes:26212] shugo:r38269 (trunk): * eval.c (rb_mod_refine), vm_eval.c (rb_yield_refine_block):
shugo 2012-12-08 11:37:16 +0900 (Sat, 08 Dec 2012) New Revision: 38269 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38269 Log: * 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. Modified files: trunk/ChangeLog trunk/eval.c trunk/include/ruby/ruby.h trunk/string.c trunk/test/ruby/test_refinement.rb trunk/vm_eval.c Index: include/ruby/ruby.h =================================================================== --- include/ruby/ruby.h (revision 38268) +++ include/ruby/ruby.h (revision 38269) @@ -1333,8 +1333,6 @@ VALUE rb_funcall2(VALUE, ID, int, const VALUE*); VALUE rb_funcall3(VALUE, ID, int, const VALUE*); VALUE rb_funcall_passing_block(VALUE, ID, int, const VALUE*); -VALUE rb_funcall_passing_block_with_refinements(VALUE, ID, int, - const VALUE*, VALUE); int rb_scan_args(int, const VALUE*, const char*, ...); VALUE rb_call_super(int, const VALUE*); Index: ChangeLog =================================================================== --- ChangeLog (revision 38268) +++ ChangeLog (revision 38269) @@ -1,3 +1,13 @@ +Sat Dec 8 11:17:53 2012 Shugo Maeda <shugo@r...> + + * 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. + Sat Dec 8 09:24:42 2012 Eric Hodel <drbrain@s...> * ext/openssl/ossl_x509name.c: Completed documentation for Index: string.c =================================================================== --- string.c (revision 38268) +++ string.c (revision 38269) @@ -14,8 +14,7 @@ #include "ruby/ruby.h" #include "ruby/re.h" #include "ruby/encoding.h" -#include "node.h" -#include "eval_intern.h" +#include "vm_core.h" #include "internal.h" #include "probes.h" #include <assert.h> @@ -7862,18 +7861,15 @@ } static VALUE -sym_call(VALUE args, VALUE p, int argc, VALUE *argv) +sym_call(VALUE args, VALUE sym, int argc, VALUE *argv) { VALUE obj; - NODE *memo = RNODE(p); if (argc < 1) { rb_raise(rb_eArgError, "no receiver given"); } obj = argv[0]; - return rb_funcall_passing_block_with_refinements(obj, (ID) memo->u1.id, - argc - 1, argv + 1, - memo->u2.value); + return rb_funcall_passing_block(obj, (ID)sym, argc - 1, argv + 1); } /* @@ -7893,32 +7889,25 @@ VALUE proc; long id, index; VALUE *aryp; - const NODE *cref = rb_vm_cref(); + if (!sym_proc_cache) { + sym_proc_cache = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2); + rb_gc_register_mark_object(sym_proc_cache); + rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil); + } + id = SYM2ID(sym); - if (NIL_P(cref->nd_refinements)) { - if (!sym_proc_cache) { - sym_proc_cache = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2); - rb_gc_register_mark_object(sym_proc_cache); - rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil); - } + index = (id % SYM_PROC_CACHE_SIZE) << 1; - index = (id % SYM_PROC_CACHE_SIZE) << 1; - aryp = RARRAY_PTR(sym_proc_cache); - if (aryp[index] == sym) { - return aryp[index + 1]; - } - else { - proc = rb_proc_new(sym_call, - (VALUE) NEW_MEMO(id, Qnil, 0)); - aryp[index] = sym; - aryp[index + 1] = proc; - return proc; - } + aryp = RARRAY_PTR(sym_proc_cache); + if (aryp[index] == sym) { + return aryp[index + 1]; } else { - return rb_proc_new(sym_call, - (VALUE) NEW_MEMO(id, cref->nd_refinements, 0)); + proc = rb_proc_new(sym_call, (VALUE)id); + aryp[index] = sym; + aryp[index + 1] = proc; + return proc; } } Index: vm_eval.c =================================================================== --- vm_eval.c (revision 38268) +++ vm_eval.c (revision 38269) @@ -784,30 +784,6 @@ return rb_call(recv, mid, argc, argv, CALL_PUBLIC); } -VALUE -rb_funcall_passing_block_with_refinements(VALUE recv, ID mid, int argc, - const VALUE *argv, - VALUE refinements) -{ - VALUE defined_class; - rb_method_entry_t *me = - rb_search_method_entry(recv, mid, &defined_class); - rb_thread_t *th; - int call_status; - - if (me && me->def->type == VM_METHOD_TYPE_REFINED) { - me = rb_resolve_refined_method(refinements, me, &defined_class); - } - PASS_PASSED_BLOCK_TH(GET_THREAD()); - th = GET_THREAD(); - call_status = rb_method_call_status(th, me, CALL_PUBLIC, th->cfp->self); - if (call_status != NOEX_OK) { - return method_missing(recv, mid, argc, argv, call_status); - } - stack_check(); - return vm_call0(th, recv, mid, argc, argv, me, defined_class); -} - static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope) { @@ -1462,6 +1438,25 @@ } } +VALUE +rb_yield_refine_block(VALUE refinement, VALUE refinements) +{ + rb_thread_t *th = GET_THREAD(); + rb_block_t block, *blockptr; + NODE *cref; + + if ((blockptr = VM_CF_BLOCK_PTR(th->cfp)) != 0) { + block = *blockptr; + block.self = refinement; + VM_CF_LEP(th->cfp)[0] = VM_ENVVAL_BLOCK_PTR(&block); + } + cref = vm_cref_push(th, refinement, NOEX_PUBLIC, blockptr); + cref->flags |= NODE_FL_CREF_PUSHED_BY_EVAL; + cref->nd_refinements = refinements; + + return vm_yield_with_cref(th, 0, NULL, cref); +} + /* string eval under the class/module context */ static VALUE eval_under(VALUE under, VALUE self, VALUE src, const char *file, int line) Index: eval.c =================================================================== --- eval.c (revision 38268) +++ eval.c (revision 38269) @@ -1148,6 +1148,38 @@ 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 @@ 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 @@ 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 Index: test/ruby/test_refinement.rb =================================================================== --- test/ruby/test_refinement.rb (revision 38268) +++ test/ruby/test_refinement.rb (revision 38269) @@ -463,33 +463,6 @@ assert_equal("no block given", e.message) end - module SymbolToProc - class C - end - - module M - refine C do - def foo - "foo" - end - end - - def self.call_foo - c = C.new - :foo.to_proc.call(c) - end - - def self.foo_proc - :foo.to_proc - end - end - end - - def test_symbol_to_proc - assert_equal("foo", SymbolToProc::M.call_foo) - assert_equal("foo", SymbolToProc::M.foo_proc.call(SymbolToProc::C.new)) - end - module Inspect module M refine Fixnum do @@ -584,6 +557,65 @@ end end + module RefineScoping + refine String do + def foo + "foo" + end + + def RefineScoping.call_in_refine_block + "".foo + end + end + + def self.call_outside_refine_block + "".foo + end + end + + def test_refine_scoping + assert_equal("foo", RefineScoping.call_in_refine_block) + assert_raise(NoMethodError) do + RefineScoping.call_outside_refine_block + end + end + + module StringRecursiveLength + refine String do + def recursive_length + if empty? + 0 + else + self[1..-1].recursive_length + 1 + end + end + end + end + + def test_refine_recursion + x = eval_using(StringRecursiveLength, "'foo'.recursive_length") + assert_equal(3, x) + end + + module ToJSON + refine Integer do + def to_json; to_s; end + end + + refine Array do + def to_json; "[" + map { |i| i.to_json }.join(",") + "]" end + end + + refine Hash do + def to_json; "{" + map { |k, v| k.to_s.dump + ":" + v.to_json }.join(",") + "}" end + end + end + + def test_refine_mutual_recursion + x = eval_using(ToJSON, "[{1=>2}, {3=>4}].to_json") + assert_equal('[{"1":2},{"3":4}]', x) + end + private def eval_using(mod, s) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/