diff options
author | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-12-08 02:37:16 +0000 |
---|---|---|
committer | shugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-12-08 02:37:16 +0000 |
commit | db051011d68950cd1261f91e724513282d419d9e (patch) | |
tree | d27e726831d1555253d08477275055f7b5de0cf0 | |
parent | 3adc9834d18ee6ff67dfca060eee170025ce3fef (diff) | |
download | ruby-db051011d68950cd1261f91e724513282d419d9e.tar.gz |
* 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
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | eval.c | 69 | ||||
-rw-r--r-- | include/ruby/ruby.h | 2 | ||||
-rw-r--r-- | string.c | 45 | ||||
-rw-r--r-- | test/ruby/test_refinement.rb | 86 | ||||
-rw-r--r-- | vm_eval.c | 43 |
6 files changed, 159 insertions, 96 deletions
@@ -1,3 +1,13 @@ +Sat Dec 8 11:17:53 2012 Shugo Maeda <shugo@ruby-lang.org> + + * 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@segment7.net> * ext/openssl/ossl_x509name.c: Completed documentation for @@ -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 diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 56e78a18d4..f25c67aaef 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -1333,8 +1333,6 @@ VALUE rb_funcall(VALUE, ID, int, ...); 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*); @@ -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 @@ sym_to_sym(VALUE sym) } 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 @@ sym_to_proc(VALUE sym) 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; } } diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index a4ebfa4c4c..872ca1754a 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -463,33 +463,6 @@ class TestRefinement < Test::Unit::TestCase 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 @@ class TestRefinement < Test::Unit::TestCase 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) @@ -784,30 +784,6 @@ rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv) 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 @@ yield_under(VALUE under, VALUE self, VALUE values) } } +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) |