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

ruby-changes:54718

From: nobu <ko1@a...>
Date: Mon, 28 Jan 2019 20:45:28 +0900 (JST)
Subject: [ruby-changes:54718] nobu:r66935 (trunk): Add refinements support to method/instance_method.

nobu	2019-01-28 20:45:21 +0900 (Mon, 28 Jan 2019)

  New Revision: 66935

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=66935

  Log:
    Add refinements support to method/instance_method.
    
    [Fix GH-2034]
    
    From: manga_osyo <manga.osyo@g...>

  Modified files:
    trunk/method.h
    trunk/proc.c
    trunk/spec/ruby/core/module/refine_spec.rb
    trunk/test/ruby/test_refinement.rb
    trunk/vm_method.c
Index: test/ruby/test_refinement.rb
===================================================================
--- test/ruby/test_refinement.rb	(revision 66934)
+++ test/ruby/test_refinement.rb	(revision 66935)
@@ -118,6 +118,10 @@ class TestRefinement < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_refinement.rb#L118
         return foo.method(:z)
       end
 
+      def self.instance_method_z(foo)
+        return foo.class.instance_method(:z)
+      end
+
       def self.invoke_call_x_on(foo)
         return foo.call_x
       end
@@ -213,11 +217,44 @@ class TestRefinement < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_refinement.rb#L217
     assert_raise(NoMethodError) { FooExtClient.public_send_b_on(foo) }
   end
 
-  def test_method_should_not_use_refinements
+  module MethodIntegerPowEx
+    refine Integer do
+      def pow(*)
+        :refine_pow
+      end
+    end
+  end
+  def test_method_should_use_refinements
     foo = Foo.new
     assert_raise(NameError) { foo.method(:z) }
-    assert_raise(NameError) { FooExtClient.method_z(foo) }
+    assert_equal("FooExt#z", FooExtClient.method_z(foo).call)
     assert_raise(NameError) { foo.method(:z) }
+    assert_equal(8, eval(<<~EOS, Sandbox::BINDING))
+      meth = 2.method(:pow)
+      using MethodIntegerPowEx
+      meth.call(3)
+    EOS
+    assert_equal(:refine_pow, eval_using(MethodIntegerPowEx, "2.pow(3)"))
+  end
+
+  module InstanceMethodIntegerPowEx
+    refine Integer do
+      def abs
+        :refine_abs
+      end
+    end
+  end
+  def test_instance_method_should_use_refinements
+    foo = Foo.new
+    assert_raise(NameError) { Foo.instance_method(:z) }
+    assert_equal("FooExt#z", FooExtClient.instance_method_z(foo).bind(foo).call)
+    assert_raise(NameError) { Foo.instance_method(:z) }
+    assert_equal(4, eval(<<~EOS, Sandbox::BINDING))
+      meth = Integer.instance_method(:abs)
+      using InstanceMethodIntegerPowEx
+      meth.bind(-4).call
+    EOS
+    assert_equal(:refine_abs, eval_using(InstanceMethodIntegerPowEx, "Integer.instance_method(:abs).bind(-4).call"))
   end
 
   def test_no_local_rebinding
Index: proc.c
===================================================================
--- proc.c	(revision 66934)
+++ proc.c	(revision 66935)
@@ -1413,7 +1413,7 @@ mnew_internal(const rb_method_entry_t *m https://github.com/ruby/ruby/blob/trunk/proc.c#L1413
 	if (me->defined_class) {
 	    VALUE klass = RCLASS_SUPER(RCLASS_ORIGIN(me->defined_class));
 	    id = me->def->original_id;
-	    me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id, &iclass);
+	    me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass);
 	}
 	else {
 	    VALUE klass = RCLASS_SUPER(me->owner);
@@ -1448,10 +1448,10 @@ mnew(VALUE klass, VALUE obj, ID id, VALU https://github.com/ruby/ruby/blob/trunk/proc.c#L1448
     VALUE iclass = Qnil;
 
     if (obj == Qundef) { /* UnboundMethod */
-	me = rb_method_entry_without_refinements(klass, id, &iclass);
+	me = rb_method_entry_with_refinements(klass, id, &iclass);
     }
     else {
-	me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id, &iclass);
+	me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass);
     }
     return mnew_from_me(me, klass, iclass, obj, id, mclass, scope);
 }
