diff options
Diffstat (limited to 'spec/ruby/core/unboundmethod')
| -rw-r--r-- | spec/ruby/core/unboundmethod/bind_call_spec.rb | 12 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/bind_spec.rb | 24 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/clone_spec.rb | 13 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/dup_spec.rb | 15 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/equal_value_spec.rb | 55 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/fixtures/classes.rb | 27 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/inspect_spec.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/original_name_spec.rb | 37 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/owner_spec.rb | 6 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/private_spec.rb | 9 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/protected_spec.rb | 9 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/public_spec.rb | 9 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/shared/dup.rb | 32 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/shared/to_s.rb | 9 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/source_location_spec.rb | 13 | ||||
| -rw-r--r-- | spec/ruby/core/unboundmethod/to_s_spec.rb | 2 |
16 files changed, 232 insertions, 42 deletions
diff --git a/spec/ruby/core/unboundmethod/bind_call_spec.rb b/spec/ruby/core/unboundmethod/bind_call_spec.rb index 8f25f8bd0d..ee1dad9c9e 100644 --- a/spec/ruby/core/unboundmethod/bind_call_spec.rb +++ b/spec/ruby/core/unboundmethod/bind_call_spec.rb @@ -7,10 +7,12 @@ describe "UnboundMethod#bind_call" do @parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind @child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind @child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind + @normal_um_super = UnboundMethodSpecs::Mod.instance_method(:foo_super) + @parent_um_super = UnboundMethodSpecs::Parent.new.method(:foo_super).unbind end it "raises TypeError if object is not kind_of? the Module the method defined in" do - -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should raise_error(TypeError) + -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should.raise(TypeError) end it "binds and calls the method if object is kind_of the Module the method defined in" do @@ -45,6 +47,12 @@ describe "UnboundMethod#bind_call" do end end um = p.method(:singleton_method).unbind - ->{ um.bind_call(other) }.should raise_error(TypeError) + ->{ um.bind_call(other) }.should.raise(TypeError) + end + + it "allows calling super for module methods bound to hierarchies that do not already have that module" do + p = UnboundMethodSpecs::Parent.new + + @normal_um_super.bind_call(p).should == true end end diff --git a/spec/ruby/core/unboundmethod/bind_spec.rb b/spec/ruby/core/unboundmethod/bind_spec.rb index 03aaa22e74..087994ff57 100644 --- a/spec/ruby/core/unboundmethod/bind_spec.rb +++ b/spec/ruby/core/unboundmethod/bind_spec.rb @@ -7,18 +7,20 @@ describe "UnboundMethod#bind" do @parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind @child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind @child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind + @normal_um_super = UnboundMethodSpecs::Mod.instance_method(:foo_super) + @parent_um_super = UnboundMethodSpecs::Parent.new.method(:foo_super).unbind end it "raises TypeError if object is not kind_of? the Module the method defined in" do - -> { @normal_um.bind(UnboundMethodSpecs::B.new) }.should raise_error(TypeError) + -> { @normal_um.bind(UnboundMethodSpecs::B.new) }.should.raise(TypeError) end it "returns Method for any object that is kind_of? the Module method was extracted from" do - @normal_um.bind(UnboundMethodSpecs::Methods.new).should be_kind_of(Method) + @normal_um.bind(UnboundMethodSpecs::Methods.new).should.is_a?(Method) end it "returns Method on any object when UnboundMethod is unbound from a module" do - UnboundMethodSpecs::Mod.instance_method(:from_mod).bind(Object.new).should be_kind_of(Method) + UnboundMethodSpecs::Mod.instance_method(:from_mod).bind(Object.new).should.is_a?(Method) end it "the returned Method is equal to the one directly returned by obj.method" do @@ -27,9 +29,9 @@ describe "UnboundMethod#bind" do end it "returns Method for any object kind_of? the Module the method is defined in" do - @parent_um.bind(UnboundMethodSpecs::Child1.new).should be_kind_of(Method) - @child1_um.bind(UnboundMethodSpecs::Parent.new).should be_kind_of(Method) - @child2_um.bind(UnboundMethodSpecs::Child1.new).should be_kind_of(Method) + @parent_um.bind(UnboundMethodSpecs::Child1.new).should.is_a?(Method) + @child1_um.bind(UnboundMethodSpecs::Parent.new).should.is_a?(Method) + @child2_um.bind(UnboundMethodSpecs::Child1.new).should.is_a?(Method) end it "allows binding a Kernel method retrieved from Object on BasicObject" do @@ -43,7 +45,7 @@ describe "UnboundMethod#bind" do it "binds a Parent's class method to any Child's class methods" do m = UnboundMethodSpecs::Parent.method(:class_method).unbind.bind(UnboundMethodSpecs::Child1) - m.should be_an_instance_of(Method) + m.should.instance_of?(Method) m.call.should == "I am UnboundMethodSpecs::Child1" end @@ -56,6 +58,12 @@ describe "UnboundMethod#bind" do end end um = p.method(:singleton_method).unbind - ->{ um.bind(other) }.should raise_error(TypeError) + ->{ um.bind(other) }.should.raise(TypeError) + end + + it "allows calling super for module methods bound to hierarchies that do not already have that module" do + p = UnboundMethodSpecs::Parent.new + + @normal_um_super.bind(p).call.should == true end end diff --git a/spec/ruby/core/unboundmethod/clone_spec.rb b/spec/ruby/core/unboundmethod/clone_spec.rb index 098ee61476..1e7fb18744 100644 --- a/spec/ruby/core/unboundmethod/clone_spec.rb +++ b/spec/ruby/core/unboundmethod/clone_spec.rb @@ -1,12 +1,13 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' +require_relative 'shared/dup' describe "UnboundMethod#clone" do - it "returns a copy of the UnboundMethod" do - um1 = UnboundMethodSpecs::Methods.instance_method(:foo) - um2 = um1.clone + it_behaves_like :unboundmethod_dup, :clone - (um1 == um2).should == true - um1.bind(UnboundMethodSpecs::Methods.new).call.should == um2.bind(UnboundMethodSpecs::Methods.new).call + it "preserves frozen status" do + method = Class.instance_method(:instance_method) + method.freeze + method.frozen?.should == true + method.clone.frozen?.should == true end end diff --git a/spec/ruby/core/unboundmethod/dup_spec.rb b/spec/ruby/core/unboundmethod/dup_spec.rb new file mode 100644 index 0000000000..5a78dd8e36 --- /dev/null +++ b/spec/ruby/core/unboundmethod/dup_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../spec_helper' +require_relative 'shared/dup' + +describe "UnboundMethod#dup" do + ruby_version_is "3.4" do + it_behaves_like :unboundmethod_dup, :dup + + it "resets frozen status" do + method = Class.instance_method(:instance_method) + method.freeze + method.frozen?.should == true + method.dup.frozen?.should == false + end + end +end diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb index b21677687e..24d5233299 100644 --- a/spec/ruby/core/unboundmethod/equal_value_spec.rb +++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb @@ -3,8 +3,8 @@ require_relative 'fixtures/classes' context "Creating UnboundMethods" do specify "there is no difference between Method#unbind and Module#instance_method" do - UnboundMethodSpecs::Methods.instance_method(:foo).should be_kind_of(UnboundMethod) - UnboundMethodSpecs::Methods.new.method(:foo).unbind.should be_kind_of(UnboundMethod) + UnboundMethodSpecs::Methods.instance_method(:foo).should.is_a?(UnboundMethod) + UnboundMethodSpecs::Methods.new.method(:foo).unbind.should.is_a?(UnboundMethod) end end @@ -35,6 +35,12 @@ describe "UnboundMethod#==" do @method_one = UnboundMethodSpecs::Methods.instance_method(:one) @method_two = UnboundMethodSpecs::Methods.instance_method(:two) + + @mixin = UnboundMethodSpecs::Mixin.instance_method(:mixin_method) + @includer_base = UnboundMethodSpecs::IncluderBase.new.method(:mixin_method).unbind + @includer_child = UnboundMethodSpecs::IncluderChild.new.method(:mixin_method).unbind + @extender_base = UnboundMethodSpecs::ExtenderBase.method(:mixin_method).unbind + @extender_child = UnboundMethodSpecs::ExtenderChild.method(:mixin_method).unbind end it "returns true if objects refer to the same method" do @@ -76,19 +82,43 @@ describe "UnboundMethod#==" do (@identical_body == @original_body).should == false end - it "returns false if same method but one extracted from a subclass" do - (@parent == @child1).should == false - (@child1 == @parent).should == false + it "returns true if same method but one extracted from a subclass" do + (@parent == @child1).should == true + (@child1 == @parent).should == true + end + + it "returns true if same method but extracted from two different subclasses" do + (@child2 == @child1).should == true + (@child1 == @child2).should == true end - it "returns false if same method but extracted from two different subclasses" do - (@child2 == @child1).should == false - (@child1 == @child2).should == false + it "returns true if methods are the same but added from an included Module" do + (@includee == @includer).should == true + (@includer == @includee).should == true end - it "returns false if methods are the same but added from an included Module" do - (@includee == @includer).should == false - (@includer == @includee).should == false + ruby_bug "#21873", ""..."4.1" do + it "returns true if same method is present in an object through module inclusion" do + (@mixin == @includer_base).should == true + (@includer_base == @mixin).should == true + + (@mixin == @includer_child).should == true + (@includer_child == @mixin).should == true + + (@includer_base == @includer_child).should == true + (@includer_child == @includer_base).should == true + end + + it "returns true if same method is present in an object through module extension" do + (@mixin == @extender_base).should == true + (@extender_base == @mixin).should == true + + (@mixin == @extender_child).should == true + (@extender_child == @mixin).should == true + + (@extender_base == @extender_child).should == true + (@extender_child == @extender_base).should == true + end end it "returns false if both have same Module, same name, identical body but not the same" do @@ -110,9 +140,6 @@ describe "UnboundMethod#==" do c.method(:n).should == Class.instance_method(:new).bind(c) end - # On CRuby < 3.2, the 2 specs below pass due to method/instance_method skipping zsuper methods. - # We are interested in the general pattern working, i.e. the combination of method/instance_method - # and #== exposes the wanted behavior. it "considers methods through visibility change equal" do c = Class.new do class << self diff --git a/spec/ruby/core/unboundmethod/fixtures/classes.rb b/spec/ruby/core/unboundmethod/fixtures/classes.rb index 1f466e39d8..58120c2f88 100644 --- a/spec/ruby/core/unboundmethod/fixtures/classes.rb +++ b/spec/ruby/core/unboundmethod/fixtures/classes.rb @@ -22,6 +22,7 @@ module UnboundMethodSpecs module Mod def from_mod; end + def foo_super; super; end end class Methods @@ -35,6 +36,7 @@ module UnboundMethodSpecs alias bar foo alias baz bar + alias qux baz alias alias_1 foo alias alias_2 foo @@ -53,10 +55,19 @@ module UnboundMethodSpecs def discard_1(); :discard; end def discard_2(); :discard; end + + def my_public_method; end + def my_protected_method; end + def my_private_method; end + protected :my_protected_method + private :my_private_method end class Parent def foo; end + def foo_super + true + end def self.class_method "I am #{name}" end @@ -70,6 +81,22 @@ module UnboundMethodSpecs end end + module Mixin + def mixin_method; end + end + + class IncluderBase + include Mixin + end + + class IncluderChild < IncluderBase; end + + class ExtenderBase + extend Mixin + end + + class ExtenderChild < ExtenderBase; end + class A def baz(a, b) return [__FILE__, self.class] diff --git a/spec/ruby/core/unboundmethod/inspect_spec.rb b/spec/ruby/core/unboundmethod/inspect_spec.rb index cecf542fcd..3abed94f7f 100644 --- a/spec/ruby/core/unboundmethod/inspect_spec.rb +++ b/spec/ruby/core/unboundmethod/inspect_spec.rb @@ -1,7 +1,9 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/to_s' +require_relative '../method/shared/aliased_inspect' describe "UnboundMethod#inspect" do it_behaves_like :unboundmethod_to_s, :inspect + it_behaves_like :method_to_s_aliased, :inspect, -> meth { meth.unbind } end diff --git a/spec/ruby/core/unboundmethod/original_name_spec.rb b/spec/ruby/core/unboundmethod/original_name_spec.rb index 7280dcb2b4..cd5f55805d 100644 --- a/spec/ruby/core/unboundmethod/original_name_spec.rb +++ b/spec/ruby/core/unboundmethod/original_name_spec.rb @@ -19,4 +19,41 @@ describe "UnboundMethod#original_name" do obj.method(:baz).unbind.original_name.should == :foo UnboundMethodSpecs::Methods.instance_method(:baz).original_name.should == :foo end + + it "returns the original name even when aliased thrice" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:qux).unbind.original_name.should == :foo + UnboundMethodSpecs::Methods.instance_method(:qux).original_name.should == :foo + end + + it "returns the source UnboundMethod's name (not the name given to define_method)" do + klass = Class.new { define_method(:my_inspect, ::Kernel.instance_method(:inspect)) } + klass.instance_method(:my_inspect).original_name.should == :inspect + end + + it "preserves the source method's name through define_method and alias" do + source = Class.new { def my_method; end } + klass = Class.new(source) do + define_method(:renamed, source.instance_method(:my_method)) + alias aliased renamed + end + klass.instance_method(:renamed).original_name.should == :my_method + klass.instance_method(:aliased).original_name.should == :my_method + end + + it "returns the source UnboundMethod's name for Kernel#is_a? and Kernel#kind_of?" do + klass = Class.new { define_method(:my_is_a?, ::Kernel.instance_method(:is_a?)) } + klass.instance_method(:my_is_a?).original_name.should == :is_a? + + klass = Class.new { define_method(:my_kind_of?, ::Kernel.instance_method(:kind_of?)) } + klass.instance_method(:my_kind_of?).original_name.should == :kind_of? + end + + it "preserves the source name when aliasing a define_method'd Kernel method" do + klass = Class.new do + define_method(:my_is_a?, ::Kernel.instance_method(:is_a?)) + alias_method :renamed_is_a?, :my_is_a? + end + klass.instance_method(:renamed_is_a?).original_name.should == :is_a? + end end diff --git a/spec/ruby/core/unboundmethod/owner_spec.rb b/spec/ruby/core/unboundmethod/owner_spec.rb index e8a734dac4..b099c56de1 100644 --- a/spec/ruby/core/unboundmethod/owner_spec.rb +++ b/spec/ruby/core/unboundmethod/owner_spec.rb @@ -25,9 +25,7 @@ describe "UnboundMethod#owner" do child_singleton_class.instance_method(:another_class_method).owner.should == child_singleton_class end - ruby_version_is "3.2" do - it "returns the class on which public was called for a private method in ancestor" do - MethodSpecs::InheritedMethods::C.instance_method(:derp).owner.should == MethodSpecs::InheritedMethods::C - end + it "returns the class on which public was called for a private method in ancestor" do + MethodSpecs::InheritedMethods::C.instance_method(:derp).owner.should == MethodSpecs::InheritedMethods::C end end diff --git a/spec/ruby/core/unboundmethod/private_spec.rb b/spec/ruby/core/unboundmethod/private_spec.rb new file mode 100644 index 0000000000..5a563939d1 --- /dev/null +++ b/spec/ruby/core/unboundmethod/private_spec.rb @@ -0,0 +1,9 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "UnboundMethod#private?" do + it "has been removed" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_private_method).unbind.should_not.respond_to?(:private?) + end +end diff --git a/spec/ruby/core/unboundmethod/protected_spec.rb b/spec/ruby/core/unboundmethod/protected_spec.rb new file mode 100644 index 0000000000..70622d658d --- /dev/null +++ b/spec/ruby/core/unboundmethod/protected_spec.rb @@ -0,0 +1,9 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "UnboundMethod#protected?" do + it "has been removed" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_protected_method).unbind.should_not.respond_to?(:protected?) + end +end diff --git a/spec/ruby/core/unboundmethod/public_spec.rb b/spec/ruby/core/unboundmethod/public_spec.rb new file mode 100644 index 0000000000..ae75e2601c --- /dev/null +++ b/spec/ruby/core/unboundmethod/public_spec.rb @@ -0,0 +1,9 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "UnboundMethod#public?" do + it "has been removed" do + obj = UnboundMethodSpecs::Methods.new + obj.method(:my_public_method).unbind.should_not.respond_to?(:public?) + end +end diff --git a/spec/ruby/core/unboundmethod/shared/dup.rb b/spec/ruby/core/unboundmethod/shared/dup.rb new file mode 100644 index 0000000000..fd30f75c5b --- /dev/null +++ b/spec/ruby/core/unboundmethod/shared/dup.rb @@ -0,0 +1,32 @@ +describe :unboundmethod_dup, shared: true do + it "returns a copy of self" do + a = Class.instance_method(:instance_method) + b = a.send(@method) + + a.should == b + a.should_not.equal?(b) + end + + ruby_version_is "3.4" do + it "copies instance variables" do + method = Class.instance_method(:instance_method) + method.instance_variable_set(:@ivar, 1) + cl = method.send(@method) + cl.instance_variables.should == [:@ivar] + end + + it "copies the finalizer" do + code = <<-'RUBY' + obj = Class.instance_method(:instance_method) + + ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) + + obj.clone + + exit 0 + RUBY + + ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] + end + end +end diff --git a/spec/ruby/core/unboundmethod/shared/to_s.rb b/spec/ruby/core/unboundmethod/shared/to_s.rb index 38503c3c60..848c1eba2e 100644 --- a/spec/ruby/core/unboundmethod/shared/to_s.rb +++ b/spec/ruby/core/unboundmethod/shared/to_s.rb @@ -8,8 +8,8 @@ describe :unboundmethod_to_s, shared: true do end it "returns a String" do - @from_module.send(@method).should be_kind_of(String) - @from_method.send(@method).should be_kind_of(String) + @from_module.send(@method).should.is_a?(String) + @from_method.send(@method).should.is_a?(String) end it "the String reflects that this is an UnboundMethod object" do @@ -20,12 +20,11 @@ describe :unboundmethod_to_s, shared: true do it "the String shows the method name, Module defined in and Module extracted from" do @from_module.send(@method).should =~ /\bfrom_mod\b/ @from_module.send(@method).should =~ /\bUnboundMethodSpecs::Mod\b/ - @from_method.send(@method).should =~ /\bUnboundMethodSpecs::Methods\b/ end it "returns a String including all details" do - @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod" - @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod" + @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod" + @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod" end it "does not show the defining module if it is the same as the origin" do diff --git a/spec/ruby/core/unboundmethod/source_location_spec.rb b/spec/ruby/core/unboundmethod/source_location_spec.rb index 96933a5d40..927600bfcb 100644 --- a/spec/ruby/core/unboundmethod/source_location_spec.rb +++ b/spec/ruby/core/unboundmethod/source_location_spec.rb @@ -8,13 +8,13 @@ describe "UnboundMethod#source_location" do it "sets the first value to the path of the file in which the method was defined" do file = @method.source_location.first - file.should be_an_instance_of(String) - file.should == File.realpath('../fixtures/classes.rb', __FILE__) + file.should.instance_of?(String) + file.should == File.realpath('fixtures/classes.rb', __dir__) end it "sets the last value to an Integer representing the line on which the method was defined" do line = @method.source_location.last - line.should be_an_instance_of(Integer) + line.should.instance_of?(Integer) line.should == 5 end @@ -49,4 +49,11 @@ describe "UnboundMethod#source_location" do method.source_location[0].should =~ /#{__FILE__}/ method.source_location[1].should == line end + + it "works for eval with a given line" do + c = Class.new do + eval('def m; end', nil, "foo", 100) + end + c.instance_method(:m).source_location.should == ["foo", 100] + end end diff --git a/spec/ruby/core/unboundmethod/to_s_spec.rb b/spec/ruby/core/unboundmethod/to_s_spec.rb index a508229b49..615d88675b 100644 --- a/spec/ruby/core/unboundmethod/to_s_spec.rb +++ b/spec/ruby/core/unboundmethod/to_s_spec.rb @@ -1,7 +1,9 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/to_s' +require_relative '../method/shared/aliased_inspect' describe "UnboundMethod#to_s" do it_behaves_like :unboundmethod_to_s, :to_s + it_behaves_like :method_to_s_aliased, :to_s, -> meth { meth.unbind } end |
