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

* eval.c (mod_using): new method Module#using, which activates

refinements of the specified module only in the current class or
  module definition.  [ruby-core:55273] [Feature #8481]

* test/ruby/test_refinement.rb: related test.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41261 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shugo 2013-06-12 14:33:59 +00:00
parent 1f828497d1
commit 17f1cdaa00
3 changed files with 96 additions and 9 deletions

View file

@ -1,3 +1,11 @@
Wed Jun 12 23:27:03 2013 Shugo Maeda <shugo@ruby-lang.org>
* eval.c (mod_using): new method Module#using, which activates
refinements of the specified module only in the current class or
module definition. [ruby-core:55273] [Feature #8481]
* test/ruby/test_refinement.rb: related test.
Wed Jun 12 22:58:48 2013 Shugo Maeda <shugo@ruby-lang.org>
* safe.c (rb_set_safe_level, safe_setter): raise an ArgumentError

32
eval.c
View file

@ -1226,6 +1226,34 @@ rb_mod_refine(VALUE module, VALUE klass)
return refinement;
}
/*
* call-seq:
* using(module) -> self
*
* Import class refinements from <i>module</i> into the current class or
* module definition.
*/
static VALUE
mod_using(VALUE self, VALUE module)
{
NODE *cref = rb_vm_cref();
rb_control_frame_t *prev_cfp = previous_frame(GET_THREAD());
warn_refinements_once();
if (prev_frame_func()) {
rb_raise(rb_eRuntimeError,
"Module#using is not permitted in methods");
}
if (prev_cfp && prev_cfp->self != self) {
rb_raise(rb_eRuntimeError, "Module#using is not called on self");
}
Check_Type(module, T_MODULE);
rb_using_module(cref, module);
rb_clear_cache();
return self;
}
void
rb_obj_call_init(VALUE obj, int argc, VALUE *argv)
{
@ -1354,7 +1382,8 @@ top_using(VALUE self, VALUE module)
warn_refinements_once();
if (cref->nd_next || (prev_cfp && prev_cfp->me)) {
rb_raise(rb_eRuntimeError, "using is permitted only at toplevel");
rb_raise(rb_eRuntimeError,
"main.using is permitted only at toplevel");
}
Check_Type(module, T_MODULE);
rb_using_module(cref, module);
@ -1558,6 +1587,7 @@ Init_eval(void)
rb_define_private_method(rb_cModule, "prepend_features", rb_mod_prepend_features, 1);
rb_define_private_method(rb_cModule, "prepend", rb_mod_prepend, -1);
rb_define_private_method(rb_cModule, "refine", rb_mod_refine, 1);
rb_define_private_method(rb_cModule, "using", mod_using, 1);
rb_undef_method(rb_cClass, "refine");
rb_undef_method(rb_cClass, "module_function");

View file

@ -429,14 +429,6 @@ class TestRefinement < Test::Unit::TestCase
end
end
def test_no_module_using
assert_raise(NoMethodError) do
Module.new {
using Module.new
}
end
end
class UsingClass
end
@ -826,6 +818,63 @@ class TestRefinement < Test::Unit::TestCase
assert_equal([:foo, :ref, bug7925], x, bug7925)
end
module ModuleUsing
using FooExt
def self.invoke_x_on(foo)
return foo.x
end
def self.invoke_y_on(foo)
return foo.y
end
def self.invoke_z_on(foo)
return foo.z
end
def self.send_z_on(foo)
return foo.send(:z)
end
def self.method_z(foo)
return foo.method(:z)
end
def self.invoke_call_x_on(foo)
return foo.call_x
end
end
def test_module_using
foo = Foo.new
assert_equal("Foo#x", foo.x)
assert_equal("Foo#y", foo.y)
assert_raise(NoMethodError) { foo.z }
assert_equal("FooExt#x", ModuleUsing.invoke_x_on(foo))
assert_equal("FooExt#y Foo#y", ModuleUsing.invoke_y_on(foo))
assert_equal("FooExt#z", ModuleUsing.invoke_z_on(foo))
assert_equal("Foo#x", foo.x)
assert_equal("Foo#y", foo.y)
assert_raise(NoMethodError) { foo.z }
end
def test_module_using_in_method
assert_raise(RuntimeError) do
Module.new.send(:using, FooExt)
end
end
def test_module_using_invalid_self
assert_raise(RuntimeError) do
eval <<-EOF, TOPLEVEL_BINDING
module TestRefinement::TestModuleUsingInvalidSelf
Module.new.send(:using, TestRefinement::FooExt)
end
EOF
end
end
private
def eval_using(mod, s)