[前][次][番号順一覧][スレッド一覧]

ruby-changes:29209

From: shugo <ko1@a...>
Date: Wed, 12 Jun 2013 23:34:12 +0900 (JST)
Subject: [ruby-changes:29209] shugo:r41261 (trunk): * eval.c (mod_using): new method Module#using, which activates

shugo	2013-06-12 23:33:59 +0900 (Wed, 12 Jun 2013)

  New Revision: 41261

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41261

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

  Modified files:
    trunk/ChangeLog
    trunk/eval.c
    trunk/test/ruby/test_refinement.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 41260)
+++ ChangeLog	(revision 41261)
@@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Wed Jun 12 23:27:03 2013  Shugo Maeda  <shugo@r...>
+
+	* 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@r...>
 
 	* safe.c (rb_set_safe_level, safe_setter): raise an ArgumentError
Index: eval.c
===================================================================
--- eval.c	(revision 41260)
+++ eval.c	(revision 41261)
@@ -1226,6 +1226,34 @@ rb_mod_refine(VALUE module, VALUE klass) https://github.com/ruby/ruby/blob/trunk/eval.c#L1226
     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) https://github.com/ruby/ruby/blob/trunk/eval.c#L1382
 
     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) https://github.com/ruby/ruby/blob/trunk/eval.c#L1587
     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");
Index: test/ruby/test_refinement.rb
===================================================================
--- test/ruby/test_refinement.rb	(revision 41260)
+++ test/ruby/test_refinement.rb	(revision 41261)
@@ -429,14 +429,6 @@ class TestRefinement < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_refinement.rb#L429
     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::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_refinement.rb#L818
     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)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]