mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 9996945af9
			
		
	
	
		9996945af9
		
	
	
	
	
		
			
			* vm_eval.c (vm_call0_body): refined module should not be skipped as prepended. [ruby-core:78073] [Bug #12920] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56694 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			1797 lines
		
	
	
	
		
			34 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			1797 lines
		
	
	
	
		
			34 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # frozen_string_literal: false
 | |
| require 'test/unit'
 | |
| 
 | |
| class TestRefinement < Test::Unit::TestCase
 | |
|   module Sandbox
 | |
|     BINDING = binding
 | |
|   end
 | |
| 
 | |
|   class Foo
 | |
|     def x
 | |
|       return "Foo#x"
 | |
|     end
 | |
| 
 | |
|     def y
 | |
|       return "Foo#y"
 | |
|     end
 | |
| 
 | |
|     def a
 | |
|       return "Foo#a"
 | |
|     end
 | |
| 
 | |
|     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
 | |
| 
 | |
|       def a
 | |
|         return "FooExt#a"
 | |
|       end
 | |
|     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
 | |
| 
 | |
|   class FooExtClient
 | |
|     using TestRefinement::FooExt
 | |
| 
 | |
|     begin
 | |
|       def self.map_x_on(foo)
 | |
|         [foo].map(&:x)[0]
 | |
|       end
 | |
| 
 | |
|       def self.invoke_x_on(foo)
 | |
|         return foo.x
 | |
|       end
 | |
| 
 | |
|       def self.invoke_y_on(foo)
 | |
|         return foo.y
 | |
|       end
 | |
| 
 | |
|       def self.invoke_z_on(foo)
 | |
|         return foo.z
 | |
|       end
 | |
| 
 | |
|       def self.send_z_on(foo)
 | |
|         return foo.send(:z)
 | |
|       end
 | |
| 
 | |
|       def self.method_z(foo)
 | |
|         return foo.method(:z)
 | |
|       end
 | |
| 
 | |
|       def self.invoke_call_x_on(foo)
 | |
|         return foo.call_x
 | |
|       end
 | |
| 
 | |
|       def self.return_proc(&block)
 | |
|         block
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   class TestRefinement::FooExtClient2
 | |
|     using TestRefinement::FooExt
 | |
|     using TestRefinement::FooExt2
 | |
| 
 | |
|     begin
 | |
|       def self.invoke_y_on(foo)
 | |
|         return foo.y
 | |
|       end
 | |
| 
 | |
|       def self.invoke_a_on(foo)
 | |
|         return foo.a
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   def test_super_not_chained
 | |
|     foo = Foo.new
 | |
|     assert_equal("Foo#y", foo.y)
 | |
|     assert_equal("FooExt2#y Foo#y", FooExtClient2.invoke_y_on(foo))
 | |
|     assert_equal("Foo#y", foo.y)
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   module RespondTo
 | |
|     class Super
 | |
|       def foo
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     class Sub < Super
 | |
|     end
 | |
| 
 | |
|     module M
 | |
|       refine Sub do
 | |
|         def foo
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_send_should_use_refinements
 | |
|     foo = Foo.new
 | |
|     assert_raise(NoMethodError) { foo.send(:z) }
 | |
|     assert_equal("FooExt#z", FooExtClient.send_z_on(foo))
 | |
|     assert_raise(NoMethodError) { foo.send(:z) }
 | |
| 
 | |
|     assert_equal(true, RespondTo::Sub.new.respond_to?(:foo))
 | |
|   end
 | |
| 
 | |
|   def test_method_should_not_use_refinements
 | |
|     foo = Foo.new
 | |
|     assert_raise(NameError) { foo.method(:z) }
 | |
|     assert_raise(NameError) { FooExtClient.method_z(foo) }
 | |
|     assert_raise(NameError) { foo.method(:z) }
 | |
|   end
 | |
| 
 | |
|   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)
 | |
|     assert_equal("Foo#x", FooExt.module_eval { foo.x })
 | |
