Skip to content

Commit

Permalink
* eval.c (mod_using): new method Module#using, which activates
Browse files Browse the repository at this point in the history
  refinements of the specified module only in the current class or
  module definition.  [ruby-core:55273] [Feature ruby#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
  • Loading branch information
shugo committed Jun 12, 2013
1 parent 1f82849 commit 17f1cda
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 9 deletions.
8 changes: 8 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
Wed Jun 12 23:27:03 2013 Shugo Maeda <[email protected]>

* 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 <[email protected]>

* safe.c (rb_set_safe_level, safe_setter): raise an ArgumentError
Expand Down
32 changes: 31 additions & 1 deletion eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");
Expand Down
65 changes: 57 additions & 8 deletions test/ruby/test_refinement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -429,14 +429,6 @@ def test_no_kernel_using
end
end

def test_no_module_using
assert_raise(NoMethodError) do
Module.new {
using Module.new
}
end
end

class UsingClass
end

Expand Down Expand Up @@ -826,6 +818,63 @@ def test_super_in_block
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)
Expand Down

0 comments on commit 17f1cda

Please sign in to comment.