summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <[email protected]>2020-03-09 07:57:16 -0700
committerGitHub <[email protected]>2020-03-09 07:57:16 -0700
commite02bd0e713ef920e6d12c27f16548f48ec5c2cf0 (patch)
treea04c6ec68aa6c9d177d09ebb5fc79bb0ece3af7e
parentecef163cf9bbdffcf1466addc39daa92084d6b53 (diff)
Don't display singleton class in Method#inspect unless method defined there
Previously, if an object has a singleton class, and you call Object#method on the object, the resulting string would include the object's singleton class, even though the method was not defined in the singleton class. Change this so the we only show the singleton class if the method is defined in the singleton class. Fixes [Bug #15608]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2949 Merged-By: jeremyevans <[email protected]>
-rw-r--r--proc.c9
-rw-r--r--spec/ruby/core/method/shared/to_s.rb18
-rw-r--r--test/ruby/test_method.rb8
3 files changed, 34 insertions, 1 deletions
diff --git a/proc.c b/proc.c
index 390b1bf3fa..0b1be9c212 100644
--- a/proc.c
+++ b/proc.c
@@ -2812,7 +2812,8 @@ method_inspect(VALUE method)
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
str = rb_sprintf("#<% "PRIsVALUE": ", rb_obj_class(method));
- mklass = data->klass;
+ mklass = data->iclass;
+ if (!mklass) mklass = data->klass;
if (RB_TYPE_P(mklass, T_ICLASS)) {
/* TODO: I'm not sure why mklass is T_ICLASS.
@@ -2852,6 +2853,12 @@ method_inspect(VALUE method)
}
}
else {
+ mklass = data->klass;
+ if (FL_TEST(mklass, FL_SINGLETON)) {
+ do {
+ mklass = RCLASS_SUPER(mklass);
+ } while (RB_TYPE_P(mklass, T_ICLASS));
+ }
rb_str_buf_append(str, rb_inspect(mklass));
if (defined_class != mklass) {
rb_str_catf(str, "(% "PRIsVALUE")", defined_class);
diff --git a/spec/ruby/core/method/shared/to_s.rb b/spec/ruby/core/method/shared/to_s.rb
index 373398a785..7666322936 100644
--- a/spec/ruby/core/method/shared/to_s.rb
+++ b/spec/ruby/core/method/shared/to_s.rb
@@ -31,4 +31,22 @@ describe :method_to_s, shared: true do
it "returns a String containing the Module the method is referenced from" do
@string.should =~ /MethodSpecs::MySub/
end
+
+ ruby_version_is '2.8' do
+ it "returns a String containing the Module containing the method if object has a singleton class but method is not defined in the singleton class" do
+ obj = MethodSpecs::MySub.new
+ obj.singleton_class
+ @m = obj.method(:bar)
+ @string = @m.send(@method).sub(/0x\w+/, '0xXXXXXX')
+ @string.should =~ /\A#<Method: MethodSpecs::MySub\(MethodSpecs::MyMod\)#bar\(\) /
+ end
+ end
+
+ it "returns a String containing the singleton class if method is defined in the singleton class" do
+ obj = MethodSpecs::MySub.new
+ def obj.bar; end
+ @m = obj.method(:bar)
+ @string = @m.send(@method).sub(/0x\w+/, '0xXXXXXX')
+ @string.should =~ /\A#<Method: #<MethodSpecs::MySub:0xXXXXXX>\.bar/
+ end
end
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index 563011a03f..01a69059e8 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -465,6 +465,14 @@ class TestMethod < Test::Unit::TestCase
c3.class_eval { alias bar foo }
m3 = c3.new.method(:bar)
assert_equal("#<Method: #{c3.inspect}(#{c.inspect})#bar(foo)() #{__FILE__}:#{line_no}>", m3.inspect, bug7806)
+
+ bug15608 = '[ruby-core:91570] [Bug #15608]'
+ c4 = Class.new(c)
+ c4.class_eval { alias bar foo }
+ o = c4.new
+ o.singleton_class
+ m4 = o.method(:bar)
+ assert_equal("#<Method: #{c4.inspect}(#{c.inspect})#bar(foo)() #{__FILE__}:#{line_no}>", m4.inspect, bug15608)
end
def test_callee_top_level