summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--eval.c88
-rw-r--r--insns.def1
-rw-r--r--test/ruby/test_refinement.rb422
-rw-r--r--vm_eval.c2
-rw-r--r--vm_insnhelper.c68
6 files changed, 96 insertions, 502 deletions
diff --git a/ChangeLog b/ChangeLog
index feb44c4a2d..a6816d0f68 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+Sat Dec 8 00:10:34 2012 Shugo Maeda <shugo@ruby-lang.org>
+
+ * vm_eval.c (yield_under, eval_under): do not activate refinements
+ of the receiver in module_eval and instance_eval.
+
+ * eval.c (ruby_Init_refinement): undef Class#refine.
+
+ * eval.c (ruby_Init_refinement): remove Module#using.
+
+ * eval.c (ruby_Init_refinement): main.using should be private.
+
+ * eval.c (rb_mod_refine): the argument of Module#refine should not
+ be a module.
+
+ * insns.def (defineclass): do not activate refinements in a class or
+ module.
+
Fri Dec 7 23:42:11 2012 Shugo Maeda <shugo@ruby-lang.org>
* ext/refinement/refinement.c: include ruby/ruby.h instead of the
diff --git a/eval.c b/eval.c
index ed84059374..20d59541e8 100644
--- a/eval.c
+++ b/eval.c
@@ -1039,16 +1039,6 @@ rb_mod_prepend(int argc, VALUE *argv, VALUE module)
return module;
}
-static
-void check_class_or_module(VALUE obj)
-{
- if (!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE)) {
- VALUE str = rb_inspect(obj);
- rb_raise(rb_eTypeError, "%s is not a class/module",
- StringValuePtr(str));
- }
-}
-
static VALUE
hidden_identity_hash_new()
{
@@ -1064,7 +1054,7 @@ rb_using_refinement(NODE *cref, VALUE klass, VALUE module)
{
VALUE iclass, c, superclass = klass;
- check_class_or_module(klass);
+ Check_Type(klass, T_CLASS);
Check_Type(module, T_MODULE);
if (NIL_P(cref->nd_refinements)) {
cref->nd_refinements = hidden_identity_hash_new();
@@ -1098,17 +1088,6 @@ rb_using_refinement(NODE *cref, VALUE klass, VALUE module)
rb_hash_aset(cref->nd_refinements, klass, iclass);
}
-void rb_using_module(NODE *cref, VALUE module);
-
-static int
-using_module_i(VALUE module, VALUE val, VALUE arg)
-{
- NODE *cref = (NODE *) arg;
-
- rb_using_module(cref, module);
- return ST_CONTINUE;
-}
-
static int
using_refinement(VALUE klass, VALUE module, VALUE arg)
{
@@ -1123,70 +1102,14 @@ rb_using_module(NODE *cref, VALUE module)
{
ID id_refinements;
VALUE refinements;
- ID id_using_modules;
- VALUE using_modules;
- check_class_or_module(module);
- CONST_ID(id_using_modules, "__using_modules__");
- using_modules = rb_attr_get(module, id_using_modules);
- if (!NIL_P(using_modules)) {
- rb_hash_foreach(using_modules, using_module_i, (VALUE) cref);
- }
+ Check_Type(module, T_MODULE);
CONST_ID(id_refinements, "__refinements__");
refinements = rb_attr_get(module, id_refinements);
if (NIL_P(refinements)) return;
rb_hash_foreach(refinements, using_refinement, (VALUE) cref);
}
-
-static int
-check_cyclic_using(VALUE mod, VALUE _, VALUE search)
-{
- VALUE using_modules;
- ID id_using_modules;
- CONST_ID(id_using_modules, "__using_modules__");
-
- if (mod == search) {
- rb_raise(rb_eArgError, "cyclic using detected");
- }
-
- using_modules = rb_attr_get(mod, id_using_modules);
- if (!NIL_P(using_modules)) {
- rb_hash_foreach(using_modules, check_cyclic_using, search);
- }
-
- return ST_CONTINUE;
-}
-
-/*
- * call-seq:
- * using(module) -> self
- *
- * Import class refinements from <i>module</i> into the receiver.
- */
-
-static VALUE
-rb_mod_using(VALUE self, VALUE module)
-{
- NODE *cref = rb_vm_cref();
- ID id_using_modules;
- VALUE using_modules;
-
- Check_Type(module, T_MODULE);
- check_cyclic_using(module, 0, self);
- CONST_ID(id_using_modules, "__using_modules__");
- using_modules = rb_attr_get(self, id_using_modules);
- if (NIL_P(using_modules)) {
- using_modules = hidden_identity_hash_new();
- rb_ivar_set(self, id_using_modules, using_modules);
- }
- rb_hash_aset(using_modules, module, Qtrue);
- rb_using_module(cref, module);
- rb_clear_cache();
- rb_funcall(module, rb_intern("used"), 1, self);
- return self;
-}
-
VALUE rb_refinement_module_get_refined_class(VALUE module)
{
ID id_refined_class;
@@ -1245,7 +1168,7 @@ rb_mod_refine(VALUE module, VALUE klass)
if (!rb_block_given_p()) {
rb_raise(rb_eArgError, "no block given");
}
- check_class_or_module(klass);
+ Check_Type(klass, T_CLASS);
CONST_ID(id_refinements, "__refinements__");
refinements = rb_attr_get(module, id_refinements);
if (NIL_P(refinements)) {
@@ -1645,10 +1568,11 @@ Init_eval(void)
void
ruby_Init_refinement(void)
{
- rb_define_private_method(rb_cModule, "using", rb_mod_using, 1);
rb_define_private_method(rb_cModule, "refine", rb_mod_refine, 1);
+ rb_undef_method(rb_cClass, "refine");
rb_define_method(rb_cModule, "refinements", rb_mod_refinements, 0);
- rb_define_singleton_method(rb_vm_top_self(), "using", top_using, 1);
+ rb_define_private_method(rb_singleton_class(rb_vm_top_self()),
+ "using", top_using, 1);
}
#if defined __GNUC__ && __GNUC__ >= 4
diff --git a/insns.def b/insns.def
index ea099060c7..8a0f91f6c1 100644
--- a/insns.def
+++ b/insns.def
@@ -967,7 +967,6 @@ defineclass
klass, 0, VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()),
class_iseq->iseq_encoded, GET_SP(),
class_iseq->local_size, 0);
- rb_vm_using_modules(class_iseq->cref_stack, klass);
RESTORE_REGS();
INC_VM_STATE_VERSION();
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index 3abfe663e5..a4ebfa4c4c 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -175,7 +175,8 @@ class TestRefinement < Test::Unit::TestCase
def test_module_eval
foo = Foo.new
assert_equal("Foo#x", foo.x)
- assert_equal("FooExt#x", FooExt.module_eval { foo.x })
+ assert_equal("Foo#x", FooExt.module_eval { foo.x })
+ assert_equal("Foo#x", FooExt.module_eval("foo.x"))
assert_equal("Foo#x", foo.x)
end
@@ -242,14 +243,15 @@ class TestRefinement < Test::Unit::TestCase
assert_not_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT3)
end
+ module FixnumFooExt
+ refine Fixnum do
+ def foo; "foo"; end
+ end
+ end
+
def test_respond_to?
- m = Module.new {
- refine Fixnum do
- def foo; "foo"; end
- end
- }
assert_equal(false, 1.respond_to?(:foo))
- assert_equal(true, m.module_eval { 1.respond_to?(:foo) })
+ assert_equal(true, eval_using(FixnumFooExt, "1.respond_to?(:foo)"))
assert_equal(false, 1.respond_to?(:foo))
end
@@ -274,183 +276,47 @@ class TestRefinement < Test::Unit::TestCase
assert_equal(1, eval_using(ArrayEachExt, "[1, 2, 3].min"))
end
- def test_module_inclusion
- m1 = Module.new {
- def foo
- "m1#foo"
- end
-
- def bar
- "m1#bar"
- end
- }
- m2 = Module.new {
- def bar
- "m2#bar"
- end
-
- def baz
- "m2#baz"
- end
- }
- m3 = Module.new {
- def baz
- "m3#baz"
- end
- }
- include_proc = Proc.new {
- include m3, m2
- }
- m = Module.new {
- refine String do
- include m1
- module_eval(&include_proc)
-
- def call_foo
- foo
- end
-
- def call_bar
- bar
- end
-
- def call_baz
- baz
- end
- end
-
- def self.call_foo(s)
- s.foo
- end
-
- def self.call_bar(s)
- s.bar
- end
-
- def self.call_baz(s)
- s.baz
- end
- }
- assert_equal("m1#foo", m.module_eval { "abc".foo })
- assert_equal("m2#bar", m.module_eval { "abc".bar })
- assert_equal("m3#baz", m.module_eval { "abc".baz })
- assert_equal("m1#foo", m.module_eval { "abc".call_foo })
- assert_equal("m2#bar", m.module_eval { "abc".call_bar })
- assert_equal("m3#baz", m.module_eval { "abc".call_baz })
- assert_equal("m1#foo", m.call_foo("abc"))
- assert_equal("m2#bar", m.call_bar("abc"))
- assert_equal("m3#baz", m.call_baz("abc"))
- end
-
- def test_refine_prepended_class
- m1 = Module.new {
+ module RefinePrependedClass
+ module M1
def foo
super << :m1
end
- }
- c = Class.new {
- prepend m1
+ end
+
+ class C
+ prepend M1
def foo
[:c]
end
- }
- m2 = Module.new {
- refine c do
- def foo
- super << :m2
- end
- end
- }
- obj = c.new
- assert_equal([:c, :m1, :m2], m2.module_eval { obj.foo })
- end
+ end
- def test_refine_module_without_overriding
- m1 = Module.new
- c = Class.new {
- include m1
- }
- m2 = Module.new {
- refine m1 do
+ module M2
+ refine C do
def foo
- :m2
+ super << :m2
end
end
- }
- obj = c.new
- assert_equal(:m2, m2.module_eval { obj.foo })
+ end
end
- def test_refine_module_with_overriding
- m1 = Module.new {
- def foo
- super << :m1
- end
- }
- c0 = Class.new {
- def foo
- [:c0]
- end
- }
- c = Class.new(c0) {
- include m1
- }
- m2 = Module.new {
- refine m1 do
- def foo
- super << :m2
- end
- end
- }
- obj = c.new
- assert_equal([:c0, :m1, :m2], m2.module_eval { obj.foo })
+ def test_refine_prepended_class
+ x = eval_using(RefinePrependedClass::M2,
+ "TestRefinement::RefinePrependedClass::C.new.foo")
+ assert_equal([:c, :m1, :m2], x)
end
- def test_refine_module_with_double_overriding
- m1 = Module.new {
- def foo
- [:m1]
- end
- }
- c = Class.new {
- include m1
- }
- m2 = Module.new {
- refine m1 do
+ def test_refine_module
+ m1 = Module.new
+ assert_raise(TypeError) do
+ Module.new {
+ refine m1 do
def foo
- super << :m2
+ :m2
end
- end
- }
- m3 = Module.new {
- using m2
- refine m1 do
- def foo
- super << :m3
end
- end
- }
- obj = c.new
- assert_equal([:m1, :m2, :m3], m3.module_eval { obj.foo })
- end
-
- def test_refine_module_and_call_superclass_method
- m1 = Module.new
- c1 = Class.new {
- def foo
- "c1#foo"
- end
- }
- c2 = Class.new(c1) {
- include m1
- }
- m2 = Module.new {
- refine m1 do
- end
- }
- obj = c2.new
- assert_equal("c1#foo", m2.module_eval { obj.foo })
+ }
+ end
end
def test_refine_neither_class_nor_module
@@ -474,15 +340,16 @@ class TestRefinement < Test::Unit::TestCase
end
end
- def test_refine_in_class_and_class_eval
- c = Class.new {
- refine Fixnum do
- def foo
- "c"
+ def test_refine_in_class
+ assert_raise(NoMethodError) do
+ Class.new {
+ refine Fixnum do
+ def foo
+ "c"
+ end
end
- end
- }
- assert_equal("c", c.class_eval { 123.foo })
+ }
+ end
end
def test_main_using
@@ -510,19 +377,33 @@ class TestRefinement < Test::Unit::TestCase
INPUT
end
+ def test_main_using_is_private
+ assert_raise(NoMethodError) do
+ eval("self.using Module.new", TOPLEVEL_BINDING)
+ end
+ end
+
def test_no_kernel_using
assert_raise(NoMethodError) do
using Module.new
end
end
+ def test_no_module_using
+ assert_raise(NoMethodError) do
+ Module.new {
+ using Module.new
+ }
+ end
+ end
+
+ class UsingClass
+ end
+
def test_module_using_class
c = Class.new
- m = Module.new
assert_raise(TypeError) do
- m.module_eval do
- using c
- end
+ eval("using TestRefinement::UsingClass", TOPLEVEL_BINDING)
end
end
@@ -572,25 +453,6 @@ class TestRefinement < Test::Unit::TestCase
assert_equal({c => c_ext}, m.refinements)
end
- def test_refinements_no_recursion
- c1 = Class.new
- c1_ext = nil
- m1 = Module.new {
- refine c1 do
- c1_ext = self
- end
- }
- c2 = Class.new
- c2_ext = nil
- m2 = Module.new {
- using m1
- refine c2 do
- c2_ext = self
- end
- }
- assert_equal({c2 => c2_ext}, m2.refinements)
- end
-
def test_refine_without_block
c1 = Class.new
e = assert_raise(ArgumentError) {
@@ -601,76 +463,6 @@ class TestRefinement < Test::Unit::TestCase
assert_equal("no block given", e.message)
end
- module IndirectUsing
- class C
- end
-
- module M1
- refine C do
- def m1
- :m1
- end
- end
- end
-
- module M2
- refine C do
- def m2
- :m2
- end
- end
- end
-
- module M3
- using M1
- using M2
- end
-
- module M
- using M3
-
- def self.call_m1
- C.new.m1
- end
-
- def self.call_m2
- C.new.m2
- end
- end
- end
-
- def test_indirect_using
- assert_equal(:m1, IndirectUsing::M.call_m1)
- assert_equal(:m2, IndirectUsing::M.call_m2)
- end
-
- def test_indirect_using_module_eval
- c = Class.new
- m1 = Module.new {
- refine c do
- def m1
- :m1
- end
- end
- }
- m2 = Module.new {
- refine c do
- def m2
- :m2
- end
- end
- }
- m3 = Module.new {
- using m1
- using m2
- }
- m = Module.new {
- using m3
- }
- assert_equal(:m1, m.module_eval { c.new.m1 })
- assert_equal(:m2, m.module_eval { c.new.m2 })
- end
-
module SymbolToProc
class C
end
@@ -722,67 +514,7 @@ class TestRefinement < Test::Unit::TestCase
m.refinements[c].inspect)
end
- module InlineMethodCache
- class C
- def foo
- "original"
- end
- end
-
- module M
- refine C do
- def foo
- "refined"
- end
- end
- end
- end
-
- def test_inline_method_cache
- c = InlineMethodCache::C.new
- f = Proc.new { c.foo }
- assert_equal("original", f.call)
- assert_equal("refined", InlineMethodCache::M.module_eval(&f))
- assert_equal("original", f.call)
- end
-
- module UsingMethodCache
- class C
- def foo
- "original"
- end
- end
-
- module M1
- refine C do
- def foo
- "M1"
- end
- end
- end
-
- module M2
- refine C do
- def foo
- "M2"
- end
- end
- end
-
- module M
- c = C.new
- ORIGINAL_FOO = c.foo
- using M1
- c.foo
- using M2
- M2_FOO = c.foo
- end
- end
-
def test_using_method_cache
- assert_equal("original", UsingMethodCache::M::ORIGINAL_FOO)
- assert_equal("M2", UsingMethodCache::M::M2_FOO)
-
assert_in_out_err([], <<-INPUT, %w(:M1 :M2), /Refinements are experimental/)
require "refinement"
@@ -816,28 +548,7 @@ class TestRefinement < Test::Unit::TestCase
INPUT
end
- def test_circular_using_is_not_allowed
- a = Module.new
- b = Module.new
-
- assert_raise ArgumentError do
- a.module_eval do
- using a
- end
- end
-
- b.module_eval do
- using a
- end
-
- assert_raise ArgumentError do
- a.module_eval do
- using b
- end
- end
- end
-
- module RedifineRefinedMethod
+ module RedefineRefinedMethod
class C
def foo
"original"
@@ -860,8 +571,17 @@ class TestRefinement < Test::Unit::TestCase
end
def test_redefine_refined_method
- c = RedifineRefinedMethod::C.new
- assert_equal("refined", RedifineRefinedMethod::M.module_eval { c.foo })
+ x = eval_using(RedefineRefinedMethod::M,
+ "TestRefinement::RedefineRefinedMethod::C.new.foo")
+ assert_equal("refined", x)
+ end
+
+ module StringExt
+ refine String do
+ def foo
+ "foo"
+ end
+ end
end
private
diff --git a/vm_eval.c b/vm_eval.c
index ea2455c691..66ff25d36b 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1453,7 +1453,6 @@ yield_under(VALUE under, VALUE self, VALUE values)
}
cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
cref->flags |= NODE_FL_CREF_PUSHED_BY_EVAL;
- rb_vm_using_modules(cref, under);
if (values == Qundef) {
return vm_yield_with_cref(th, 1, &self, cref);
@@ -1478,7 +1477,6 @@ eval_under(VALUE under, VALUE self, VALUE src, const char *file, int line)
else {
SafeStringValue(src);
}
- rb_vm_using_modules(cref, under);
return eval_string_with_cref(self, src, Qnil, cref, file, line);
}
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 7d57b792b9..8c687bfbb7 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -920,41 +920,6 @@ opt_eq_func(VALUE recv, VALUE obj, CALL_INFO ci)
return Qundef;
}
-void rb_using_module(NODE *cref, VALUE module);
-
-static int
-vm_using_module_i(VALUE module, VALUE value, VALUE arg)
-{
- NODE *cref = (NODE *) arg;
-
- rb_using_module(cref, module);
- return ST_CONTINUE;
-}
-
-static void
-rb_vm_using_modules(NODE *cref, VALUE klass)
-{
- ID id_using_modules;
- VALUE using_modules;
-
- if (NIL_P(klass)) return;
- CONST_ID(id_using_modules, "__using_modules__");
- using_modules = rb_attr_get(klass, id_using_modules);
- if (NIL_P(using_modules) && BUILTIN_TYPE(klass) == T_CLASS) {
- VALUE super = rb_class_real(RCLASS_SUPER(klass));
- using_modules = rb_attr_get(super, id_using_modules);
- if (!NIL_P(using_modules)) {
- using_modules = rb_hash_dup(using_modules);
- rb_ivar_set(klass, id_using_modules, using_modules);
- }
- }
- if (!NIL_P(using_modules)) {
- rb_hash_foreach(using_modules, vm_using_module_i,
- (VALUE) cref);
- }
- rb_using_module(cref, klass);
-}
-
static VALUE
check_match(VALUE pattern, VALUE target, enum vm_check_match_type type)
{
@@ -1694,42 +1659,13 @@ vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
return vm_call_method(th, reg_cfp, &ci_entry);
}
-static VALUE
-copy_refinement_iclass(VALUE iclass, VALUE superclass)
-{
- VALUE result, c;
-
- Check_Type(iclass, T_ICLASS);
- c = result = rb_include_class_new(RBASIC(iclass)->klass, superclass);
- RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
- iclass = RCLASS_SUPER(iclass);
- while (iclass && BUILTIN_TYPE(iclass) == T_ICLASS) {
- c = RCLASS_SUPER(c) = rb_include_class_new(RBASIC(iclass)->klass,
- RCLASS_SUPER(c));
- RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
- iclass = RCLASS_SUPER(iclass);
- }
- return result;
-}
-
-static VALUE
+static inline VALUE
find_refinement(VALUE refinements, VALUE klass)
{
- VALUE refinement;
-
if (NIL_P(refinements)) {
return Qnil;
}
- refinement = rb_hash_lookup(refinements, klass);
- if (NIL_P(refinement) &&
- BUILTIN_TYPE(klass) == T_ICLASS) {
- refinement = rb_hash_lookup(refinements,
- RBASIC(klass)->klass);
- if (!NIL_P(refinement)) {
- refinement = copy_refinement_iclass(refinement, klass);
- }
- }
- return refinement;
+ return rb_hash_lookup(refinements, klass);
}
static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);