|     assert_equal("Foo#x", FooExt.module_eval("foo.x"))
 | |
|     assert_equal("Foo#x", foo.x)
 | |
|   end
 | |
| 
 | |
|   def test_instance_eval_without_refinement
 | |
|     foo = Foo.new
 | |
|     ext_client = FooExtClient.new
 | |
|     assert_equal("Foo#x", foo.x)
 | |
|     assert_equal("Foo#x", ext_client.instance_eval { foo.x })
 | |
|     assert_equal("Foo#x", foo.x)
 | |
|   end
 | |
| 
 | |
|   module IntegerSlashExt
 | |
|     refine Integer do
 | |
|       def /(other) quo(other) end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_override_builtin_method
 | |
|     assert_equal(0, 1 / 2)
 | |
|     assert_equal(Rational(1, 2), eval_using(IntegerSlashExt, "1 / 2"))
 | |
|     assert_equal(0, 1 / 2)
 | |
|   end
 | |
| 
 | |
|   module IntegerPlusExt
 | |
|     refine Integer do
 | |
|       def self.method_added(*args); end
 | |
|       def +(other) "overridden" end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_override_builtin_method_with_method_added
 | |
|     assert_equal(3, 1 + 2)
 | |
|     assert_equal("overridden", eval_using(IntegerPlusExt, "1 + 2"))
 | |
|     assert_equal(3, 1 + 2)
 | |
|   end
 | |
| 
 | |
|   def test_return_value_of_refine
 | |
|     mod = nil
 | |
|     result = nil
 | |
|     Module.new {
 | |
|       result = refine(Object) {
 | |
|         mod = self
 | |
|       }
 | |
|     }
 | |
|     assert_equal mod, result
 | |
|   end
 | |
| 
 | |
|   module RefineSameClass
 | |
|     REFINEMENT1 = refine(Integer) {
 | |
|       def foo; return "foo" end
 | |
|     }
 | |
|     REFINEMENT2 = refine(Integer) {
 | |
|       def bar; return "bar" end
 | |
|     }
 | |
|     REFINEMENT3 = refine(String) {
 | |
|       def baz; return "baz" end
 | |
|     }
 | |
|   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)
 | |
|   end
 | |
| 
 | |
|   module IntegerFooExt
 | |
|     refine Integer do
 | |
|       def foo; "foo"; end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_respond_to_should_not_use_refinements
 | |
|     assert_equal(false, 1.respond_to?(:foo))
 | |
|     assert_equal(false, eval_using(IntegerFooExt, "1.respond_to?(:foo)"))
 | |
|   end
 | |
| 
 | |
|   module StringCmpExt
 | |
|     refine String do
 | |
|       def <=>(other) return 0 end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   module ArrayEachExt
 | |
|     refine Array do
 | |
|       def each
 | |
|         super do |i|
 | |
|           yield 2 * i
 | |
|         end
 | |
|       end
 | |
|     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"))
 | |
|   end
 | |
| 
 | |
|   module RefinePrependedClass
 | |
|     module M1
 | |
|       def foo
 | |
|         super << :m1
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     class C
 | |
|       prepend M1
 | |
| 
 | |
|       def foo
 | |
|         [:c]
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     module M2
 | |
|       refine C do
 | |
|         def foo
 | |
|           super << :m2
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_refine_prepended_class
 | |
|     x = eval_using(RefinePrependedClass::M2,
 | |
|                    "TestRefinement::RefinePrependedClass::C.new.foo")
 | |
|     assert_equal([:c, :m1, :m2], x)
 | |
|   end
 | |
| 
 | |
|   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
 | |
|         def foo
 | |
|           "M@M2#foo"
 | |
|         end
 | |
| 
 | |
|         def bar
 | |
|           "#{super} M@M2#bar"
 | |
|         end
 | |
| 
 | |
|         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
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   def test_refine_in_class
 | |
|     assert_raise(NoMethodError) do
 | |
