2015-12-16 00:07:31 -05:00
|
|
|
# frozen_string_literal: false
|
2012-08-02 07:34:19 -04:00
|
|
|
require 'test/unit'
|
|
|
|
|
|
|
|
class TestRefinement < Test::Unit::TestCase
|
2015-03-04 21:56:03 -05:00
|
|
|
module Sandbox
|
|
|
|
BINDING = binding
|
|
|
|
end
|
|
|
|
|
2012-08-02 07:34:19 -04:00
|
|
|
class Foo
|
|
|
|
def x
|
|
|
|
return "Foo#x"
|
|
|
|
end
|
|
|
|
|
|
|
|
def y
|
|
|
|
return "Foo#y"
|
|
|
|
end
|
|
|
|
|
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 11:05:45 -05:00
|
|
|
def a
|
|
|
|
return "Foo#a"
|
|
|
|
end
|
|
|
|
|
2018-11-22 02:53:07 -05:00
|
|
|
def b
|
|
|
|
return "Foo#b"
|
|
|
|
end
|
|
|
|
|
2012-08-02 07:34:19 -04:00
|
|
|
def call_x
|
|
|
|
return x
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module FooExt
|
|
|
|
refine Foo do
|
|
|
|
def x
|
|
|
|
return "FooExt#x"
|
|
|
|
end
|
|
|
|
|
|
|
|
def y
|
|
|
|
return "FooExt#y " + super
|
|
|
|
end
|
|
|
|
|
|
|
|
def z
|
|
|
|
return "FooExt#z"
|
|
|
|
end
|
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 11:05:45 -05:00
|
|
|
|
|
|
|
def a
|
|
|
|
return "FooExt#a"
|
|
|
|
end
|
2018-11-22 02:53:07 -05:00
|
|
|
|
|
|
|
private def b
|
|
|
|
return "FooExt#b"
|
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module FooExt2
|
|
|
|
refine Foo do
|
|
|
|
def x
|
|
|
|
return "FooExt2#x"
|
|
|
|
end
|
|
|
|
|
|
|
|
def y
|
|
|
|
return "FooExt2#y " + super
|
|
|
|
end
|
|
|
|
|
|
|
|
def z
|
|
|
|
return "FooExt2#z"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class FooSub < Foo
|
|
|
|
def x
|
|
|
|
return "FooSub#x"
|
|
|
|
end
|
|
|
|
|
|
|
|
def y
|
|
|
|
return "FooSub#y " + super
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-10-15 18:59:38 -04:00
|
|
|
class FooExtClient
|
2012-12-06 10:12:36 -05:00
|
|
|
using TestRefinement::FooExt
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2016-10-15 18:59:38 -04:00
|
|
|
begin
|
2016-10-15 18:59:39 -04:00
|
|
|
def self.map_x_on(foo)
|
|
|
|
[foo].map(&:x)[0]
|
|
|
|
end
|
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
def self.invoke_x_on(foo)
|
|
|
|
return foo.x
|
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
def self.invoke_y_on(foo)
|
|
|
|
return foo.y
|
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
def self.invoke_z_on(foo)
|
|
|
|
return foo.z
|
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
def self.send_z_on(foo)
|
|
|
|
return foo.send(:z)
|
|
|
|
end
|
2012-11-02 20:09:26 -04:00
|
|
|
|
2018-11-22 02:53:07 -05:00
|
|
|
def self.send_b_on(foo)
|
|
|
|
return foo.send(:b)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.public_send_z_on(foo)
|
|
|
|
return foo.public_send(:z)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.public_send_b_on(foo)
|
|
|
|
return foo.public_send(:b)
|
|
|
|
end
|
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
def self.method_z(foo)
|
|
|
|
return foo.method(:z)
|
|
|
|
end
|
2012-11-02 20:09:26 -04:00
|
|
|
|
2019-01-28 06:45:21 -05:00
|
|
|
def self.instance_method_z(foo)
|
|
|
|
return foo.class.instance_method(:z)
|
|
|
|
end
|
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
def self.invoke_call_x_on(foo)
|
|
|
|
return foo.call_x
|
|
|
|
end
|
2016-10-22 22:03:56 -04:00
|
|
|
|
|
|
|
def self.return_proc(&block)
|
|
|
|
block
|
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
end
|
2016-10-15 18:59:38 -04:00
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2016-10-15 18:59:38 -04:00
|
|
|
class TestRefinement::FooExtClient2
|
2012-12-06 10:12:36 -05:00
|
|
|
using TestRefinement::FooExt
|
|
|
|
using TestRefinement::FooExt2
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2016-10-15 18:59:38 -04:00
|
|
|
begin
|
2012-12-06 10:12:36 -05:00
|
|
|
def self.invoke_y_on(foo)
|
|
|
|
return foo.y
|
|
|
|
end
|
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 11:05:45 -05:00
|
|
|
|
|
|
|
def self.invoke_a_on(foo)
|
|
|
|
return foo.a
|
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
end
|
2016-10-15 18:59:38 -04:00
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
|
|
|
|
def test_override
|
|
|
|
foo = Foo.new
|
|
|
|
assert_equal("Foo#x", foo.x)
|
|
|
|
assert_equal("FooExt#x", FooExtClient.invoke_x_on(foo))
|
|
|
|
assert_equal("Foo#x", foo.x)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_super
|
|
|
|
foo = Foo.new
|
|
|
|
assert_equal("Foo#y", foo.y)
|
|
|
|
assert_equal("FooExt#y Foo#y", FooExtClient.invoke_y_on(foo))
|
|
|
|
assert_equal("Foo#y", foo.y)
|
|
|
|
end
|
|
|
|
|
2012-12-07 22:36:58 -05:00
|
|
|
def test_super_not_chained
|
2012-08-02 07:34:19 -04:00
|
|
|
foo = Foo.new
|
|
|
|
assert_equal("Foo#y", foo.y)
|
2012-12-07 22:36:58 -05:00
|
|
|
assert_equal("FooExt2#y Foo#y", FooExtClient2.invoke_y_on(foo))
|
2012-08-02 07:34:19 -04:00
|
|
|
assert_equal("Foo#y", foo.y)
|
|
|
|
end
|
|
|
|
|
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 11:05:45 -05:00
|
|
|
def test_using_same_class_refinements
|
|
|
|
foo = Foo.new
|
|
|
|
assert_equal("Foo#a", foo.a)
|
|
|
|
assert_equal("FooExt#a", FooExtClient2.invoke_a_on(foo))
|
|
|
|
assert_equal("Foo#a", foo.a)
|
|
|
|
end
|
|
|
|
|
2012-08-02 07:34:19 -04:00
|
|
|
def test_new_method
|
|
|
|
foo = Foo.new
|
|
|
|
assert_raise(NoMethodError) { foo.z }
|
|
|
|
assert_equal("FooExt#z", FooExtClient.invoke_z_on(foo))
|
|
|
|
assert_raise(NoMethodError) { foo.z }
|
|
|
|
end
|
|
|
|
|
2012-12-10 08:02:54 -05:00
|
|
|
module RespondTo
|
|
|
|
class Super
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Sub < Super
|
|
|
|
end
|
|
|
|
|
|
|
|
module M
|
|
|
|
refine Sub do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-10-19 04:02:17 -04:00
|
|
|
def test_send_should_use_refinements
|
2012-11-02 20:09:26 -04:00
|
|
|
foo = Foo.new
|
|
|
|
assert_raise(NoMethodError) { foo.send(:z) }
|
2016-10-19 04:02:17 -04:00
|
|
|
assert_equal("FooExt#z", FooExtClient.send_z_on(foo))
|
2018-11-22 02:53:07 -05:00
|
|
|
assert_equal("FooExt#b", FooExtClient.send_b_on(foo))
|
2012-11-02 20:09:26 -04:00
|
|
|
assert_raise(NoMethodError) { foo.send(:z) }
|
2012-12-10 08:02:54 -05:00
|
|
|
|
|
|
|
assert_equal(true, RespondTo::Sub.new.respond_to?(:foo))
|
2012-11-02 20:09:26 -04:00
|
|
|
end
|
|
|
|
|
2018-11-22 02:53:07 -05:00
|
|
|
def test_public_send_should_use_refinements
|
|
|
|
foo = Foo.new
|
|
|
|
assert_raise(NoMethodError) { foo.public_send(:z) }
|
|
|
|
assert_equal("FooExt#z", FooExtClient.public_send_z_on(foo))
|
|
|
|
assert_equal("Foo#b", foo.public_send(:b))
|
|
|
|
assert_raise(NoMethodError) { FooExtClient.public_send_b_on(foo) }
|
|
|
|
end
|
|
|
|
|
2019-01-28 06:45:21 -05:00
|
|
|
module MethodIntegerPowEx
|
|
|
|
refine Integer do
|
|
|
|
def pow(*)
|
|
|
|
:refine_pow
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
def test_method_should_use_refinements
|
2021-09-08 07:36:56 -04:00
|
|
|
skip if Test::Unit::Runner.current_repeat_count > 0
|
2020-01-28 00:35:38 -05:00
|
|
|
|
2012-11-02 20:09:26 -04:00
|
|
|
foo = Foo.new
|
2012-12-09 03:48:34 -05:00
|
|
|
assert_raise(NameError) { foo.method(:z) }
|
2019-01-28 06:45:21 -05:00
|
|
|
assert_equal("FooExt#z", FooExtClient.method_z(foo).call)
|
2012-12-09 03:48:34 -05:00
|
|
|
assert_raise(NameError) { foo.method(:z) }
|
2019-01-28 06:45:21 -05:00
|
|
|
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)"))
|
2019-10-23 12:06:59 -04:00
|
|
|
assert_equal(:refine_pow, eval_using(MethodIntegerPowEx, "2.method(:pow).(3)"))
|
2019-01-28 06:45:21 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
module InstanceMethodIntegerPowEx
|
|
|
|
refine Integer do
|
|
|
|
def abs
|
|
|
|
:refine_abs
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
def test_instance_method_should_use_refinements
|
2021-09-08 07:36:56 -04:00
|
|
|
skip if Test::Unit::Runner.current_repeat_count > 0
|
2020-01-28 00:35:38 -05:00
|
|
|
|
2019-01-28 06:45:21 -05:00
|
|
|
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"))
|
2012-11-02 20:09:26 -04:00
|
|
|
end
|
|
|
|
|
2012-08-02 07:34:19 -04:00
|
|
|
def test_no_local_rebinding
|
|
|
|
foo = Foo.new
|
|
|
|
assert_equal("Foo#x", foo.call_x)
|
|
|
|
assert_equal("Foo#x", FooExtClient.invoke_call_x_on(foo))
|
|
|
|
assert_equal("Foo#x", foo.call_x)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_subclass_is_prior
|
|
|
|
sub = FooSub.new
|
|
|
|
assert_equal("FooSub#x", sub.x)
|
|
|
|
assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub))
|
|
|
|
assert_equal("FooSub#x", sub.x)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_super_in_subclass
|
|
|
|
sub = FooSub.new
|
|
|
|
assert_equal("FooSub#y Foo#y", sub.y)
|
|
|
|
# not "FooSub#y FooExt#y Foo#y"
|
|
|
|
assert_equal("FooSub#y Foo#y", FooExtClient.invoke_y_on(sub))
|
|
|
|
assert_equal("FooSub#y Foo#y", sub.y)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_new_method_on_subclass
|
|
|
|
sub = FooSub.new
|
|
|
|
assert_raise(NoMethodError) { sub.z }
|
|
|
|
assert_equal("FooExt#z", FooExtClient.invoke_z_on(sub))
|
|
|
|
assert_raise(NoMethodError) { sub.z }
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_module_eval
|
|
|
|
foo = Foo.new
|
|
|
|
assert_equal("Foo#x", foo.x)
|
2012-12-07 10:49:21 -05:00
|
|
|
assert_equal("Foo#x", FooExt.module_eval { foo.x })
|
|
|
|
assert_equal("Foo#x", FooExt.module_eval("foo.x"))
|
2012-08-02 07:34:19 -04:00
|
|
|
assert_equal("Foo#x", foo.x)
|
|
|
|
end
|
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
def test_instance_eval_without_refinement
|
2012-08-02 07:34:19 -04:00
|
|
|
foo = Foo.new
|
|
|
|
ext_client = FooExtClient.new
|
|
|
|
assert_equal("Foo#x", foo.x)
|
2012-12-06 10:12:36 -05:00
|
|
|
assert_equal("Foo#x", ext_client.instance_eval { foo.x })
|
2012-08-02 07:34:19 -04:00
|
|
|
assert_equal("Foo#x", foo.x)
|
|
|
|
end
|
|
|
|
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
module IntegerSlashExt
|
|
|
|
refine Integer do
|
2012-12-06 10:12:36 -05:00
|
|
|
def /(other) quo(other) end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-08-02 07:34:19 -04:00
|
|
|
def test_override_builtin_method
|
|
|
|
assert_equal(0, 1 / 2)
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
assert_equal(Rational(1, 2), eval_using(IntegerSlashExt, "1 / 2"))
|
2012-08-02 07:34:19 -04:00
|
|
|
assert_equal(0, 1 / 2)
|
|
|
|
end
|
|
|
|
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
module IntegerPlusExt
|
|
|
|
refine Integer do
|
2012-12-06 10:12:36 -05:00
|
|
|
def self.method_added(*args); end
|
2013-12-19 23:44:09 -05:00
|
|
|
def +(other) "overridden" end
|
2012-12-06 10:12:36 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-11-06 23:09:51 -05:00
|
|
|
def test_override_builtin_method_with_method_added
|
|
|
|
assert_equal(3, 1 + 2)
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
assert_equal("overridden", eval_using(IntegerPlusExt, "1 + 2"))
|
2012-11-06 23:09:51 -05:00
|
|
|
assert_equal(3, 1 + 2)
|
|
|
|
end
|
|
|
|
|
2012-08-02 07:34:19 -04:00
|
|
|
def test_return_value_of_refine
|
|
|
|
mod = nil
|
|
|
|
result = nil
|
2014-03-05 08:27:22 -05:00
|
|
|
Module.new {
|
2012-08-02 07:34:19 -04:00
|
|
|
result = refine(Object) {
|
|
|
|
mod = self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert_equal mod, result
|
|
|
|
end
|
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
module RefineSameClass
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
REFINEMENT1 = refine(Integer) {
|
2012-12-06 10:12:36 -05:00
|
|
|
def foo; return "foo" end
|
|
|
|
}
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
REFINEMENT2 = refine(Integer) {
|
2012-12-06 10:12:36 -05:00
|
|
|
def bar; return "bar" end
|
|
|
|
}
|
|
|
|
REFINEMENT3 = refine(String) {
|
|
|
|
def baz; return "baz" end
|
2012-08-02 07:34:19 -04:00
|
|
|
}
|
2012-12-06 10:12:36 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_same_class_twice
|
|
|
|
assert_equal("foo", eval_using(RefineSameClass, "1.foo"))
|
|
|
|
assert_equal("bar", eval_using(RefineSameClass, "1.bar"))
|
|
|
|
assert_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT2)
|
|
|
|
assert_not_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT3)
|
2012-08-02 07:34:19 -04:00
|
|
|
end
|
|
|
|
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
module IntegerFooExt
|
|
|
|
refine Integer do
|
2012-12-07 10:49:21 -05:00
|
|
|
def foo; "foo"; end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-22 03:29:02 -05:00
|
|
|
def test_respond_to_should_use_refinements
|
2012-08-02 07:34:19 -04:00
|
|
|
assert_equal(false, 1.respond_to?(:foo))
|
2018-11-22 03:29:02 -05:00
|
|
|
assert_equal(true, eval_using(IntegerFooExt, "1.respond_to?(:foo)"))
|
2012-08-02 07:34:19 -04:00
|
|
|
end
|
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
module StringCmpExt
|
|
|
|
refine String do
|
|
|
|
def <=>(other) return 0 end
|
|
|
|
end
|
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2012-12-06 10:12:36 -05:00
|
|
|
module ArrayEachExt
|
|
|
|
refine Array do
|
|
|
|
def each
|
|
|
|
super do |i|
|
|
|
|
yield 2 * i
|
2012-08-02 07:34:19 -04:00
|
|
|
end
|
|
|
|
end
|
2012-12-06 10:12:36 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_builtin_method_no_local_rebinding
|
|
|
|
assert_equal(false, eval_using(StringCmpExt, '"1" >= "2"'))
|
|
|
|
assert_equal(1, eval_using(ArrayEachExt, "[1, 2, 3].min"))
|
2012-08-02 07:34:19 -04:00
|
|
|
end
|
|
|
|
|
2012-12-07 10:49:21 -05:00
|
|
|
module RefinePrependedClass
|
|
|
|
module M1
|
2012-08-06 22:44:24 -04:00
|
|
|
def foo
|
|
|
|
super << :m1
|
|
|
|
end
|
2012-12-07 10:49:21 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
class C
|
|
|
|
prepend M1
|
2012-08-06 22:44:24 -04:00
|
|
|
|
|
|
|
def foo
|
|
|
|
[:c]
|
|
|
|
end
|
2012-12-07 10:49:21 -05:00
|
|
|
end
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2012-12-07 10:49:21 -05:00
|
|
|
module M2
|
|
|
|
refine C do
|
2012-09-27 05:53:24 -04:00
|
|
|
def foo
|
2012-12-07 10:49:21 -05:00
|
|
|
super << :m2
|
2012-09-27 05:53:24 -04:00
|
|
|
end
|
|
|
|
end
|
2012-12-07 10:49:21 -05:00
|
|
|
end
|
2012-09-27 05:53:24 -04:00
|
|
|
end
|
|
|
|
|
2012-12-07 10:49:21 -05:00
|
|
|
def test_refine_prepended_class
|
|
|
|
x = eval_using(RefinePrependedClass::M2,
|
|
|
|
"TestRefinement::RefinePrependedClass::C.new.foo")
|
|
|
|
assert_equal([:c, :m1, :m2], x)
|
2012-09-27 05:53:24 -04:00
|
|
|
end
|
|
|
|
|
2016-09-23 07:46:33 -04:00
|
|
|
module RefineModule
|
|
|
|
module M
|
|
|
|
def foo
|
|
|
|
"M#foo"
|
|
|
|
end
|
|
|
|
|
|
|
|
def bar
|
|
|
|
"M#bar"
|
|
|
|
end
|
|
|
|
|
|
|
|
def baz
|
|
|
|
"M#baz"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class C
|
|
|
|
include M
|
|
|
|
|
|
|
|
def baz
|
|
|
|
"#{super} C#baz"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M2
|
|
|
|
refine M do
|
2012-09-28 22:21:27 -04:00
|
|
|
def foo
|
2016-09-23 07:46:33 -04:00
|
|
|
"M@M2#foo"
|
2012-09-28 22:21:27 -04:00
|
|
|
end
|
2016-09-23 07:46:33 -04:00
|
|
|
|
|
|
|
def bar
|
|
|
|
"#{super} M@M2#bar"
|
2012-09-28 22:21:27 -04:00
|
|
|
end
|
2016-09-23 07:46:33 -04:00
|
|
|
|
|
|
|
def baz
|
|
|
|
"#{super} M@M2#baz"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using M2
|
|
|
|
|
|
|
|
def self.call_foo
|
|
|
|
C.new.foo
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.call_bar
|
|
|
|
C.new.bar
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.call_baz
|
|
|
|
C.new.baz
|
2012-12-07 10:49:21 -05:00
|
|
|
end
|
2012-09-28 02:48:20 -04:00
|
|
|
end
|
|
|
|
|
2016-09-23 07:46:33 -04:00
|
|
|
def test_refine_module
|
|
|
|
assert_equal("M@M2#foo", RefineModule.call_foo)
|
|
|
|
assert_equal("M#bar M@M2#bar", RefineModule.call_bar)
|
|
|
|
assert_equal("M#baz C#baz", RefineModule.call_baz)
|
|
|
|
end
|
|
|
|
|
2012-09-27 05:53:24 -04:00
|
|
|
def test_refine_neither_class_nor_module
|
|
|
|
assert_raise(TypeError) do
|
|
|
|
Module.new {
|
|
|
|
refine Object.new do
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end
|
|
|
|
assert_raise(TypeError) do
|
|
|
|
Module.new {
|
|
|
|
refine 123 do
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end
|
|
|
|
assert_raise(TypeError) do
|
|
|
|
Module.new {
|
|
|
|
refine "foo" do
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
2012-09-28 22:21:27 -04:00
|
|
|
|
2012-12-07 10:49:21 -05:00
|
|
|
def test_refine_in_class
|
|
|
|
assert_raise(NoMethodError) do
|
|
|
|
Class.new {
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 09:15:57 -04:00
|
|
|
refine Integer do
|
2012-12-07 10:49:21 -05:00
|
|
|
def foo
|
|
|
|
"c"
|
|
|
|
end
|
2012-09-28 22:21:27 -04:00
|
|
|
end
|
2012-12-07 10:49:21 -05:00
|
|
|
}
|
|
|
|
end
|
2012-09-28 22:21:27 -04:00
|
|
|
end
|
|
|
|
|
2012-11-11 01:14:16 -05:00
|
|
|
def test_main_using
|
2013-07-31 05:29:40 -04:00
|
|
|
assert_in_out_err([], <<-INPUT, %w(:C :M), [])
|
2012-11-11 01:14:16 -05:00
|
|
|
class C
|
|
|
|
def foo
|
|
|
|
:C
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
:M
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
c = C.new
|
|
|
|
p c.foo
|
|
|
|
using M
|
|
|
|
p c.foo
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2012-12-07 10:49:21 -05:00
|
|
|
def test_main_using_is_private
|
|
|
|
assert_raise(NoMethodError) do
|
2019-07-02 10:06:54 -04:00
|
|
|
eval("recv = self; recv.using Module.new", Sandbox::BINDING)
|
2012-12-07 10:49:21 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-11-11 01:14:16 -05:00
|
|
|
def test_no_kernel_using
|
|
|
|
assert_raise(NoMethodError) do
|
|
|
|
using Module.new
|
2012-09-28 22:21:27 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-07 10:49:21 -05:00
|
|
|
class UsingClass
|
|
|
|
end
|
|
|
|
|
2012-09-28 22:21:27 -04:00
|
|
|
def test_module_using_class
|
|
|
|
assert_raise(TypeError) do
|
2015-03-04 21:56:03 -05:00
|
|
|
eval("using TestRefinement::UsingClass", Sandbox::BINDING)
|
2012-09-28 22:21:27 -04:00
|
|
|
end
|
|
|
|
end
|
2012-10-08 10:56:08 -04:00
|
|
|
|
2012-10-30 10:58:47 -04:00
|
|
|
def test_refine_without_block
|
|
|
|
c1 = Class.new
|
2013-10-09 11:17:20 -04:00
|
|
|
assert_raise_with_message(ArgumentError, "no block given") {
|
2012-10-30 10:58:47 -04:00
|
|
|
Module.new do
|
|
|
|
refine c1
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end
|
2012-11-01 01:45:28 -04:00
|
|
|
|
2012-11-02 04:53:06 -04:00
|
|
|
module Inspect
|
|
|
|
module M
|
2016-05-01 23:35:52 -04:00
|
|
|
Integer = refine(Integer) {}
|
2012-11-02 04:53:06 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_inspect
|
2016-05-01 23:35:52 -04:00
|
|
|
assert_equal("#<refinement:Integer@TestRefinement::Inspect::M>",
|
|
|
|
Inspect::M::Integer.inspect)
|
2012-11-02 04:53:06 -04:00
|
|
|
end
|
2012-11-10 21:42:04 -05:00
|
|
|
|
2012-11-10 23:45:31 -05:00
|
|
|
def test_using_method_cache
|
2013-07-31 05:29:40 -04:00
|
|
|
assert_in_out_err([], <<-INPUT, %w(:M1 :M2), [])
|
2012-11-10 23:45:31 -05:00
|
|
|
class C
|
|
|
|
def foo
|
|
|
|
"original"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M1
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
:M1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M2
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
:M2
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
c = C.new
|
|
|
|
using M1
|
|
|
|
p c.foo
|
|
|
|
using M2
|
|
|
|
p c.foo
|
|
|
|
INPUT
|
|
|
|
end
|
2012-11-13 04:05:18 -05:00
|
|
|
|
2012-12-07 10:49:21 -05:00
|
|
|
module RedefineRefinedMethod
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
class C
|
|
|
|
def foo
|
|
|
|
"original"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
"refined"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class C
|
2016-02-19 02:58:09 -05:00
|
|
|
EnvUtil.suppress_warning do
|
|
|
|
def foo
|
|
|
|
"redefined"
|
|
|
|
end
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_redefine_refined_method
|
2012-12-07 10:49:21 -05:00
|
|
|
x = eval_using(RedefineRefinedMethod::M,
|
|
|
|
"TestRefinement::RedefineRefinedMethod::C.new.foo")
|
|
|
|
assert_equal("refined", x)
|
|
|
|
end
|
|
|
|
|
|
|
|
module StringExt
|
|
|
|
refine String do
|
|
|
|
def foo
|
|
|
|
"foo"
|
|
|
|
end
|
|
|
|
end
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
end
|
2012-12-06 10:12:36 -05:00
|
|
|
|
2012-12-07 21:37:16 -05:00
|
|
|
module RefineScoping
|
|
|
|
refine String do
|
|
|
|
def foo
|
|
|
|
"foo"
|
|
|
|
end
|
|
|
|
|
|
|
|
def RefineScoping.call_in_refine_block
|
|
|
|
"".foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.call_outside_refine_block
|
|
|
|
"".foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_scoping
|
|
|
|
assert_equal("foo", RefineScoping.call_in_refine_block)
|
|
|
|
assert_raise(NoMethodError) do
|
|
|
|
RefineScoping.call_outside_refine_block
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module StringRecursiveLength
|
|
|
|
refine String do
|
|
|
|
def recursive_length
|
|
|
|
if empty?
|
|
|
|
0
|
2012-12-19 20:52:47 -05:00
|
|
|
else
|
2012-12-07 21:37:16 -05:00
|
|
|
self[1..-1].recursive_length + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_recursion
|
|
|
|
x = eval_using(StringRecursiveLength, "'foo'.recursive_length")
|
|
|
|
assert_equal(3, x)
|
|
|
|
end
|
|
|
|
|
|
|
|
module ToJSON
|
|
|
|
refine Integer do
|
|
|
|
def to_json; to_s; end
|
|
|
|
end
|
|
|
|
|
|
|
|
refine Array do
|
|
|
|
def to_json; "[" + map { |i| i.to_json }.join(",") + "]" end
|
|
|
|
end
|
|
|
|
|
|
|
|
refine Hash do
|
|
|
|
def to_json; "{" + map { |k, v| k.to_s.dump + ":" + v.to_json }.join(",") + "}" end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_mutual_recursion
|
|
|
|
x = eval_using(ToJSON, "[{1=>2}, {3=>4}].to_json")
|
|
|
|
assert_equal('[{"1":2},{"3":4}]', x)
|
|
|
|
end
|
|
|
|
|
2012-12-07 22:06:13 -05:00
|
|
|
def test_refine_with_proc
|
|
|
|
assert_raise(ArgumentError) do
|
|
|
|
Module.new {
|
|
|
|
refine(String, &Proc.new {})
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-08 08:35:12 -05:00
|
|
|
def test_using_in_module
|
|
|
|
assert_raise(RuntimeError) do
|
2015-03-04 21:56:03 -05:00
|
|
|
eval(<<-EOF, Sandbox::BINDING)
|
2012-12-08 08:35:12 -05:00
|
|
|
$main = self
|
|
|
|
module M
|
|
|
|
end
|
|
|
|
module M2
|
|
|
|
$main.send(:using, M)
|
|
|
|
end
|
|
|
|
EOF
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_using_in_method
|
|
|
|
assert_raise(RuntimeError) do
|
2015-03-04 21:56:03 -05:00
|
|
|
eval(<<-EOF, Sandbox::BINDING)
|
2012-12-08 08:35:12 -05:00
|
|
|
$main = self
|
|
|
|
module M
|
|
|
|
end
|
2015-03-04 21:56:03 -05:00
|
|
|
class C
|
|
|
|
def call_using_in_method
|
|
|
|
$main.send(:using, M)
|
|
|
|
end
|
2012-12-08 08:35:12 -05:00
|
|
|
end
|
2015-03-04 21:56:03 -05:00
|
|
|
C.new.call_using_in_method
|
2012-12-08 08:35:12 -05:00
|
|
|
EOF
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 11:05:45 -05:00
|
|
|
module IncludeIntoRefinement
|
|
|
|
class C
|
|
|
|
def bar
|
|
|
|
return "C#bar"
|
|
|
|
end
|
|
|
|
|
|
|
|
def baz
|
|
|
|
return "C#baz"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module Mixin
|
|
|
|
def foo
|
|
|
|
return "Mixin#foo"
|
|
|
|
end
|
|
|
|
|
|
|
|
def bar
|
|
|
|
return super << " Mixin#bar"
|
|
|
|
end
|
|
|
|
|
|
|
|
def baz
|
|
|
|
return super << " Mixin#baz"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M
|
|
|
|
refine C do
|
|
|
|
include Mixin
|
|
|
|
|
|
|
|
def baz
|
|
|
|
return super << " M#baz"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-03-04 21:56:03 -05:00
|
|
|
eval <<-EOF, Sandbox::BINDING
|
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 11:05:45 -05:00
|
|
|
using TestRefinement::IncludeIntoRefinement::M
|
|
|
|
|
|
|
|
module TestRefinement::IncludeIntoRefinement::User
|
|
|
|
def self.invoke_foo_on(x)
|
|
|
|
x.foo
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.invoke_bar_on(x)
|
|
|
|
x.bar
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.invoke_baz_on(x)
|
|
|
|
x.baz
|
|
|
|
end
|
|
|
|
end
|
|
|
|
EOF
|
|
|
|
|
|
|
|
def test_include_into_refinement
|
|
|
|
x = IncludeIntoRefinement::C.new
|
|
|
|
assert_equal("Mixin#foo", IncludeIntoRefinement::User.invoke_foo_on(x))
|
|
|
|
assert_equal("C#bar Mixin#bar",
|
|
|
|
IncludeIntoRefinement::User.invoke_bar_on(x))
|
|
|
|
assert_equal("C#baz Mixin#baz M#baz",
|
|
|
|
IncludeIntoRefinement::User.invoke_baz_on(x))
|
|
|
|
end
|
|
|
|
|
2012-12-11 11:48:21 -05:00
|
|
|
module PrependIntoRefinement
|
|
|
|
class C
|
|
|
|
def bar
|
|
|
|
return "C#bar"
|
|
|
|
end
|
|
|
|
|
|
|
|
def baz
|
|
|
|
return "C#baz"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module Mixin
|
|
|
|
def foo
|
|
|
|
return "Mixin#foo"
|
|
|
|
end
|
|
|
|
|
|
|
|
def bar
|
|
|
|
return super << " Mixin#bar"
|
|
|
|
end
|
|
|
|
|
|
|
|
def baz
|
|
|
|
return super << " Mixin#baz"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M
|
|
|
|
refine C do
|
|
|
|
prepend Mixin
|
|
|
|
|
|
|
|
def baz
|
|
|
|
return super << " M#baz"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-03-04 21:56:03 -05:00
|
|
|
eval <<-EOF, Sandbox::BINDING
|
2012-12-11 11:48:21 -05:00
|
|
|
using TestRefinement::PrependIntoRefinement::M
|
|
|
|
|
|
|
|
module TestRefinement::PrependIntoRefinement::User
|
|
|
|
def self.invoke_foo_on(x)
|
|
|
|
x.foo
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.invoke_bar_on(x)
|
|
|
|
x.bar
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.invoke_baz_on(x)
|
|
|
|
x.baz
|
|
|
|
end
|
|
|
|
end
|
|
|
|
EOF
|
|
|
|
|
|
|
|
def test_prepend_into_refinement
|
|
|
|
x = PrependIntoRefinement::C.new
|
|
|
|
assert_equal("Mixin#foo", PrependIntoRefinement::User.invoke_foo_on(x))
|
|
|
|
assert_equal("C#bar Mixin#bar",
|
|
|
|
PrependIntoRefinement::User.invoke_bar_on(x))
|
|
|
|
assert_equal("C#baz M#baz Mixin#baz",
|
|
|
|
PrependIntoRefinement::User.invoke_baz_on(x))
|
|
|
|
end
|
|
|
|
|
2015-08-31 04:07:59 -04:00
|
|
|
PrependAfterRefine_CODE = <<-EOC
|
2012-12-12 04:35:50 -05:00
|
|
|
module PrependAfterRefine
|
|
|
|
class C
|
|
|
|
def foo
|
|
|
|
"original"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
"refined"
|
|
|
|
end
|
|
|
|
|
|
|
|
def bar
|
|
|
|
"refined"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module Mixin
|
|
|
|
def foo
|
|
|
|
"mixin"
|
|
|
|
end
|
|
|
|
|
|
|
|
def bar
|
|
|
|
"mixin"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class C
|
|
|
|
prepend Mixin
|
|
|
|
end
|
|
|
|
end
|
2015-08-31 04:07:59 -04:00
|
|
|
EOC
|
|
|
|
eval PrependAfterRefine_CODE
|
|
|
|
|
|
|
|
def test_prepend_after_refine_wb_miss
|
2016-06-28 23:45:23 -04:00
|
|
|
if /\A(arm|mips)/ =~ RUBY_PLATFORM
|
|
|
|
skip "too slow cpu"
|
|
|
|
end
|
2015-08-31 04:07:59 -04:00
|
|
|
assert_normal_exit %Q{
|
|
|
|
GC.stress = true
|
|
|
|
10.times{
|
|
|
|
#{PrependAfterRefine_CODE}
|
|
|
|
undef PrependAfterRefine
|
|
|
|
}
|
2020-04-20 11:06:07 -04:00
|
|
|
}, timeout: 60
|
2015-08-31 04:07:59 -04:00
|
|
|
end
|
2012-12-12 04:35:50 -05:00
|
|
|
|
|
|
|
def test_prepend_after_refine
|
|
|
|
x = eval_using(PrependAfterRefine::M,
|
|
|
|
"TestRefinement::PrependAfterRefine::C.new.foo")
|
|
|
|
assert_equal("refined", x)
|
|
|
|
assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.foo)
|
|
|
|
y = eval_using(PrependAfterRefine::M,
|
|
|
|
"TestRefinement::PrependAfterRefine::C.new.bar")
|
|
|
|
assert_equal("refined", y)
|
|
|
|
assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.bar)
|
|
|
|
end
|
|
|
|
|
2013-02-23 23:36:00 -05:00
|
|
|
module SuperInBlock
|
|
|
|
class C
|
|
|
|
def foo(*args)
|
|
|
|
[:foo, *args]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module R
|
|
|
|
refine C do
|
|
|
|
def foo(*args)
|
|
|
|
tap do
|
|
|
|
return super(:ref, *args)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_super_in_block
|
|
|
|
bug7925 = '[ruby-core:52750] [Bug #7925]'
|
|
|
|
x = eval_using(SuperInBlock::R,
|
|
|
|
"TestRefinement:: SuperInBlock::C.new.foo(#{bug7925.dump})")
|
|
|
|
assert_equal([:foo, :ref, bug7925], x, bug7925)
|
|
|
|
end
|
|
|
|
|
2013-06-12 10:33:59 -04:00
|
|
|
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
|
|
|
|
|
2018-11-22 02:53:07 -05:00
|
|
|
def self.public_send_z_on(foo)
|
|
|
|
return foo.public_send(:z)
|
|
|
|
end
|
|
|
|
|
2013-06-12 10:33:59 -04:00
|
|
|
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
|
2015-03-04 21:56:03 -05:00
|
|
|
eval <<-EOF, Sandbox::BINDING
|
2013-06-12 10:33:59 -04:00
|
|
|
module TestRefinement::TestModuleUsingInvalidSelf
|
|
|
|
Module.new.send(:using, TestRefinement::FooExt)
|
|
|
|
end
|
|
|
|
EOF
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-06-30 23:57:16 -04:00
|
|
|
class Bar
|
|
|
|
end
|
|
|
|
|
|
|
|
module BarExt
|
|
|
|
refine Bar do
|
|
|
|
def x
|
|
|
|
return "BarExt#x"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module FooBarExt
|
|
|
|
include FooExt
|
|
|
|
include BarExt
|
|
|
|
end
|
|
|
|
|
|
|
|
module FooBarExtClient
|
|
|
|
using FooBarExt
|
|
|
|
|
|
|
|
def self.invoke_x_on(foo)
|
|
|
|
return foo.x
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_module_inclusion
|
|
|
|
foo = Foo.new
|
|
|
|
assert_equal("FooExt#x", FooBarExtClient.invoke_x_on(foo))
|
|
|
|
bar = Bar.new
|
|
|
|
assert_equal("BarExt#x", FooBarExtClient.invoke_x_on(bar))
|
|
|
|
end
|
|
|
|
|
|
|
|
module FooFoo2Ext
|
|
|
|
include FooExt
|
|
|
|
include FooExt2
|
|
|
|
end
|
|
|
|
|
|
|
|
module FooFoo2ExtClient
|
|
|
|
using FooFoo2Ext
|
|
|
|
|
|
|
|
def self.invoke_x_on(foo)
|
|
|
|
return foo.x
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.invoke_y_on(foo)
|
|
|
|
return foo.y
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_module_inclusion2
|
|
|
|
foo = Foo.new
|
|
|
|
assert_equal("FooExt2#x", FooFoo2ExtClient.invoke_x_on(foo))
|
|
|
|
assert_equal("FooExt2#y Foo#y", FooFoo2ExtClient.invoke_y_on(foo))
|
|
|
|
end
|
|
|
|
|
2013-08-06 03:15:18 -04:00
|
|
|
def test_eval_scoping
|
|
|
|
assert_in_out_err([], <<-INPUT, ["HELLO WORLD", "dlrow olleh", "HELLO WORLD"], [])
|
|
|
|
module M
|
|
|
|
refine String do
|
|
|
|
def upcase
|
|
|
|
reverse
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
puts "hello world".upcase
|
|
|
|
puts eval(%{using M; "hello world".upcase})
|
|
|
|
puts "hello world".upcase
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_eval_with_binding_scoping
|
2015-03-04 21:56:03 -05:00
|
|
|
assert_in_out_err([], <<-INPUT, ["HELLO WORLD", "dlrow olleh", "dlrow olleh"], [])
|
2013-08-06 03:15:18 -04:00
|
|
|
module M
|
|
|
|
refine String do
|
|
|
|
def upcase
|
|
|
|
reverse
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
puts "hello world".upcase
|
2015-03-04 21:56:03 -05:00
|
|
|
b = binding
|
|
|
|
puts eval(%{using M; "hello world".upcase}, b)
|
|
|
|
puts eval(%{"hello world".upcase}, b)
|
2013-08-06 03:15:18 -04:00
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2013-09-07 02:44:31 -04:00
|
|
|
def test_case_dispatch_is_aware_of_refinements
|
|
|
|
assert_in_out_err([], <<-RUBY, ["refinement used"], [])
|
|
|
|
module RefineSymbol
|
|
|
|
refine Symbol do
|
|
|
|
def ===(other)
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using RefineSymbol
|
|
|
|
|
|
|
|
case :a
|
|
|
|
when :b
|
|
|
|
puts "refinement used"
|
|
|
|
else
|
|
|
|
puts "refinement not used"
|
|
|
|
end
|
|
|
|
RUBY
|
|
|
|
end
|
|
|
|
|
2013-09-09 03:56:02 -04:00
|
|
|
def test_refine_after_using
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug8880 = '[ruby-core:57079] [Bug #8880]'
|
|
|
|
module Test
|
|
|
|
refine(String) do
|
|
|
|
end
|
|
|
|
end
|
|
|
|
using Test
|
|
|
|
def t
|
|
|
|
'Refinements are broken!'.chop!
|
|
|
|
end
|
|
|
|
t
|
|
|
|
module Test
|
|
|
|
refine(String) do
|
|
|
|
def chop!
|
|
|
|
self.sub!(/broken/, 'fine')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert_equal('Refinements are fine!', t, bug8880)
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2013-09-09 23:39:31 -04:00
|
|
|
def test_instance_methods
|
|
|
|
bug8881 = '[ruby-core:57080] [Bug #8881]'
|
|
|
|
assert_not_include(Foo.instance_methods(false), :z, bug8881)
|
|
|
|
assert_not_include(FooSub.instance_methods(true), :z, bug8881)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_method_defined
|
|
|
|
assert_not_send([Foo, :method_defined?, :z])
|
|
|
|
assert_not_send([FooSub, :method_defined?, :z])
|
|
|
|
end
|
|
|
|
|
2013-09-29 21:49:21 -04:00
|
|
|
def test_undef_refined_method
|
|
|
|
bug8966 = '[ruby-core:57466] [Bug #8966]'
|
|
|
|
|
|
|
|
assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966)
|
|
|
|
module Foo
|
|
|
|
refine Object do
|
|
|
|
def foo
|
|
|
|
puts "foo"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using Foo
|
|
|
|
|
|
|
|
class Object
|
|
|
|
begin
|
|
|
|
undef foo
|
|
|
|
rescue Exception => e
|
|
|
|
p e.class
|
|
|
|
end
|
|
|
|
end
|
|
|
|
INPUT
|
|
|
|
|
|
|
|
assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966)
|
|
|
|
module Foo
|
|
|
|
refine Object do
|
|
|
|
def foo
|
|
|
|
puts "foo"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# without `using Foo'
|
|
|
|
|
|
|
|
class Object
|
|
|
|
begin
|
|
|
|
undef foo
|
|
|
|
rescue Exception => e
|
|
|
|
p e.class
|
|
|
|
end
|
|
|
|
end
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2013-10-17 04:44:26 -04:00
|
|
|
def test_refine_undefed_method_and_call
|
|
|
|
assert_in_out_err([], <<-INPUT, ["NoMethodError"], [])
|
|
|
|
class Foo
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
|
|
|
|
undef foo
|
|
|
|
end
|
|
|
|
|
|
|
|
module FooExt
|
|
|
|
refine Foo do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
begin
|
|
|
|
Foo.new.foo
|
|
|
|
rescue => e
|
|
|
|
p e.class
|
|
|
|
end
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_undefed_method_and_send
|
|
|
|
assert_in_out_err([], <<-INPUT, ["NoMethodError"], [])
|
|
|
|
class Foo
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
|
|
|
|
undef foo
|
|
|
|
end
|
|
|
|
|
|
|
|
module FooExt
|
|
|
|
refine Foo do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
begin
|
|
|
|
Foo.new.send(:foo)
|
|
|
|
rescue => e
|
|
|
|
p e.class
|
|
|
|
end
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2014-02-13 09:44:41 -05:00
|
|
|
def test_adding_private_method
|
|
|
|
bug9452 = '[ruby-core:60111] [Bug #9452]'
|
|
|
|
|
|
|
|
assert_in_out_err([], <<-INPUT, ["Success!", "NoMethodError"], [], bug9452)
|
|
|
|
module R
|
|
|
|
refine Object do
|
|
|
|
def m
|
|
|
|
puts "Success!"
|
|
|
|
end
|
|
|
|
|
|
|
|
private(:m)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using R
|
|
|
|
|
|
|
|
m
|
|
|
|
42.m rescue p($!.class)
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_making_private_method_public
|
|
|
|
bug9452 = '[ruby-core:60111] [Bug #9452]'
|
|
|
|
|
|
|
|
assert_in_out_err([], <<-INPUT, ["Success!", "Success!"], [], bug9452)
|
|
|
|
class Object
|
|
|
|
private
|
|
|
|
def m
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module R
|
|
|
|
refine Object do
|
|
|
|
def m
|
|
|
|
puts "Success!"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using R
|
|
|
|
m
|
|
|
|
42.m
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2014-08-02 21:43:10 -04:00
|
|
|
def test_refine_basic_object
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug10106 = '[ruby-core:64166] [Bug #10106]'
|
|
|
|
module RefinementBug
|
|
|
|
refine BasicObject do
|
|
|
|
def foo
|
|
|
|
1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise(NoMethodError, bug10106) {Object.new.foo}
|
|
|
|
end;
|
2015-01-08 03:05:03 -05:00
|
|
|
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug10707 = '[ruby-core:67389] [Bug #10707]'
|
|
|
|
module RefinementBug
|
|
|
|
refine BasicObject do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert(methods, bug10707)
|
|
|
|
assert_raise(NameError, bug10707) {method(:foo)}
|
|
|
|
end;
|
2014-08-02 21:43:10 -04:00
|
|
|
end
|
|
|
|
|
2015-01-08 02:31:45 -05:00
|
|
|
def test_change_refined_new_method_visibility
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug10706 = '[ruby-core:67387] [Bug #10706]'
|
|
|
|
module RefinementBug
|
|
|
|
refine Object do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise(NameError, bug10706) {private(:foo)}
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2015-01-12 02:45:49 -05:00
|
|
|
def test_alias_refined_method
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug10731 = '[ruby-core:67523] [Bug #10731]'
|
|
|
|
|
|
|
|
class C
|
|
|
|
end
|
|
|
|
|
|
|
|
module RefinementBug
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
|
|
|
|
def bar
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise(NameError, bug10731) do
|
|
|
|
class C
|
|
|
|
alias foo bar
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2015-01-15 07:35:00 -05:00
|
|
|
def test_singleton_method_should_not_use_refinements
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug10744 = '[ruby-core:67603] [Bug #10744]'
|
|
|
|
|
|
|
|
class C
|
|
|
|
end
|
|
|
|
|
|
|
|
module RefinementBug
|
|
|
|
refine C.singleton_class do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise(NameError, bug10744) { C.singleton_method(:foo) }
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2015-01-18 01:57:34 -05:00
|
|
|
def test_refined_method_defined
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug10753 = '[ruby-core:67656] [Bug #10753]'
|
|
|
|
|
|
|
|
c = Class.new do
|
|
|
|
def refined_public; end
|
|
|
|
def refined_protected; end
|
|
|
|
def refined_private; end
|
|
|
|
|
|
|
|
public :refined_public
|
|
|
|
protected :refined_protected
|
|
|
|
private :refined_private
|
|
|
|
end
|
|
|
|
|
|
|
|
m = Module.new do
|
|
|
|
refine(c) do
|
|
|
|
def refined_public; end
|
|
|
|
def refined_protected; end
|
|
|
|
def refined_private; end
|
|
|
|
|
|
|
|
public :refined_public
|
|
|
|
protected :refined_protected
|
|
|
|
private :refined_private
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using m
|
|
|
|
|
|
|
|
assert_equal(true, c.public_method_defined?(:refined_public), bug10753)
|
|
|
|
assert_equal(false, c.public_method_defined?(:refined_protected), bug10753)
|
|
|
|
assert_equal(false, c.public_method_defined?(:refined_private), bug10753)
|
|
|
|
|
|
|
|
assert_equal(false, c.protected_method_defined?(:refined_public), bug10753)
|
|
|
|
assert_equal(true, c.protected_method_defined?(:refined_protected), bug10753)
|
|
|
|
assert_equal(false, c.protected_method_defined?(:refined_private), bug10753)
|
|
|
|
|
|
|
|
assert_equal(false, c.private_method_defined?(:refined_public), bug10753)
|
|
|
|
assert_equal(false, c.private_method_defined?(:refined_protected), bug10753)
|
|
|
|
assert_equal(true, c.private_method_defined?(:refined_private), bug10753)
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_undefined_refined_method_defined
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug10753 = '[ruby-core:67656] [Bug #10753]'
|
|
|
|
|
|
|
|
c = Class.new
|
|
|
|
|
|
|
|
m = Module.new do
|
|
|
|
refine(c) do
|
|
|
|
def undefined_refined_public; end
|
|
|
|
def undefined_refined_protected; end
|
|
|
|
def undefined_refined_private; end
|
|
|
|
public :undefined_refined_public
|
|
|
|
protected :undefined_refined_protected
|
|
|
|
private :undefined_refined_private
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using m
|
|
|
|
|
|
|
|
assert_equal(false, c.public_method_defined?(:undefined_refined_public), bug10753)
|
|
|
|
assert_equal(false, c.public_method_defined?(:undefined_refined_protected), bug10753)
|
|
|
|
assert_equal(false, c.public_method_defined?(:undefined_refined_private), bug10753)
|
|
|
|
|
|
|
|
assert_equal(false, c.protected_method_defined?(:undefined_refined_public), bug10753)
|
|
|
|
assert_equal(false, c.protected_method_defined?(:undefined_refined_protected), bug10753)
|
|
|
|
assert_equal(false, c.protected_method_defined?(:undefined_refined_private), bug10753)
|
|
|
|
|
|
|
|
assert_equal(false, c.private_method_defined?(:undefined_refined_public), bug10753)
|
|
|
|
assert_equal(false, c.private_method_defined?(:undefined_refined_protected), bug10753)
|
|
|
|
assert_equal(false, c.private_method_defined?(:undefined_refined_private), bug10753)
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2015-02-03 01:26:48 -05:00
|
|
|
def test_remove_refined_method
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug10765 = '[ruby-core:67722] [Bug #10765]'
|
|
|
|
|
|
|
|
class C
|
|
|
|
def foo
|
|
|
|
"C#foo"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module RefinementBug
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
"RefinementBug#foo"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using RefinementBug
|
|
|
|
|
|
|
|
class C
|
|
|
|
remove_method :foo
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_equal("RefinementBug#foo", C.new.foo, bug10765)
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_remove_undefined_refined_method
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
bug10765 = '[ruby-core:67722] [Bug #10765]'
|
|
|
|
|
|
|
|
class C
|
|
|
|
end
|
|
|
|
|
|
|
|
module RefinementBug
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using RefinementBug
|
|
|
|
|
|
|
|
assert_raise(NameError, bug10765) {
|
|
|
|
class C
|
|
|
|
remove_method :foo
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2015-02-04 02:45:29 -05:00
|
|
|
module NotIncludeSuperclassMethod
|
|
|
|
class X
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Y < X
|
|
|
|
end
|
|
|
|
|
|
|
|
module Bar
|
|
|
|
refine Y do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_instance_methods_not_include_superclass_method
|
|
|
|
bug10826 = '[ruby-dev:48854] [Bug #10826]'
|
|
|
|
assert_not_include(NotIncludeSuperclassMethod::Y.instance_methods(false),
|
|
|
|
:foo, bug10826)
|
|
|
|
assert_include(NotIncludeSuperclassMethod::Y.instance_methods(true),
|
|
|
|
:foo, bug10826)
|
|
|
|
end
|
|
|
|
|
2015-02-09 21:40:21 -05:00
|
|
|
def test_undef_original_method
|
|
|
|
assert_in_out_err([], <<-INPUT, ["NoMethodError"], [])
|
|
|
|
module NoPlus
|
|
|
|
refine String do
|
|
|
|
undef +
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using NoPlus
|
|
|
|
"a" + "b" rescue p($!.class)
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2017-01-18 00:23:53 -05:00
|
|
|
def test_undef_prepended_method
|
|
|
|
bug13096 = '[ruby-core:78944] [Bug #13096]'
|
|
|
|
klass = EnvUtil.labeled_class("X") do
|
|
|
|
def foo; end
|
|
|
|
end
|
|
|
|
klass.prepend(Module.new)
|
|
|
|
ext = EnvUtil.labeled_module("Ext") do
|
|
|
|
refine klass do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert_nothing_raised(NameError, bug13096) do
|
|
|
|
klass.class_eval do
|
|
|
|
undef :foo
|
|
|
|
end
|
|
|
|
end
|
2019-06-29 20:34:41 -04:00
|
|
|
ext
|
2017-01-18 00:23:53 -05:00
|
|
|
end
|
|
|
|
|
2015-02-22 02:05:14 -05:00
|
|
|
def test_call_refined_method_in_duplicate_module
|
|
|
|
bug10885 = '[ruby-dev:48878]'
|
|
|
|
assert_in_out_err([], <<-INPUT, [], [], bug10885)
|
|
|
|
module M
|
|
|
|
refine Object do
|
|
|
|
def raise
|
|
|
|
# do nothing
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class << self
|
|
|
|
using M
|
|
|
|
def m0
|
|
|
|
raise
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using M
|
|
|
|
def M.m1
|
|
|
|
raise
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
M.dup.m0
|
|
|
|
M.dup.m1
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2015-05-06 09:49:57 -04:00
|
|
|
def test_check_funcall_undefined
|
|
|
|
bug11117 = '[ruby-core:69064] [Bug #11117]'
|
|
|
|
|
|
|
|
x = Class.new
|
|
|
|
Module.new do
|
|
|
|
refine x do
|
|
|
|
def to_regexp
|
|
|
|
//
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_nothing_raised(NoMethodError, bug11117) {
|
|
|
|
assert_nil(Regexp.try_convert(x.new))
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2015-05-07 23:11:35 -04:00
|
|
|
def test_funcall_inherited
|
|
|
|
bug11117 = '[ruby-core:69064] [Bug #11117]'
|
|
|
|
|
|
|
|
Module.new {refine(Dir) {def to_s; end}}
|
|
|
|
x = Class.new(Dir).allocate
|
|
|
|
assert_nothing_raised(NoMethodError, bug11117) {
|
|
|
|
x.inspect
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2015-05-26 09:16:18 -04:00
|
|
|
def test_alias_refined_method2
|
|
|
|
bug11182 = '[ruby-core:69360]'
|
|
|
|
assert_in_out_err([], <<-INPUT, ["C"], [], bug11182)
|
|
|
|
class C
|
|
|
|
def foo
|
|
|
|
puts "C"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M
|
|
|
|
refine C do
|
|
|
|
def foo
|
2015-08-10 21:33:32 -04:00
|
|
|
puts "Refined C"
|
2015-05-26 09:16:18 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class D < C
|
|
|
|
alias bar foo
|
|
|
|
end
|
|
|
|
|
|
|
|
using M
|
|
|
|
D.new.bar
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2015-11-09 10:57:07 -05:00
|
|
|
def test_reopen_refinement_module
|
|
|
|
assert_separately([], <<-"end;")
|
|
|
|
class C
|
|
|
|
end
|
|
|
|
|
|
|
|
module R
|
|
|
|
refine C do
|
|
|
|
def m
|
|
|
|
:foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using R
|
|
|
|
assert_equal(:foo, C.new.m)
|
|
|
|
|
|
|
|
module R
|
|
|
|
refine C do
|
2020-12-17 06:06:18 -05:00
|
|
|
alias m m
|
2015-11-09 10:57:07 -05:00
|
|
|
def m
|
|
|
|
:bar
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-11-09 17:25:10 -05:00
|
|
|
assert_equal(:bar, C.new.m, "[ruby-core:71423] [Bug #11672]")
|
2015-11-09 10:57:07 -05:00
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2015-11-19 19:17:25 -05:00
|
|
|
module MixedUsing1
|
|
|
|
class C
|
|
|
|
def foo
|
|
|
|
:orig_foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module R1
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
[:R1, super]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module_function
|
|
|
|
|
|
|
|
def foo
|
|
|
|
[:foo, C.new.foo]
|
|
|
|
end
|
|
|
|
|
|
|
|
using R1
|
|
|
|
|
|
|
|
def bar
|
|
|
|
[:bar, C.new.foo]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module MixedUsing2
|
|
|
|
class C
|
|
|
|
def foo
|
|
|
|
:orig_foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module R1
|
|
|
|
refine C do
|
|
|
|
def foo
|
|
|
|
[:R1_foo, super]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module R2
|
|
|
|
refine C do
|
|
|
|
def bar
|
|
|
|
[:R2_bar, C.new.foo]
|
|
|
|
end
|
|
|
|
|
|
|
|
using R1
|
|
|
|
|
|
|
|
def baz
|
|
|
|
[:R2_baz, C.new.foo]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using R2
|
|
|
|
module_function
|
|
|
|
def f1; C.new.bar; end
|
|
|
|
def f2; C.new.baz; end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_mixed_using
|
|
|
|
assert_equal([:foo, :orig_foo], MixedUsing1.foo)
|
|
|
|
assert_equal([:bar, [:R1, :orig_foo]], MixedUsing1.bar)
|
|
|
|
|
|
|
|
assert_equal([:R2_bar, :orig_foo], MixedUsing2.f1)
|
|
|
|
assert_equal([:R2_baz, [:R1_foo, :orig_foo]], MixedUsing2.f2)
|
|
|
|
end
|
|
|
|
|
2015-12-12 10:08:52 -05:00
|
|
|
module MethodMissing
|
|
|
|
class Foo
|
|
|
|
end
|
|
|
|
|
|
|
|
module Bar
|
|
|
|
refine Foo do
|
|
|
|
def method_missing(mid, *args)
|
|
|
|
"method_missing refined"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using Bar
|
|
|
|
|
|
|
|
def self.call_undefined_method
|
|
|
|
Foo.new.foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_method_missing
|
|
|
|
assert_raise(NoMethodError) do
|
|
|
|
MethodMissing.call_undefined_method
|
|
|
|
end
|
|
|
|
end
|
2016-09-07 12:15:46 -04:00
|
|
|
|
2016-09-07 12:15:45 -04:00
|
|
|
module VisibleRefinements
|
|
|
|
module RefA
|
|
|
|
refine Object do
|
|
|
|
def in_ref_a
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module RefB
|
|
|
|
refine Object do
|
|
|
|
def in_ref_b
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module RefC
|
|
|
|
using RefA
|
2016-09-07 12:15:46 -04:00
|
|
|
|
2016-09-07 12:15:45 -04:00
|
|
|
refine Object do
|
|
|
|
def in_ref_c
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module Foo
|
|
|
|
using RefB
|
2016-09-08 03:49:02 -04:00
|
|
|
USED_MODS = Module.used_modules
|
2016-09-07 12:15:45 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
module Bar
|
|
|
|
using RefC
|
2016-09-08 03:49:02 -04:00
|
|
|
USED_MODS = Module.used_modules
|
2016-09-07 12:15:45 -04:00
|
|
|
end
|
2016-09-07 12:15:46 -04:00
|
|
|
|
2016-09-07 12:15:45 -04:00
|
|
|
module Combined
|
|
|
|
using RefA
|
|
|
|
using RefB
|
2016-09-08 03:49:02 -04:00
|
|
|
USED_MODS = Module.used_modules
|
2016-09-07 12:15:45 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-09-08 03:49:02 -04:00
|
|
|
def test_used_modules
|
2016-09-07 12:15:45 -04:00
|
|
|
ref = VisibleRefinements
|
2016-09-08 03:49:02 -04:00
|
|
|
assert_equal [], Module.used_modules
|
|
|
|
assert_equal [ref::RefB], ref::Foo::USED_MODS
|
|
|
|
assert_equal [ref::RefC], ref::Bar::USED_MODS
|
|
|
|
assert_equal [ref::RefB, ref::RefA], ref::Combined::USED_MODS
|
2016-09-07 12:15:45 -04:00
|
|
|
end
|
2015-12-12 10:08:52 -05:00
|
|
|
|
2016-09-08 00:44:51 -04:00
|
|
|
def test_warn_setconst_in_refinmenet
|
|
|
|
bug10103 = '[ruby-core:64143] [Bug #10103]'
|
|
|
|
warnings = [
|
|
|
|
"-:3: warning: not defined at the refinement, but at the outer class/module",
|
|
|
|
"-:4: warning: not defined at the refinement, but at the outer class/module"
|
|
|
|
]
|
|
|
|
assert_in_out_err([], <<-INPUT, [], warnings, bug10103)
|
|
|
|
module M
|
|
|
|
refine String do
|
|
|
|
FOO = 123
|
|
|
|
@@foo = 456
|
|
|
|
end
|
|
|
|
end
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2016-10-15 18:59:39 -04:00
|
|
|
def test_symbol_proc
|
|
|
|
assert_equal("FooExt#x", FooExtClient.map_x_on(Foo.new))
|
2016-10-22 22:03:56 -04:00
|
|
|
assert_equal("Foo#x", FooExtClient.return_proc(&:x).(Foo.new))
|
2016-10-15 18:59:39 -04:00
|
|
|
end
|
|
|
|
|
2017-03-18 10:22:15 -04:00
|
|
|
def test_symbol_proc_with_block
|
|
|
|
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
|
|
|
|
bug = '[ruby-core:80219] [Bug #13325]'
|
|
|
|
begin;
|
|
|
|
module M
|
|
|
|
refine Class.new do
|
|
|
|
end
|
|
|
|
end
|
|
|
|
class C
|
|
|
|
def call(a, x, &b)
|
|
|
|
b.call(a, &x)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
o = C.new
|
|
|
|
r = nil
|
|
|
|
x = ->(z){r = z}
|
|
|
|
assert_equal(42, o.call(42, x, &:tap))
|
|
|
|
assert_equal(42, r)
|
|
|
|
using M
|
|
|
|
r = nil
|
|
|
|
assert_equal(42, o.call(42, x, &:tap), bug)
|
|
|
|
assert_equal(42, r, bug)
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2016-11-04 22:57:40 -04:00
|
|
|
module AliasInSubclass
|
|
|
|
class C
|
|
|
|
def foo
|
|
|
|
:original
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class D < C
|
|
|
|
alias bar foo
|
|
|
|
end
|
|
|
|
|
|
|
|
module M
|
|
|
|
refine D do
|
|
|
|
def bar
|
|
|
|
:refined
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_alias_in_subclass
|
|
|
|
assert_equal(:refined,
|
|
|
|
eval_using(AliasInSubclass::M, "AliasInSubclass::D.new.bar"))
|
|
|
|
end
|
|
|
|
|
2016-11-10 09:18:52 -05:00
|
|
|
def test_refine_with_prepend
|
|
|
|
assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
|
|
|
|
begin;
|
|
|
|
bug = '[ruby-core:78073] [Bug #12920]'
|
|
|
|
Integer.prepend(Module.new)
|
|
|
|
Module.new do
|
|
|
|
refine Integer do
|
|
|
|
define_method(:+) {}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert_kind_of(Time, Time.now, bug)
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2016-12-08 00:16:33 -05:00
|
|
|
def test_public_in_refine
|
|
|
|
assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
|
|
|
|
begin;
|
|
|
|
bug12729 = '[ruby-core:77161] [Bug #12729]'
|
|
|
|
|
|
|
|
class Cow
|
|
|
|
private
|
|
|
|
def moo() "Moo"; end
|
|
|
|
end
|
|
|
|
|
|
|
|
module PublicCows
|
|
|
|
refine(Cow) {
|
|
|
|
public :moo
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
using PublicCows
|
|
|
|
assert_equal("Moo", Cow.new.moo, bug12729)
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2017-02-18 20:27:52 -05:00
|
|
|
module SuperToModule
|
|
|
|
class Parent
|
|
|
|
end
|
|
|
|
|
|
|
|
class Child < Parent
|
|
|
|
end
|
|
|
|
|
|
|
|
module FooBar
|
|
|
|
refine Parent do
|
|
|
|
def to_s
|
|
|
|
"Parent"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
refine Child do
|
|
|
|
def to_s
|
|
|
|
super + " -> Child"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using FooBar
|
|
|
|
def Child.test
|
|
|
|
new.to_s
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_super_to_module
|
|
|
|
bug = '[ruby-core:79588] [Bug #13227]'
|
|
|
|
assert_equal("Parent -> Child", SuperToModule::Child.test, bug)
|
|
|
|
end
|
|
|
|
|
2017-03-24 23:23:43 -04:00
|
|
|
def test_include_refinement
|
|
|
|
bug = '[ruby-core:79632] [Bug #13236] cannot include refinement module'
|
|
|
|
r = nil
|
|
|
|
m = Module.new do
|
|
|
|
r = refine(String) {def test;:ok end}
|
|
|
|
end
|
|
|
|
assert_raise_with_message(ArgumentError, /refinement/, bug) do
|
|
|
|
m.module_eval {include r}
|
|
|
|
end
|
|
|
|
assert_raise_with_message(ArgumentError, /refinement/, bug) do
|
|
|
|
m.module_eval {prepend r}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-07-29 08:42:42 -04:00
|
|
|
class ParentDefiningPrivateMethod
|
|
|
|
private
|
|
|
|
def some_inherited_method
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module MixinDefiningPrivateMethod
|
|
|
|
private
|
|
|
|
def some_included_method
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class SomeChildClassToRefine < ParentDefiningPrivateMethod
|
|
|
|
include MixinDefiningPrivateMethod
|
|
|
|
|
|
|
|
private
|
|
|
|
def some_method
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_inherited_method_with_visibility_changes
|
|
|
|
Module.new do
|
|
|
|
refine(SomeChildClassToRefine) do
|
|
|
|
def some_inherited_method; end
|
|
|
|
def some_included_method; end
|
|
|
|
def some_method; end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
obj = SomeChildClassToRefine.new
|
|
|
|
|
|
|
|
assert_raise_with_message(NoMethodError, /private/) do
|
|
|
|
obj.some_inherited_method
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise_with_message(NoMethodError, /private/) do
|
|
|
|
obj.some_included_method
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_raise_with_message(NoMethodError, /private/) do
|
|
|
|
obj.some_method
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-08-17 10:58:11 -04:00
|
|
|
def test_refined_method_alias_warning
|
|
|
|
c = Class.new do
|
|
|
|
def t; :t end
|
|
|
|
def f; :f end
|
|
|
|
end
|
|
|
|
Module.new do
|
|
|
|
refine(c) do
|
|
|
|
alias foo t
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert_warning('', '[ruby-core:82385] [Bug #13817] refined method is not redefined') do
|
|
|
|
c.class_eval do
|
|
|
|
alias foo f
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-09-30 08:26:23 -04:00
|
|
|
def test_using_wrong_argument
|
|
|
|
bug = '[ruby-dev:50270] [Bug #13956]'
|
|
|
|
pattern = /expected Module/
|
|
|
|
assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}")
|
|
|
|
bug = ""#{bug.dump}
|
|
|
|
pattern = /#{pattern}/
|
|
|
|
begin;
|
|
|
|
assert_raise_with_message(TypeError, pattern, bug) {
|
|
|
|
using(1) do end
|
|
|
|
}
|
|
|
|
end;
|
|
|
|
assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}")
|
|
|
|
bug = ""#{bug.dump}
|
|
|
|
pattern = /#{pattern}/
|
|
|
|
begin;
|
|
|
|
assert_raise_with_message(TypeError, pattern, bug) {
|
|
|
|
Module.new {using(1) {}}
|
|
|
|
}
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
|
2017-09-17 22:27:13 -04:00
|
|
|
class ToString
|
|
|
|
c = self
|
|
|
|
using Module.new {refine(c) {def to_s; "ok"; end}}
|
|
|
|
def string
|
|
|
|
"#{self}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_tostring
|
|
|
|
assert_equal("ok", ToString.new.string)
|
|
|
|
end
|
|
|
|
|
2017-09-30 22:24:11 -04:00
|
|
|
class ToSymbol
|
|
|
|
c = self
|
|
|
|
using Module.new {refine(c) {def intern; "<#{upcase}>"; end}}
|
|
|
|
def symbol
|
|
|
|
:"#{@string}"
|
|
|
|
end
|
|
|
|
def initialize(string)
|
|
|
|
@string = string
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_dsym_literal
|
|
|
|
assert_equal(:foo, ToSymbol.new("foo").symbol)
|
|
|
|
end
|
|
|
|
|
2018-01-24 01:25:02 -05:00
|
|
|
module ToProc
|
|
|
|
def self.call &block
|
|
|
|
block.call
|
|
|
|
end
|
|
|
|
|
|
|
|
class ReturnProc
|
|
|
|
c = self
|
|
|
|
using Module.new {
|
|
|
|
refine c do
|
|
|
|
def to_proc
|
|
|
|
proc { "to_proc" }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
def call
|
2019-06-01 08:20:21 -04:00
|
|
|
ToProc.call(&self)
|
2018-01-24 01:25:02 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class ReturnNoProc
|
|
|
|
c = self
|
|
|
|
using Module.new {
|
|
|
|
refine c do
|
|
|
|
def to_proc
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
def call
|
2019-06-01 08:20:21 -04:00
|
|
|
ToProc.call(&self)
|
2018-01-24 01:25:02 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class PrivateToProc
|
|
|
|
c = self
|
|
|
|
using Module.new {
|
|
|
|
refine c do
|
|
|
|
private
|
|
|
|
def to_proc
|
|
|
|
proc { "private_to_proc" }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
def call
|
2019-06-01 08:20:21 -04:00
|
|
|
ToProc.call(&self)
|
2018-01-24 01:25:02 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
class NonProc
|
|
|
|
def call
|
2019-06-01 08:20:21 -04:00
|
|
|
ToProc.call(&self)
|
2018-01-24 01:25:02 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class MethodMissing
|
|
|
|
def method_missing *args
|
|
|
|
proc { "method_missing" }
|
|
|
|
end
|
|
|
|
|
|
|
|
def call
|
2019-06-01 08:20:21 -04:00
|
|
|
ToProc.call(&self)
|
2018-01-24 01:25:02 -05:00
|
|
|
end
|
2019-06-01 08:23:24 -04:00
|
|
|
end
|
2018-01-24 01:25:02 -05:00
|
|
|
|
|
|
|
class ToProcAndMethodMissing
|
|
|
|
def method_missing *args
|
|
|
|
proc { "method_missing" }
|
|
|
|
end
|
|
|
|
|
|
|
|
c = self
|
|
|
|
using Module.new {
|
|
|
|
refine c do
|
|
|
|
def to_proc
|
|
|
|
proc { "to_proc" }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
def call
|
2019-06-01 08:20:21 -04:00
|
|
|
ToProc.call(&self)
|
2018-01-24 01:25:02 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class ToProcAndRefinements
|
|
|
|
def to_proc
|
|
|
|
proc { "to_proc" }
|
|
|
|
end
|
|
|
|
|
|
|
|
c = self
|
|
|
|
using Module.new {
|
|
|
|
refine c do
|
|
|
|
def to_proc
|
|
|
|
proc { "refinements_to_proc" }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
def call
|
2019-06-01 08:20:21 -04:00
|
|
|
ToProc.call(&self)
|
2018-01-24 01:25:02 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_to_proc
|
|
|
|
assert_equal("to_proc", ToProc::ReturnProc.new.call)
|
|
|
|
assert_equal("private_to_proc", ToProc::PrivateToProc.new.call)
|
|
|
|
assert_raise(TypeError){ ToProc::ReturnNoProc.new.call }
|
|
|
|
assert_raise(TypeError){ ToProc::NonProc.new.call }
|
|
|
|
assert_equal("method_missing", ToProc::MethodMissing.new.call)
|
|
|
|
assert_equal("to_proc", ToProc::ToProcAndMethodMissing.new.call)
|
|
|
|
assert_equal("refinements_to_proc", ToProc::ToProcAndRefinements.new.call)
|
|
|
|
end
|
|
|
|
|
2017-11-29 03:39:47 -05:00
|
|
|
def test_unused_refinement_for_module
|
|
|
|
bug14068 = '[ruby-core:83613] [Bug #14068]'
|
|
|
|
assert_in_out_err([], <<-INPUT, ["M1#foo"], [], bug14068)
|
|
|
|
module M1
|
|
|
|
def foo
|
|
|
|
puts "M1#foo"
|
|
|
|
end
|
|
|
|
end
|
2017-11-29 03:39:48 -05:00
|
|
|
|
2017-11-29 03:39:47 -05:00
|
|
|
module M2
|
|
|
|
end
|
2017-11-29 03:39:48 -05:00
|
|
|
|
2017-11-29 03:39:47 -05:00
|
|
|
module UnusedRefinement
|
|
|
|
refine(M2) do
|
|
|
|
def foo
|
|
|
|
puts "M2#foo"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-11-29 03:39:48 -05:00
|
|
|
|
2017-11-29 03:39:47 -05:00
|
|
|
include M1
|
|
|
|
include M2
|
|
|
|
foo()
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2017-12-02 05:54:39 -05:00
|
|
|
def test_refining_module_repeatedly
|
|
|
|
bug14070 = '[ruby-core:83617] [Bug #14070]'
|
|
|
|
assert_in_out_err([], <<-INPUT, ["ok"], [], bug14070)
|
|
|
|
1000.times do
|
|
|
|
Class.new do
|
|
|
|
include Enumerable
|
|
|
|
end
|
|
|
|
|
|
|
|
Module.new do
|
|
|
|
refine Enumerable do
|
|
|
|
def foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
puts "ok"
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2019-06-10 18:47:56 -04:00
|
|
|
def test_call_method_in_unused_refinement
|
|
|
|
bug15720 = '[ruby-core:91916] [Bug #15720]'
|
|
|
|
assert_in_out_err([], <<-INPUT, ["ok"], [], bug15720)
|
|
|
|
module M1
|
|
|
|
refine Kernel do
|
|
|
|
def foo
|
|
|
|
'foo called!'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M2
|
|
|
|
refine Kernel do
|
|
|
|
def bar
|
|
|
|
'bar called!'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using M1
|
|
|
|
|
|
|
|
foo
|
|
|
|
|
|
|
|
begin
|
|
|
|
bar
|
|
|
|
rescue NameError
|
|
|
|
end
|
|
|
|
|
|
|
|
puts "ok"
|
|
|
|
INPUT
|
|
|
|
end
|
|
|
|
|
2017-12-26 05:32:58 -05:00
|
|
|
def test_super_from_refined_module
|
|
|
|
a = EnvUtil.labeled_module("A") do
|
|
|
|
def foo;"[A#{super}]";end
|
|
|
|
end
|
|
|
|
b = EnvUtil.labeled_class("B") do
|
|
|
|
def foo;"[B]";end
|
|
|
|
end
|
|
|
|
c = EnvUtil.labeled_class("C", b) do
|
|
|
|
include a
|
|
|
|
def foo;"[C#{super}]";end
|
|
|
|
end
|
|
|
|
d = EnvUtil.labeled_module("D") do
|
|
|
|
refine(a) do
|
|
|
|
def foo;end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert_equal("[C[A[B]]]", c.new.foo, '[ruby-dev:50390] [Bug #14232]')
|
2019-06-29 20:34:41 -04:00
|
|
|
d
|
2017-12-26 05:32:58 -05:00
|
|
|
end
|
|
|
|
|
2019-08-16 11:17:15 -04:00
|
|
|
class RefineInUsing
|
|
|
|
module M1
|
|
|
|
refine RefineInUsing do
|
|
|
|
def foo
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module M2
|
|
|
|
using M1
|
|
|
|
refine RefineInUsing do
|
|
|
|
def call_foo
|
|
|
|
RefineInUsing.new.foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using M2
|
|
|
|
def self.test
|
|
|
|
new.call_foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_in_using
|
|
|
|
assert_equal(:ok, RefineInUsing.test)
|
|
|
|
end
|
|
|
|
|
2019-10-12 03:01:37 -04:00
|
|
|
class Bug16242
|
|
|
|
module OtherM
|
|
|
|
end
|
|
|
|
|
|
|
|
module M
|
|
|
|
prepend OtherM
|
|
|
|
|
|
|
|
refine M do
|
|
|
|
def refine_method
|
|
|
|
"refine_method"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
using M
|
|
|
|
|
|
|
|
def hoge
|
|
|
|
refine_method
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class X
|
|
|
|
include M
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_prepended_module
|
|
|
|
assert_equal("refine_method", Bug16242::X.new.hoge)
|
|
|
|
end
|
|
|
|
|
Make prepending a refined module after inclusion not break refinements
After the previous commit, this was still broken. The reason it
was broken is that a refined module that hasn't been prepended to
yet keeps the refined methods in the module's method table. When
prepending, the module's method table is moved to the origin
iclass, and then the refined methods are moved from the method
table to a new method table in the module itself.
Unfortunately, that means that if a class has included the module,
prepending breaks the refinements, because when the methods are
moved from the origin iclass method table to the module method
table, they are removed from the method table from the iclass
created when the module was included earlier.
Fix this by always creating an origin class when including a
module that has any refinements, even if the refinements are
not currently used. I wasn't sure the best way to do that.
The approach I choose was to use an object flag. The flag is
set on the module when Module#refine is called, and if the
flag is present when the module is included in another module
or class, an origin iclass is created for the module.
Fixes [Bug #13446]
2019-10-12 04:02:51 -04:00
|
|
|
module Bug13446
|
|
|
|
module Enumerable
|
|
|
|
def sum(*args)
|
|
|
|
i = 0
|
|
|
|
args.each { |arg| i += a }
|
|
|
|
i
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using Module.new {
|
|
|
|
refine Enumerable do
|
|
|
|
alias :orig_sum :sum
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
module Enumerable
|
|
|
|
def sum(*args)
|
|
|
|
orig_sum(*args)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class GenericEnumerable
|
|
|
|
include Enumerable
|
|
|
|
end
|
|
|
|
|
|
|
|
Enumerable.prepend(Module.new)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_prepend_refined_module
|
|
|
|
assert_equal(0, Bug13446::GenericEnumerable.new.sum)
|
|
|
|
end
|
|
|
|
|
2020-02-09 06:13:49 -05:00
|
|
|
def test_unbound_refine_method
|
|
|
|
a = EnvUtil.labeled_class("A") do
|
|
|
|
def foo
|
|
|
|
self.class
|
|
|
|
end
|
|
|
|
end
|
|
|
|
b = EnvUtil.labeled_class("B")
|
|
|
|
bar = EnvUtil.labeled_module("R") do
|
|
|
|
break refine a do
|
|
|
|
def foo
|
|
|
|
super
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert_raise(TypeError) do
|
|
|
|
bar.instance_method(:foo).bind(b.new)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-06-01 18:54:47 -04:00
|
|
|
def test_refine_frozen_class
|
2020-06-18 21:45:13 -04:00
|
|
|
verbose_bak, $VERBOSE = $VERBOSE, nil
|
2020-06-01 18:54:47 -04:00
|
|
|
singleton_class.instance_variable_set(:@x, self)
|
|
|
|
class << self
|
|
|
|
c = Class.new do
|
|
|
|
def foo
|
|
|
|
:cfoo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
foo = Module.new do
|
|
|
|
refine c do
|
|
|
|
def foo
|
|
|
|
:rfoo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
using foo
|
|
|
|
@x.assert_equal(:rfoo, c.new.foo)
|
|
|
|
c.freeze
|
|
|
|
foo.module_eval do
|
|
|
|
refine c do
|
|
|
|
def foo
|
|
|
|
:rfoo2
|
|
|
|
end
|
|
|
|
def bar
|
|
|
|
:rbar
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
@x.assert_equal(:rfoo2, c.new.foo)
|
|
|
|
@x.assert_equal(:rbar, c.new.bar, '[ruby-core:71391] [Bug #11669]')
|
|
|
|
end
|
2020-06-18 21:45:13 -04:00
|
|
|
ensure
|
|
|
|
$VERBOSE = verbose_bak
|
2020-06-01 18:54:47 -04:00
|
|
|
end
|
|
|
|
|
2020-12-18 14:30:25 -05:00
|
|
|
# [Bug #17386]
|
|
|
|
def test_prepended_with_method_cache
|
|
|
|
foo = Class.new do
|
|
|
|
def foo
|
|
|
|
:Foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
code = Module.new do
|
|
|
|
def foo
|
|
|
|
:Code
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
_ext = Module.new do
|
|
|
|
refine foo do
|
|
|
|
def foo; end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
obj = foo.new
|
|
|
|
|
|
|
|
assert_equal :Foo, obj.foo
|
|
|
|
foo.prepend code
|
|
|
|
assert_equal :Code, obj.foo
|
|
|
|
end
|
2020-12-21 15:27:47 -05:00
|
|
|
|
|
|
|
# [Bug #17417]
|
|
|
|
def test_prepended_with_method_cache_17417
|
|
|
|
assert_normal_exit %q{
|
|
|
|
module M
|
|
|
|
def hoge; end
|
|
|
|
end
|
|
|
|
|
|
|
|
module R
|
|
|
|
refine Hash do
|
|
|
|
def except *args; end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
h = {}
|
|
|
|
h.method(:except) # put it on pCMC
|
|
|
|
Hash.prepend(M)
|
|
|
|
h.method(:except)
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2021-05-11 12:05:06 -04:00
|
|
|
def test_defining_after_cached
|
|
|
|
klass = Class.new
|
2021-05-14 02:44:13 -04:00
|
|
|
_refinement = Module.new { refine(klass) { def foo; end } }
|
2021-05-11 12:05:06 -04:00
|
|
|
klass.new.foo rescue nil # cache the refinement method entry
|
|
|
|
klass.define_method(:foo) { 42 }
|
|
|
|
assert_equal(42, klass.new.foo)
|
|
|
|
end
|
|
|
|
|
|
|
|
# [Bug #17806]
|
|
|
|
def test_two_refinements_for_prepended_class
|
|
|
|
assert_normal_exit %q{
|
|
|
|
module R1
|
|
|
|
refine Hash do
|
|
|
|
def foo; :r1; end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Hash
|
|
|
|
prepend(Module.new)
|
|
|
|
end
|
|
|
|
|
|
|
|
class Hash
|
|
|
|
def foo; end
|
|
|
|
end
|
|
|
|
|
|
|
|
{}.method(:foo) # put it on pCMC
|
|
|
|
|
|
|
|
module R2
|
|
|
|
refine Hash do
|
|
|
|
def foo; :r2; end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
{}.foo
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
# [Bug #17806]
|
|
|
|
def test_redefining_refined_for_prepended_class
|
|
|
|
klass = Class.new { def foo; end }
|
|
|
|
_refinement = Module.new do
|
|
|
|
refine(klass) { def foo; :refined; end }
|
|
|
|
end
|
|
|
|
klass.prepend(Module.new)
|
|
|
|
klass.new.foo # cache foo
|
|
|
|
klass.define_method(:foo) { :second }
|
|
|
|
assert_equal(:second, klass.new.foo)
|
|
|
|
end
|
|
|
|
|
2021-09-30 18:18:14 -04:00
|
|
|
class Bug18180
|
|
|
|
module M
|
|
|
|
refine Array do
|
|
|
|
def min; :min; end
|
|
|
|
def max; :max; end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
using M
|
|
|
|
|
|
|
|
def t
|
|
|
|
[[1+0, 2, 4].min, [1, 2, 4].min, [1+0, 2, 4].max, [1, 2, 4].max]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_refine_array_min_max
|
|
|
|
assert_equal([:min, :min, :max, :max], Bug18180.new.t)
|
|
|
|
end
|
|
|
|
|
2021-05-20 18:52:32 -04:00
|
|
|
class Bug17822
|
|
|
|
module Ext
|
|
|
|
refine(Bug17822) do
|
|
|
|
def foo = :refined
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private(def foo = :not_refined)
|
|
|
|
|
|
|
|
module Client
|
|
|
|
using Ext
|
|
|
|
def self.call_foo
|
|
|
|
Bug17822.new.foo
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# [Bug #17822]
|
|
|
|
def test_privatizing_refined_method
|
|
|
|
assert_equal(:refined, Bug17822::Client.call_foo)
|
|
|
|
end
|
|
|
|
|
2021-08-19 21:42:01 -04:00
|
|
|
def test_ancestors
|
|
|
|
refinement = nil
|
|
|
|
as = nil
|
|
|
|
Module.new do
|
|
|
|
refine Array do
|
|
|
|
refinement = self
|
|
|
|
as = ancestors
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert_equal([refinement], as, "[ruby-core:86949] [Bug #14744]")
|
|
|
|
end
|
|
|
|
|
2020-12-21 15:27:47 -05:00
|
|
|
private
|
|
|
|
|
|
|
|
def eval_using(mod, s)
|
|
|
|
eval("using #{mod}; #{s}", Sandbox::BINDING)
|
|
|
|
end
|
2012-09-27 05:53:24 -04:00
|
|
|
end
|