Forum: Ruby-core [ruby-trunk - Bug #8982][Open] NoMethodError#message produces surprising output when #inspect is def

42d4590355a1404230fbc9aff4dd377b?d=identicon&s=25 myronmarston (Myron Marston) (Guest)
on 2013-10-03 08:23
(Received via mailing list)
Issue #8982 has been reported by myronmarston (Myron Marston).

----------------------------------------
Bug #8982: NoMethodError#message produces surprising output when
#inspect is defined on an anonymous class
https://bugs.ruby-lang.org/issues/8982

Author: myronmarston (Myron Marston)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:
ruby -v: ruby 2.0.0p247 (2013-06-27 revision 41674)
[x86_64-darwin12.4.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


Given the following script:

```
def raise_no_method_error_for_anonymous_class_with_inspect(&block)
  klass = Class.new do
    define_method(:inspect, &block)
  end

  begin
    instance = klass.new
    puts "#inspect output: #{instance.inspect}
(#{instance.inspect.length} chars)"
    instance.undefined_method
  rescue NoMethodError => e
    puts e.message
  end

  puts
end

raise_no_method_error_for_anonymous_class_with_inspect do
  "#<MyAnonymousClass>"
end

raise_no_method_error_for_anonymous_class_with_inspect do
  "<MyAnonymousClass>"
end

raise_no_method_error_for_anonymous_class_with_inspect do
  "#<MyAnonymousClass #{'a' * 45}>"
end

raise_no_method_error_for_anonymous_class_with_inspect do
  "#<MyAnonymousClass #{'a' * 46}>"
end
```

It produces the following output:

```
#inspect output: #<MyAnonymousClass> (19 chars)
undefined method `undefined_method' for #<MyAnonymousClass>

#inspect output: <MyAnonymousClass> (18 chars)
undefined method `undefined_method' for
<MyAnonymousClass>:#<Class:0x1017270e8>

#inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (65 chars)
undefined method `undefined_method' for #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>

#inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (66 chars)
undefined method `undefined_method' for
#<#<Class:0x1017266e8>:0x101726698>
```

There are two surprising things here:

* It matters whether or not the first character in my `inspect` is a
`#`.  If it's not, ruby appends the class's `#inspect` output to it.
* It matters how long my `inspect` string is.  If it's less than 66
characters, it's used; if it's more than 65, it's discarded, and the
default anonymous `#inspect` is used instead.

Both of these things are extremely surprising and seem very arbitrary
and inconsistent.

I brought this up on ruby parley and @charliesome was kind enough to
point me to the code that's the source of this issue:

https://github.com/ruby/ruby/blob/870dc20922d1ab0b...

So it looks intentional, but I think this is a bug.
F1d6cc2b735bfd82c8773172da2aeab9?d=identicon&s=25 Nobuyoshi Nakada (nobu)
on 2013-10-17 17:13
(Received via mailing list)
Issue #8982 has been updated by nobu (Nobuyoshi Nakada).

Description updated

myronmarston (Myron Marston) wrote:
> * It matters whether or not the first character in my `inspect` is a `#`.  If
it's not, ruby appends the class's `#inspect` output to it.

'#' at the beginning is assumed the string is same as Object#inspect,
otherwise its class name is appended since the string may not represent
the class.

> * It matters how long my `inspect` string is.  If it's less than 66 characters,
it's used; if it's more than 65, it's discarded, and the default anonymous
`#inspect` is used instead.

If the `inspect` string is too long, just ignore it and use default
conersion method

----------------------------------------
Bug #8982: NoMethodError#message produces surprising output when
#inspect is defined on an anonymous class
https://bugs.ruby-lang.org/issues/8982#change-42505

Author: myronmarston (Myron Marston)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:
ruby -v: ruby 2.0.0p247 (2013-06-27 revision 41674)
[x86_64-darwin12.4.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


=begin
Given the following script:

 def raise_no_method_error_for_anonymous_class_with_inspect(&block)
   klass = Class.new do
     define_method(:inspect, &block)
   end

   begin
     instance = klass.new
     puts "#inspect output: #{instance.inspect}
(#{instance.inspect.length} chars)"
     instance.undefined_method
   rescue NoMethodError => e
     puts e.message
   end

   puts
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "<MyAnonymousClass>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass #{'a' * 45}>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass #{'a' * 46}>"
 end

It produces the following output:

 #inspect output: #<MyAnonymousClass> (19 chars)
 undefined method `undefined_method' for #<MyAnonymousClass>

 #inspect output: <MyAnonymousClass> (18 chars)
 undefined method `undefined_method' for
<MyAnonymousClass>:#<Class:0x1017270e8>

 #inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (65 chars)
 undefined method `undefined_method' for #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>

 #inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (66 chars)
 undefined method `undefined_method' for
#<#<Class:0x1017266e8>:0x101726698>

There are two surprising things here:

* It matters whether or not the first character in my `inspect` is a
`#`.  If it's not, ruby appends the class's `#inspect` output to it.
* It matters how long my `inspect` string is.  If it's less than 66
characters, it's used; if it's more than 65, it's discarded, and the
default anonymous `#inspect` is used instead.

Both of these things are extremely surprising and seem very arbitrary
and inconsistent.

I brought this up on ruby parley and @charliesome was kind enough to
point me to the code that's the source of this issue:

((<error.c#L1091-1104|URL:https://github.com/ruby/ruby/blob/870dc20922d1ab0b...))

So it looks intentional, but I think this is a bug.
=end
C4e88907313843cf07f6d85ba8162120?d=identicon&s=25 alexeymuranov (Alexey Muranov) (Guest)
on 2013-10-18 06:58
(Received via mailing list)
Issue #8982 has been updated by alexeymuranov (Alexey Muranov).


nobu (Nobuyoshi Nakada) wrote:

> '#' at the beginning is assumed the string is same as Object#inspect, otherwise
its class name is appended since the string may not represent the class.

> If the `inspect` string is too long, just ignore it and use default conersion
method

Looks like defensive programming to me.
----------------------------------------
Bug #8982: NoMethodError#message produces surprising output when
#inspect is defined on an anonymous class
https://bugs.ruby-lang.org/issues/8982#change-42513

Author: myronmarston (Myron Marston)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:
ruby -v: ruby 2.0.0p247 (2013-06-27 revision 41674)
[x86_64-darwin12.4.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


=begin
Given the following script:

 def raise_no_method_error_for_anonymous_class_with_inspect(&block)
   klass = Class.new do
     define_method(:inspect, &block)
   end

   begin
     instance = klass.new
     puts "#inspect output: #{instance.inspect}
(#{instance.inspect.length} chars)"
     instance.undefined_method
   rescue NoMethodError => e
     puts e.message
   end

   puts
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "<MyAnonymousClass>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass #{'a' * 45}>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass #{'a' * 46}>"
 end

It produces the following output:

 #inspect output: #<MyAnonymousClass> (19 chars)
 undefined method `undefined_method' for #<MyAnonymousClass>

 #inspect output: <MyAnonymousClass> (18 chars)
 undefined method `undefined_method' for
<MyAnonymousClass>:#<Class:0x1017270e8>

 #inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (65 chars)
 undefined method `undefined_method' for #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>

 #inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (66 chars)
 undefined method `undefined_method' for
#<#<Class:0x1017266e8>:0x101726698>

There are two surprising things here:

* It matters whether or not the first character in my `inspect` is a
`#`.  If it's not, ruby appends the class's `#inspect` output to it.
* It matters how long my `inspect` string is.  If it's less than 66
characters, it's used; if it's more than 65, it's discarded, and the
default anonymous `#inspect` is used instead.

Both of these things are extremely surprising and seem very arbitrary
and inconsistent.

I brought this up on ruby parley and @charliesome was kind enough to
point me to the code that's the source of this issue:

((<error.c#L1091-1104|URL:https://github.com/ruby/ruby/blob/870dc20922d1ab0b...))

So it looks intentional, but I think this is a bug.
=end
42d4590355a1404230fbc9aff4dd377b?d=identicon&s=25 myronmarston (Myron Marston) (Guest)
on 2013-10-27 04:00
(Received via mailing list)
Issue #8982 has been updated by myronmarston (Myron Marston).


nobu (Nobuyoshi Nakada) wrote:
> myronmarston (Myron Marston) wrote:
> > * It matters whether or not the first character in my `inspect` is a `#`.  If
it's not, ruby appends the class's `#inspect` output to it.
>
> '#' at the beginning is assumed the string is same as Object#inspect, otherwise
its class name is appended since the string may not represent the class.

Ruby itself provides many classes whose definition of `inspect` does not
include `#`.  Why cannot it not allow me to do the same?  Also, `#` at
the beginning of the string being taken as a sign that it's the same
string as `Object#inspect` would produce seems incredibly broken.  And
I'm not sure why you care?  Why can't I define how my class is
represented as a string?  Isn't that the point of `inspect`?

> > * It matters how long my `inspect` string is.  If it's less than 66
characters, it's used; if it's more than 65, it's discarded, and the default
anonymous `#inspect` is used instead.
>
> If the `inspect` string is too long, just ignore it and use default conersion
method

Many of ruby's built-in classes can produce longer inspect strings than
this.  (As an example:`([1] * 1000).inspect`).  Ignoring what a user has
defined for `inspect` seems incredibly surprising and would be
considered a bug by every ruby programmer I know (well, every ruby
programmer I've shown this issue to, at least).

IMO, Ruby should either retain complete control over how objects
represent themselves strings, or allow users to define how objects are
represented as strings...but giving us the illusion that we can define
how objects represent themselves as strings, and then not actually
allowing that, is the worst possible outcome.

And this isn't just theoretical: I spent a couple hours a few weeks ago
scratching my head, trying to figure out why in the world my object's
`inspect` wasn't working.

----------------------------------------
Bug #8982: NoMethodError#message produces surprising output when
#inspect is defined on an anonymous class
https://bugs.ruby-lang.org/issues/8982#change-42631

Author: myronmarston (Myron Marston)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:
ruby -v: ruby 2.0.0p247 (2013-06-27 revision 41674)
[x86_64-darwin12.4.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


=begin
Given the following script:

 def raise_no_method_error_for_anonymous_class_with_inspect(&block)
   klass = Class.new do
     define_method(:inspect, &block)
   end

   begin
     instance = klass.new
     puts "#inspect output: #{instance.inspect}
(#{instance.inspect.length} chars)"
     instance.undefined_method
   rescue NoMethodError => e
     puts e.message
   end

   puts
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "<MyAnonymousClass>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass #{'a' * 45}>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass #{'a' * 46}>"
 end

It produces the following output:

 #inspect output: #<MyAnonymousClass> (19 chars)
 undefined method `undefined_method' for #<MyAnonymousClass>

 #inspect output: <MyAnonymousClass> (18 chars)
 undefined method `undefined_method' for
<MyAnonymousClass>:#<Class:0x1017270e8>

 #inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (65 chars)
 undefined method `undefined_method' for #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>

 #inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (66 chars)
 undefined method `undefined_method' for
#<#<Class:0x1017266e8>:0x101726698>

There are two surprising things here:

* It matters whether or not the first character in my `inspect` is a
`#`.  If it's not, ruby appends the class's `#inspect` output to it.
* It matters how long my `inspect` string is.  If it's less than 66
characters, it's used; if it's more than 65, it's discarded, and the
default anonymous `#inspect` is used instead.

Both of these things are extremely surprising and seem very arbitrary
and inconsistent.

I brought this up on ruby parley and @charliesome was kind enough to
point me to the code that's the source of this issue:

((<error.c#L1091-1104|URL:https://github.com/ruby/ruby/blob/870dc20922d1ab0b...))

So it looks intentional, but I think this is a bug.
=end
42d4590355a1404230fbc9aff4dd377b?d=identicon&s=25 unknown (Guest)
on 2014-09-12 08:47
(Received via mailing list)
Issue #8982 has been updated by Myron Marston.


So I've run into this issue again, and as it turns out, this is a much
more widespread problem than I first thought.  I originally thought that
this was just a problem with anonymous classes, but that's not the case;
now I'm running up against it in RSpec. We're trying to define
`RSpec::Core::ExampleGroup#inspect` so that when users have a typo (or
otherwise trigger a `NoMethodError` for a message sent to an example
group) the example group is represented in the error message in a
pretty, useful way, rather than having the obscure hex value:

https://github.com/rspec/rspec-core/issues/1590
https://github.com/rspec/rspec-core/pull/1687

As far as I can tell, it's impossible to achieve this behavior on MRI,
and that really bums me out :(.

Any chance this can get fixed in Ruby 2.2?

----------------------------------------
Bug #8982: NoMethodError#message produces surprising output when
#inspect is defined on an anonymous class
https://bugs.ruby-lang.org/issues/8982#change-48867

* Author: Myron Marston
* Status: Open
* Priority: Normal
* Assignee:
* Category:
* Target version:
* ruby -v: ruby 2.0.0p247 (2013-06-27 revision 41674)
[x86_64-darwin12.4.0]
* Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN
----------------------------------------
=begin
Given the following script:

 def raise_no_method_error_for_anonymous_class_with_inspect(&block)
   klass = Class.new do
     define_method(:inspect, &block)
   end

   begin
     instance = klass.new
     puts "#inspect output: #{instance.inspect}
(#{instance.inspect.length} chars)"
     instance.undefined_method
   rescue NoMethodError => e
     puts e.message
   end

   puts
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "<MyAnonymousClass>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass #{'a' * 45}>"
 end

 raise_no_method_error_for_anonymous_class_with_inspect do
   "#<MyAnonymousClass #{'a' * 46}>"
 end

It produces the following output:

 #inspect output: #<MyAnonymousClass> (19 chars)
 undefined method `undefined_method' for #<MyAnonymousClass>

 #inspect output: <MyAnonymousClass> (18 chars)
 undefined method `undefined_method' for
<MyAnonymousClass>:#<Class:0x1017270e8>

 #inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (65 chars)
 undefined method `undefined_method' for #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>

 #inspect output: #<MyAnonymousClass
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> (66 chars)
 undefined method `undefined_method' for
#<#<Class:0x1017266e8>:0x101726698>

There are two surprising things here:

* It matters whether or not the first character in my `inspect` is a
`#`.  If it's not, ruby appends the class's `#inspect` output to it.
* It matters how long my `inspect` string is.  If it's less than 66
characters, it's used; if it's more than 65, it's discarded, and the
default anonymous `#inspect` is used instead.

Both of these things are extremely surprising and seem very arbitrary
and inconsistent.

I brought this up on ruby parley and @charliesome was kind enough to
point me to the code that's the source of this issue:

((<error.c#L1091-1104|URL:https://github.com/ruby/ruby/blob/870dc20922d1ab0b...))

So it looks intentional, but I think this is a bug.
=end
This topic is locked and can not be replied to.