@@ -2766,7 +2766,7 @@ method_super_method(VALUE method) https://github.com/ruby/ruby/blob/trunk/proc.c#L2766
     super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass));
     mid = data->me->called_id;
     if (!super_class) return Qnil;
-    me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(super_class, mid, &iclass);
+    me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, mid, &iclass);
     if (!me) return Qnil;
     return mnew_internal(me, me->owner, iclass, data->recv, mid, rb_obj_class(method), FALSE, FALSE);
 }
Index: method.h
===================================================================
--- method.h	(revision 66934)
+++ method.h	(revision 66935)
@@ -196,6 +196,7 @@ rb_method_entry_t *rb_method_entry_creat https://github.com/ruby/ruby/blob/trunk/method.h#L196
 const rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
 
 const rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
+const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class);
 const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class);
 const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
 RUBY_SYMBOL_EXPORT_BEGIN
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 66934)
+++ vm_method.c	(revision 66935)
@@ -899,6 +899,12 @@ method_entry_resolve_refinement(VALUE kl https://github.com/ruby/ruby/blob/trunk/vm_method.c#L899
     return me;
 }
 
+const rb_method_entry_t *
+rb_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
+{
+    return method_entry_resolve_refinement(klass, id, TRUE, defined_class_ptr);
+}
+
 MJIT_FUNC_EXPORTED const rb_callable_method_entry_t *
 rb_callable_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
 {
Index: spec/ruby/core/module/refine_spec.rb
===================================================================
--- spec/ruby/core/module/refine_spec.rb	(revision 66934)
+++ spec/ruby/core/module/refine_spec.rb	(revision 66935)
@@ -526,20 +526,78 @@ describe "Module#refine" do https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/module/refine_spec.rb#L526
       result.should == "hello from refinement"
     end
 
-    it "is not honored by Kernel#method" do
-      klass = Class.new
-      refinement = Module.new do
-        refine klass do
-          def foo; end
+    ruby_version_is "" ... "2.7" do
+      it "is not honored by Kernel#method" do
+        klass = Class.new
+        refinement = Module.new do
+          refine klass do
+            def foo; end
+          end
         end
+
+        -> {
+          Module.new do
+            using refinement
+            klass.new.method(:foo)
+          end
+        }.should raise_error(NameError, /undefined method `foo'/)
+      end
+    end
+
+    ruby_version_is "2.7" do
+      it "is honored by Kernel#method" do
+        klass = Class.new
+        refinement = Module.new do
+          refine klass do
+            def foo; end
+          end
+        end
+
+        result = nil
+        Module.new do
+          using refinement
+          result = klass.new.method(:foo).class
+        end
+
+        result.should == Method
       end
+    end
+
+    ruby_version_is "" ... "2.7" do
+      it "is not honored by Kernel#instance_method" do
+        klass = Class.new
+        refinement = Module.new do
+          refine klass do
+            def foo; end
+          end
+        end
+
+        -> {
+          Module.new do
+            using refinement
+            klass.instance_method(:foo)
+          end
+        }.should raise_error(NameError, /undefined method `foo'/)
+      end
+    end
+
+    ruby_version_is "2.7" do
+      it "is honored by Kernel#method" do
+        klass = Class.new
+        refinement = Module.new do
+          refine klass do
+            def foo; end
+          end
+        end
 
-      -> {
+        result = nil
         Module.new do
           using refinement
-          klass.new.method(:foo)
+          result = klass.instance_method(:foo).class
         end
-      }.should raise_error(NameError, /undefined method `foo'/)
+
+        result.should == UnboundMethod
+      end
     end
 
     ruby_version_is "" ... "2.6" do

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

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