1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38262 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shugo 2012-12-07 15:49:21 +00:00
parent c36d15f206
commit 537297d1cb
6 changed files with 96 additions and 502 deletions

View file

@ -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

88
eval.c
View file

@ -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

View file

@ -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();

View file

@ -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
end
module M2
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
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
m1 = Module.new
c = Class.new {
include m1
}
m2 = Module.new {
refine m1 do
assert_raise(TypeError) do
Module.new {
refine m1 do
def foo
:m2
end
end
}
obj = c.new
assert_equal(:m2, m2.module_eval { obj.foo })
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 })
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 foo
super << :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

View file

@ -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);
}

View file

@ -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);