UnboundMethod only refer defined_class
UnboundMethod records caller's class, like `D` or `E` on the following case: ```ruby class C def foo = :foo end class D < C end class E < C end d = D.instance_method(:foo) e = E.instance_method(:foo) ``` But `d` and `e` only refers `C#foo` so that UnboundMethod doesn't record `D` or `E`. This behavior changes the following methods: * `UnboundMethod#inspect` (doesn't show caller's class) * `UnboundMethod#==` (`d == e` for example) fix https://bugs.ruby-lang.org/issues/18798
This commit is contained in:
parent
7161bf34e1
commit
59e389af28
Notes:
git
2022-12-02 23:53:36 +00:00
20
proc.c
20
proc.c
@ -1724,8 +1724,14 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass,
|
||||
|
||||
method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data);
|
||||
|
||||
RB_OBJ_WRITE(method, &data->recv, obj);
|
||||
RB_OBJ_WRITE(method, &data->klass, klass);
|
||||
if (obj == Qundef) {
|
||||
RB_OBJ_WRITE(method, &data->recv, Qundef);
|
||||
RB_OBJ_WRITE(method, &data->klass, Qundef);
|
||||
}
|
||||
else {
|
||||
RB_OBJ_WRITE(method, &data->recv, obj);
|
||||
RB_OBJ_WRITE(method, &data->klass, klass);
|
||||
}
|
||||
RB_OBJ_WRITE(method, &data->iclass, iclass);
|
||||
RB_OBJ_WRITE(method, &data->owner, original_me->owner);
|
||||
RB_OBJ_WRITE(method, &data->me, me);
|
||||
@ -1876,9 +1882,9 @@ method_unbind(VALUE obj)
|
||||
method = TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD,
|
||||
&method_data_type, data);
|
||||
RB_OBJ_WRITE(method, &data->recv, Qundef);
|
||||
RB_OBJ_WRITE(method, &data->klass, orig->klass);
|
||||
RB_OBJ_WRITE(method, &data->klass, Qundef);
|
||||
RB_OBJ_WRITE(method, &data->iclass, orig->iclass);
|
||||
RB_OBJ_WRITE(method, &data->owner, orig->owner);
|
||||
RB_OBJ_WRITE(method, &data->owner, orig->me->owner);
|
||||
RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me));
|
||||
|
||||
return method;
|
||||
@ -3139,7 +3145,11 @@ method_inspect(VALUE method)
|
||||
defined_class = RBASIC_CLASS(defined_class);
|
||||
}
|
||||
|
||||
if (FL_TEST(mklass, FL_SINGLETON)) {
|
||||
if (data->recv == Qundef) {
|
||||
// UnboundMethod
|
||||
rb_str_buf_append(str, rb_inspect(defined_class));
|
||||
}
|
||||
else if (FL_TEST(mklass, FL_SINGLETON)) {
|
||||
VALUE v = rb_ivar_get(mklass, attached);
|
||||
|
||||
if (UNDEF_P(data->recv)) {
|
||||
|
@ -27,8 +27,16 @@ describe "Method#unbind" do
|
||||
@string.should =~ /MethodSpecs::MyMod/
|
||||
end
|
||||
|
||||
it "returns a String containing the Module the method is referenced from" do
|
||||
@string.should =~ /MethodSpecs::MySub/
|
||||
ruby_version_is ""..."3.2" do
|
||||
it "returns a String containing the Module the method is referenced from" do
|
||||
@string.should =~ /MethodSpecs::MySub/
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "3.2" do
|
||||
it "returns a String containing the Module the method is referenced from" do
|
||||
@string.should =~ /MethodSpecs::MyMod/
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -45,10 +45,14 @@ describe "Module#instance_method" do
|
||||
@parent_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/
|
||||
@child_um.inspect.should =~ /\bfoo\b/
|
||||
@child_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/
|
||||
@child_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
|
||||
|
||||
@mod_um.inspect.should =~ /\bbar\b/
|
||||
@mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethMod\b/
|
||||
@mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
|
||||
|
||||
ruby_version_is ""..."3.2" do
|
||||
@child_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
|
||||
@mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
|
||||
end
|
||||
end
|
||||
|
||||
it "raises a TypeError if the given name is not a String/Symbol" do
|
||||
|
@ -76,19 +76,38 @@ 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
|
||||
ruby_version_is ""..."3.2" do
|
||||
it "returns false if same method but one extracted from a subclass" do
|
||||
(@parent == @child1).should == false
|
||||
(@child1 == @parent).should == false
|
||||
end
|
||||
|
||||
it "returns false if same method but extracted from two different subclasses" do
|
||||
(@child2 == @child1).should == false
|
||||
(@child1 == @child2).should == false
|
||||
end
|
||||
|
||||
it "returns false if methods are the same but added from an included Module" do
|
||||
(@includee == @includer).should == false
|
||||
(@includer == @includee).should == false
|
||||
end
|
||||
end
|
||||
|
||||
it "returns false if same method but extracted from two different subclasses" do
|
||||
(@child2 == @child1).should == false
|
||||
(@child1 == @child2).should == false
|
||||
end
|
||||
ruby_version_is "3.2" do
|
||||
it "returns true if same method but one extracted from a subclass" do
|
||||
(@parent == @child1).should == true
|
||||
(@child1 == @parent).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
|
||||
it "returns false if same method but extracted from two different subclasses" do
|
||||
(@child2 == @child1).should == true
|
||||
(@child1 == @child2).should == true
|
||||
end
|
||||
|
||||
it "returns true if methods are the same but added from an included Module" do
|
||||
(@includee == @includer).should == true
|
||||
(@includer == @includee).should == true
|
||||
end
|
||||
end
|
||||
|
||||
it "returns false if both have same Module, same name, identical body but not the same" do
|
||||
|
@ -20,12 +20,22 @@ 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/
|
||||
|
||||
ruby_version_is ""..."3.2" do
|
||||
@from_method.send(@method).should =~ /\bUnboundMethodSpecs::Methods\b/
|
||||
end
|
||||
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"
|
||||
ruby_version_is ""..."3.2" 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"
|
||||
end
|
||||
|
||||
ruby_version_is "3.2" do
|
||||
@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
|
||||
end
|
||||
|
||||
it "does not show the defining module if it is the same as the origin" do
|
||||
|
@ -1236,12 +1236,12 @@ class TestMethod < Test::Unit::TestCase
|
||||
unbound = b.instance_method(:foo)
|
||||
|
||||
assert_equal unbound, b.public_instance_method(:foo)
|
||||
assert_equal "#<UnboundMethod: B(A)#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect
|
||||
assert_equal "#<UnboundMethod: A#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect
|
||||
assert_equal [[:opt, :arg]], unbound.parameters
|
||||
|
||||
a.remove_method(:foo)
|
||||
|
||||
assert_equal "#<UnboundMethod: B(A)#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect
|
||||
assert_equal "#<UnboundMethod: A#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect
|
||||
assert_equal [[:opt, :arg]], unbound.parameters
|
||||
|
||||
obj = b.new
|
||||
@ -1281,7 +1281,7 @@ class TestMethod < Test::Unit::TestCase
|
||||
|
||||
a.remove_method(:foo)
|
||||
|
||||
assert_equal "#<UnboundMethod: B(A)#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect
|
||||
assert_equal "#<UnboundMethod: A#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect
|
||||
assert_equal [[:opt, :arg]], unbound.parameters
|
||||
assert_equal a0_foo, unbound.super_method
|
||||
|
||||
@ -1289,7 +1289,7 @@ class TestMethod < Test::Unit::TestCase
|
||||
assert_equal 1, unbound.bind_call(obj)
|
||||
|
||||
assert_include b.instance_methods(false), :foo
|
||||
assert_equal "#<UnboundMethod: B(A0)#foo(arg1=..., arg2=...) #{__FILE__}:#{line0}>", b.instance_method(:foo).inspect
|
||||
assert_equal "#<UnboundMethod: A0#foo(arg1=..., arg2=...) #{__FILE__}:#{line0}>", b.instance_method(:foo).inspect
|
||||
end
|
||||
|
||||
def test_zsuper_method_redefined_bind_call
|
||||
|
Loading…
x
Reference in New Issue
Block a user