|       Class.new {
 | |
|         refine Integer do
 | |
|           def foo
 | |
|             "c"
 | |
|           end
 | |
|         end
 | |
|       }
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_main_using
 | |
|     assert_in_out_err([], <<-INPUT, %w(:C :M), [])
 | |
|       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
 | |
| 
 | |
|   def test_main_using_is_private
 | |
|     assert_raise(NoMethodError) do
 | |
|       eval("self.using Module.new", Sandbox::BINDING)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_no_kernel_using
 | |
|     assert_raise(NoMethodError) do
 | |
|       using Module.new
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   class UsingClass
 | |
|   end
 | |
| 
 | |
|   def test_module_using_class
 | |
|     assert_raise(TypeError) do
 | |
|       eval("using TestRefinement::UsingClass", Sandbox::BINDING)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_refine_without_block
 | |
|     c1 = Class.new
 | |
|     assert_raise_with_message(ArgumentError, "no block given") {
 | |
|       Module.new do
 | |
|         refine c1
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   module Inspect
 | |
|     module M
 | |
|       Integer = refine(Integer) {}
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_inspect
 | |
|     assert_equal("#<refinement:Integer@TestRefinement::Inspect::M>",
 | |
|                  Inspect::M::Integer.inspect)
 | |
|   end
 | |
| 
 | |
|   def test_using_method_cache
 | |
|     assert_in_out_err([], <<-INPUT, %w(:M1 :M2), [])
 | |
|       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
 | |
| 
 | |
|   module RedefineRefinedMethod
 | |
|     class C
 | |
|       def foo
 | |
|         "original"
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     module M
 | |
|       refine C do
 | |
|         def foo
 | |
|           "refined"
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     class C
 | |
|       EnvUtil.suppress_warning do
 | |
|         def foo
 | |
|           "redefined"
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_redefine_refined_method
 | |
|     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
 | |
|   end
 | |
| 
 | |
|   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
 | |
|         else
 | |
|           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
 | |
| 
 | |
|   def test_refine_with_proc
 | |
|     assert_raise(ArgumentError) do
 | |
|       Module.new {
 | |
|         refine(String, &Proc.new {})
 | |
|       }
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_using_in_module
 | |
|     assert_raise(RuntimeError) do
 | |
|       eval(<<-EOF, Sandbox::BINDING)
 | |
|         $main = self
 | |
|         module M
 | |
|         end
 | |
|         module M2
 | |
|           $main.send(:using, M)
 | |
|         end
 | |
|       EOF
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_using_in_method
 | |
|     assert_raise(RuntimeError) do
 | |
|       eval(<<-EOF, Sandbox::BINDING)
 | |
|         $main = self
 | |
|         module M
 | |
|         end
 | |
|         class C
 | |
|           def call_using_in_method
 | |
|             $main.send(:using, M)
 | |
|           end
 | |
|         end
 | |
|         C.new.call_using_in_method
 | |
|       EOF
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   eval <<-EOF, Sandbox::BINDING
 | |
|     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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   eval <<-EOF, Sandbox::BINDING
 | |
|     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
 | |
| 
 | |
|   PrependAfterRefine_CODE = <<-EOC
 | |
|   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
 | |
|   EOC
 | |
|   eval PrependAfterRefine_CODE
 | |
| 
 | |
|   def test_prepend_after_refine_wb_miss
 | |
|     if /\A(arm|mips)/ =~ RUBY_PLATFORM
 | |
|       skip "too slow cpu"
 | |
|     end
 | |
|     assert_normal_exit %Q{
 | |
|       GC.stress = true
 | |
|       10.times{
 | |
|         #{PrependAfterRefine_CODE}
 | |
|         undef PrependAfterRefine
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   module ModuleUsing
 | |
|     using FooExt
 | |
| 
 | |
|     def self.invoke_x_on(foo)
 | |
|       return foo.x
 | |
|     end
 | |
| 
 | |
|     def self.invoke_y_on(foo)
 | |
|       return foo.y
 | |
|     end
 | |
| 
 | |
|     def self.invoke_z_on(foo)
 | |
|       return foo.z
 | |
|     end
 | |
| 
 | |
|     def self.send_z_on(foo)
 | |
|       return foo.send(:z)
 | |
|     end
 | |
| 
 | |
|     def self.method_z(foo)
 | |
|       return foo.method(:z)
 | |
|     end
 | |
| 
 | |
|     def self.invoke_call_x_on(foo)
 | |
|       return foo.call_x
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_module_using
 | |
|     foo = Foo.new
 | |
|     assert_equal("Foo#x", foo.x)
 | |
|     assert_equal("Foo#y", foo.y)
 | |
|     assert_raise(NoMethodError) { foo.z }
 | |
|     assert_equal("FooExt#x", ModuleUsing.invoke_x_on(foo))
 | |
|     assert_equal("FooExt#y Foo#y", ModuleUsing.invoke_y_on(foo))
 | |
|     assert_equal("FooExt#z", ModuleUsing.invoke_z_on(foo))
 | |
|     assert_equal("Foo#x", foo.x)
 | |
|     assert_equal("Foo#y", foo.y)
 | |
|     assert_raise(NoMethodError) { foo.z }
 | |
|   end
 | |
| 
 | |
|   def test_module_using_in_method
 | |
|     assert_raise(RuntimeError) do
 | |
|       Module.new.send(:using, FooExt)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_module_using_invalid_self
 | |
|     assert_raise(RuntimeError) do
 | |
|       eval <<-EOF, Sandbox::BINDING
 | |
|         module TestRefinement::TestModuleUsingInvalidSelf
 | |
|           Module.new.send(:using, TestRefinement::FooExt)
 | |
|         end
 | |
|       EOF
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
|     assert_in_out_err([], <<-INPUT, ["HELLO WORLD", "dlrow olleh", "dlrow olleh"], [])
 | |
|       module M
 | |
|         refine String do
 | |
|           def upcase
 | |
|             reverse
 | |
|           end
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       puts "hello world".upcase
 | |
|       b = binding
 | |
|       puts eval(%{using M; "hello world".upcase}, b)
 | |
|       puts eval(%{"hello world".upcase}, b)
 | |
|     INPUT
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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;
 | |
| 
 | |
|     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;
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
|             puts "Refined C"
 | |
|           end
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       class D < C
 | |
|         alias bar foo
 | |
|       end
 | |
| 
 | |
|       using M
 | |
|       D.new.bar
 | |
|     INPUT
 | |
|   end
 | |
| 
 | |
|   def test_reopen_refinement_module
 | |
|     assert_separately([], <<-"end;")
 | |
|       $VERBOSE = nil
 | |
|       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
 | |
|           def m
 | |
|             :bar
 | |
|           end
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       assert_equal(:bar, C.new.m, "[ruby-core:71423] [Bug #11672]")
 | |
|     end;
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|       refine Object do
 | |
|         def in_ref_c
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     module Foo
 | |
|       using RefB
 | |
|       USED_MODS = Module.used_modules
 | |
|     end
 | |
| 
 | |
|     module Bar
 | |
|       using RefC
 | |
|       USED_MODS = Module.used_modules
 | |
|     end
 | |
| 
 | |
|     module Combined
 | |
|       using RefA
 | |
|       using RefB
 | |
|       USED_MODS = Module.used_modules
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_used_modules
 | |
|     ref = VisibleRefinements
 | |
|     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
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   def test_symbol_proc
 | |
|     assert_equal("FooExt#x", FooExtClient.map_x_on(Foo.new))
 | |
|     assert_equal("Foo#x", FooExtClient.return_proc(&:x).(Foo.new))
 | |
|   end
 | |
| 
 | |
|   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
 | |
| 
 | |
|   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
 | |
| 
 | |
|   private
 | |
| 
 | |
|   def eval_using(mod, s)
 | |
|     eval("using #{mod}; #{s}", Sandbox::BINDING)
 | |
|   end
 | |
| end
 |