[#33640] [Ruby 1.9-Bug#4136][Open] Enumerable#reject should not inherit the receiver's instance variables — Hiro Asari <redmine@...>

Bug #4136: Enumerable#reject should not inherit the receiver's instance variables

10 messages 2010/12/08

[#33667] [Ruby 1.9-Bug#4149][Open] Documentation submission: syslog standard library — mathew murphy <redmine@...>

Bug #4149: Documentation submission: syslog standard library

11 messages 2010/12/10

[#33683] [feature:trunk] Enumerable#categorize — Tanaka Akira <akr@...>

Hi.

14 messages 2010/12/12
[#33684] Re: [feature:trunk] Enumerable#categorize — "Martin J. Dst" <duerst@...> 2010/12/12

[#33687] Towards a standardized AST for Ruby code — Magnus Holm <judofyr@...>

Hey folks,

23 messages 2010/12/12
[#33688] Re: Towards a standardized AST for Ruby code — Charles Oliver Nutter <headius@...> 2010/12/12

On Sun, Dec 12, 2010 at 9:55 AM, Magnus Holm <judofyr@gmail.com> wrote:

[#33689] Re: Towards a standardized AST for Ruby code — "Haase, Konstantin" <Konstantin.Haase@...> 2010/12/12

On Dec 12, 2010, at 17:46 , Charles Oliver Nutter wrote:

[#33763] [Ruby 1.9-Bug#4168][Open] WeakRef is unsafe to use in Ruby 1.9 — Brian Durand <redmine@...>

Bug #4168: WeakRef is unsafe to use in Ruby 1.9

43 messages 2010/12/17

[#33815] trunk warnflags build issue with curb 0.7.9? — Jon <jon.forums@...>

As this may turn out to be a 3rd party issue rather than a bug, I'd like some feedback.

11 messages 2010/12/22

[#33833] Ruby 1.9.2 is going to be released — "Yuki Sonoda (Yugui)" <yugui@...>

-----BEGIN PGP SIGNED MESSAGE-----

15 messages 2010/12/23

[#33846] [Ruby 1.9-Feature#4197][Open] Improvement of the benchmark library — Benoit Daloze <redmine@...>

Feature #4197: Improvement of the benchmark library

15 messages 2010/12/23

[#33910] [Ruby 1.9-Feature#4211][Open] Converting the Ruby and C API documentation to YARD syntax — Loren Segal <redmine@...>

Feature #4211: Converting the Ruby and C API documentation to YARD syntax

10 messages 2010/12/26

[#33923] [Ruby 1.9-Bug#4214][Open] Fiddle::WINDOWS == false on Windows — Jon Forums <redmine@...>

Bug #4214: Fiddle::WINDOWS == false on Windows

15 messages 2010/12/27

[ruby-core:33567] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods

From: Shugo Maeda <shugo@...>
Date: 2010-12-04 12:32:47 UTC
List: ruby-core #33567
Hi,

2010/12/3 Yusuke ENDOH <mame@tsg.ne.jp>:
>>> ... Oops! his does not work as excepted.  had believed that this
>>> would work... hy don't you allow this?
>>
>> Currently refine doesn't work without blocks, but do you mean that?
>
> Ah sorry.
>
> odule FooExt
> efine(Fixnum) do
> ef /(other); quo(other); end
> nd
> nd
> odule BarExt
> nclude FooExt # or using FooExt
> nd
> sing BarExt
>  1 / 2 #=> actual: 0, expected: (1/2)

I forgot to support it.  Please apply the attached patch.  I have also
added Kernel#refine.

>> I think it's hard to add new keywords by a gem. ave you abandoned
>> keywords?  prefer to the keyword refine to the method refine without
>> blocks suggested by you.
>
> I first said in [ruby-core:33375]:
>
>> However, we should discuss this topic (new keyword) towards
>> 2.0. odule's methods are not bad, as a part of reflection
>> features (such as Module#define_method for `def' keyword).
>
> Needless to say, we must not add any new keywords to 1.9.x, especially
> normal simple word like "refine." 'm ok to include this feature in
> 1.9.x, and now I believe that gem is a good idea as the first step.
>
> However, I received many negative comments to this approach (gem),
> from nars*, kosak*, ko*, nakad*, shyouhe*. hey seem to think that
> it is better to import your patch "as is".

I also wouldn't like to see such a language core feature in a gem.

>> Isn't it enough to introduce refinements as an experimental feature,
>> at least in trunk?
>
> I don't like to include a feature called "experimental", not because
> it is not complete yet, but because it becomes "de facto standard."
> It would be good if there are not only "document" but also "mechanism"
> to inform users that the feature is experimental, such as warning or
> a new method like "RubyVM.enable_experimental_features".

As far as I know, the current status of trunk is unstable, and if new
features break backward compatibility, Yugui will create the branch
ruby_1_9, won't you, Yugui?  So, we don't need the above mechanism
until new experimental features are decided to include to 1.9.x.

> Note that this is just my opinion, and that I seem to be in the
> minority ;-)
> I hope that 1.9.x would be stable, but many other committers seem to
> hope to include new feature in 1.9.x aggressively.

I also hope that 1.9.x would be stable, but I'd like to develop
aggressively in trunk.  I don't think the current design and
implementation of refinements are mature, but I can't make them mature
on my own, so I'd like to have help from other committers.

-- 
Shugo Maeda

Attachments (1)

diff --git a/eval.c b/eval.c
index 6d5af7b..bcef1d9 100644
--- a/eval.c
+++ b/eval.c
@@ -898,8 +898,19 @@ rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
     rb_clear_cache_by_class(klass);
 }
 
+void rb_using_module(NODE *cref, VALUE module);
+
+static int
+using_module_i(VALUE module, VALUE value, VALUE arg)
+{
+    NODE *cref = (NODE *) arg;
+
+    rb_using_module(cref, module);
+    return ST_CONTINUE;
+}
+
 static int
-using_module_i(VALUE klass, VALUE module, VALUE arg)
+overlay_module_i(VALUE klass, VALUE module, VALUE arg)
 {
     NODE *cref = (NODE *) arg;
     int i;
@@ -911,14 +922,18 @@ using_module_i(VALUE klass, VALUE module, VALUE arg)
 void
 rb_using_module(NODE *cref, VALUE module)
 {
-    ID id_overlayed_modules;
-    VALUE overlayed_modules;
+    ID id_overlayed_modules, id_using_modules;
+    VALUE overlayed_modules, using_modules;
 
-    Check_Type(module, T_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);
+    }
     CONST_ID(id_overlayed_modules, "__overlayed_modules__");
     overlayed_modules = rb_attr_get(module, id_overlayed_modules);
     if (NIL_P(overlayed_modules)) return;
-    rb_hash_foreach(overlayed_modules, using_module_i, (VALUE) cref);
+    rb_hash_foreach(overlayed_modules, overlay_module_i, (VALUE) cref);
 }
 
 /*
@@ -935,6 +950,7 @@ rb_mod_using(VALUE self, VALUE module)
     ID id_using_modules;
     VALUE using_modules;
 
+    Check_Type(module, T_MODULE);
     CONST_ID(id_using_modules, "__using_modules__");
     using_modules = rb_attr_get(self, id_using_modules);
     if (NIL_P(using_modules)) {
@@ -994,6 +1010,21 @@ refinement_module_include(int argc, VALUE *argv, VALUE module)
     return result;
 }
 
+static VALUE
+refinement_module_new(VALUE klass)
+{
+    ID id_refined_class;
+    VALUE mod = rb_module_new();
+
+    CONST_ID(id_refined_class, "__refined_class__");
+    rb_ivar_set(mod, id_refined_class, klass);
+    rb_define_singleton_method(mod, "method_added",
+			       refinement_module_method_added, 1);
+    rb_define_singleton_method(mod, "include",
+			       refinement_module_include, -1);
+    return mod;
+}
+
 /*
  *  call-seq:
  *     refine(klass) { block }   -> self
@@ -1006,7 +1037,7 @@ rb_mod_refine(VALUE module, VALUE klass)
 {
     NODE *cref = rb_vm_cref();
     VALUE mod;
-    ID id_overlayed_modules, id_refined_class;
+    ID id_overlayed_modules;
     VALUE overlayed_modules, modules;
 
     Check_Type(klass, T_CLASS);
@@ -1019,13 +1050,7 @@ rb_mod_refine(VALUE module, VALUE klass)
     }
     mod = rb_hash_aref(overlayed_modules, klass);
     if (NIL_P(mod)) {
-	mod = rb_module_new();
-	CONST_ID(id_refined_class, "__refined_class__");
-	rb_ivar_set(mod, id_refined_class, klass);
-	rb_define_singleton_method(mod, "method_added",
-				   refinement_module_method_added, 1);
-	rb_define_singleton_method(mod, "include",
-				   refinement_module_include, -1);
+	mod = refinement_module_new(klass);
 	rb_overlay_module(cref, klass, mod);
 	rb_hash_aset(overlayed_modules, klass, mod);
     }
@@ -1033,6 +1058,26 @@ rb_mod_refine(VALUE module, VALUE klass)
     return mod;
 }
 
+/*
+ *  call-seq:
+ *     refine(klass) { block }   -> self
+ *
+ *  Refine <i>klass</i> in the scope where the method is called.
+ */
+
+static VALUE
+f_refine(VALUE self, VALUE klass)
+{
+    NODE *cref = rb_vm_cref();
+    VALUE mod;
+
+    Check_Type(klass, T_CLASS);
+    mod = refinement_module_new(klass);
+    rb_overlay_module(cref, klass, mod);
+    rb_mod_module_eval(0, NULL, mod);
+    return mod;
+}
+
 void
 rb_obj_call_init(VALUE obj, int argc, VALUE *argv)
 {
@@ -1157,6 +1202,7 @@ f_using(VALUE self, VALUE module)
 {
     NODE *cref = rb_vm_cref();
 
+    Check_Type(module, T_MODULE);
     rb_using_module(cref, module);
     return self;
 }
@@ -1331,6 +1377,7 @@ Init_eval(void)
     rb_define_singleton_method(rb_vm_top_self(), "include", top_include, -1);
 
     rb_define_global_function("using", f_using, 1);
+    rb_define_global_function("refine", f_refine, 1);
 
     rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1);
 
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index 05a4f33..ed01c77 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -86,6 +86,18 @@ class TestRefinement < Test::Unit::TestCase
     end
   end
 
+  module FooExt3
+    using FooExt
+  end
+
+  class FooExtClient3
+    using FooExt3
+
+    def self.invoke_x_on(foo)
+      return foo.x
+    end
+  end
+
   def test_override
     foo = Foo.new
     assert_equal("Foo#x", foo.x)
@@ -150,6 +162,13 @@ class TestRefinement < Test::Unit::TestCase
     assert_raise(NoMethodError) { sub.z }
   end
 
+  def test_indirect_using
+    foo = Foo.new
+    assert_equal("Foo#x", foo.x)
+    assert_equal("FooExt#x", FooExtClient3.invoke_x_on(foo))
+    assert_equal("Foo#x", foo.x)
+  end
+
   def test_module_eval
     foo = Foo.new
     assert_equal("Foo#x", foo.x)
@@ -307,5 +326,33 @@ class TestRefinement < Test::Unit::TestCase
     assert_equal("m2#bar", m.call_bar("abc"))
     assert_equal("m3#baz", m.call_baz("abc"))
   end
+
+  def test_refine_at_toplevel
+    assert_equal(0, 1 / 2)
+    result = eval(<<-EOF, TOPLEVEL_BINDING)
+      refine Fixnum do
+        def /(other) quo(other) end
+      end
+
+      1 / 2
+    EOF
+    assert_equal(Rational(1, 2), result)
+    assert_equal(0, 1 / 2)
+  end
+
+  def refine_in_method
+    refine Fixnum do
+      def /(other) quo(other) end
+    end
+
+    return 1 / 2
+  end
+  private :refine_in_method
+
+  def test_refine_in_method
+    assert_equal(0, 1 / 2)
+    assert_equal(Rational(1, 2), refine_in_method)
+    assert_equal(0, 1 / 2)
+  end
 end
 
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 6bb6f5b..4a4156a 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1763,10 +1763,9 @@ rb_vm_using_modules(NODE *cref, VALUE klass)
     ID id_using_modules;
     VALUE using_modules;
 
-    CONST_ID(id_using_modules, "__using_modules__");
-    using_modules = rb_attr_get(klass, id_using_modules);
-    switch (TYPE(klass)) {
-    case T_CLASS:
+    if (TYPE(klass) == T_CLASS) {
+	CONST_ID(id_using_modules, "__using_modules__");
+	using_modules = rb_attr_get(klass, id_using_modules);
 	if (NIL_P(using_modules)) {
 	    VALUE super = rb_class_real(RCLASS_SUPER(klass));
 	    using_modules = rb_attr_get(super, id_using_modules);
@@ -1775,14 +1774,7 @@ rb_vm_using_modules(NODE *cref, VALUE klass)
 		rb_ivar_set(klass, id_using_modules, using_modules);
 	    }
 	}
-	break;
-    case T_MODULE:
-	rb_using_module(cref, klass);
-	break;
-    }
-    if (!NIL_P(using_modules)) {
-	rb_hash_foreach(using_modules, vm_using_module_i,
-		       	(VALUE) cref);
     }
+    rb_using_module(cref, klass);
 }
 

In This Thread