Project

General

Profile

Actions

Bug #20808

closed

Data#pretty_print doesn't handle private or remove attribute readers

Added by maicolben (Maicol Bentancor) 10 months ago. Updated 9 months ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:119575]

Description

Given the next code:

Dog = Data.define(:name) do
  def inspect
    "Hello!"
  end

  private
  attr_reader :name
end

Dog.new(name: "Fido")

It throws an error:

  • An error occurred when inspecting the object: #<NoMethodError: private method `name' called for an instance of Dog>

And isn't using my inspect function

Updated by byroot (Jean Boussier) 10 months ago

So the problem isn't with inspect, as it only reproduce in irb.

It's coming from pretty_inspect:

>> d.pretty_inspect
/opt/rubies/3.3.5/lib/ruby/3.3.0/pp.rb:432:in `public_send': private method `name' called for an instance of Dog (NoMethodError)

          q.pp public_send(member)
               ^^^^^^^^^^^
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/pp.rb:432:in `block (3 levels) in pretty_print'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:255:in `block (2 levels) in group'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:282:in `nest'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:254:in `block in group'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:267:in `group_sub'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:253:in `group'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/pp.rb:430:in `block (2 levels) in pretty_print'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/pp.rb:264:in `block in seplist'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/pp.rb:258:in `each'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/pp.rb:258:in `seplist'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/pp.rb:426:in `block in pretty_print'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:255:in `block (2 levels) in group'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:282:in `nest'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:254:in `block in group'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:267:in `group_sub'
	from /opt/rubies/3.3.5/lib/ruby/3.3.0/prettyprint.rb:253:in `group'

Updated by byroot (Jean Boussier) 10 months ago

The pp implementation for Struct and Data both assume all member readers are public:

class Struct # :nodoc:
  def pretty_print(q) # :nodoc:
    q.group(1, sprintf("#<struct %s", PP.mcall(self, Kernel, :class).name), '>') {
      q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member|
        q.breakable
        q.text member.to_s
        q.text '='
        q.group(1) {
          q.breakable ''
          q.pp self[member]
        }
      }
    }
  end

  def pretty_print_cycle(q) # :nodoc:
    q.text sprintf("#<struct %s:...>", PP.mcall(self, Kernel, :class).name)
  end
end

class Data # :nodoc:
  def pretty_print(q) # :nodoc:
    q.group(1, sprintf("#<data %s", PP.mcall(self, Kernel, :class).name), '>') {
      q.seplist(PP.mcall(self, Data, :members), lambda { q.text "," }) {|member|
        q.breakable
        q.text member.to_s
        q.text '='
        q.group(1) {
          q.breakable ''
          q.pp public_send(member)
        }
      }
    }
  end

  def pretty_print_cycle(q) # :nodoc:
    q.text sprintf("#<data %s:...>", PP.mcall(self, Kernel, :class).name)
  end
end if "3.2" <= RUBY_VERSION

Updated by byroot (Jean Boussier) 10 months ago

Struct and Data both assume all member readers are public:

Actually I misread. The Struct one uses Struct#[] so it would work with Struct. Data however has no such method, so two solutions I can think of are:

  • Use send, but only work for private. If instead the method is renamed or removed, it will still fail.
  • Rescue NoMethodError, and skip displaying that field.

Updated by byroot (Jean Boussier) 10 months ago

cc @akr (Akira Tanaka) , as maintainer of PP perhaps you have an opinion on how this sort of issue should be handled?

Updated by mame (Yusuke Endoh) 10 months ago

The code in question is written by @osyo and committed by @nobu (Nobuyoshi Nakada). Just FYI.

Actions #6

Updated by byroot (Jean Boussier) 10 months ago

  • Subject changed from Cannot override Data#inspect to Data#pretty_print doesn't handle private or remove attribute readers

Updated by mame (Yusuke Endoh) 9 months ago

Discussed the dev meeting. @akr (Akira Tanaka) said using __send__ instead of public_send would be good.

Actions #9

Updated by byroot (Jean Boussier) 9 months ago

  • Status changed from Open to Closed

Applied in changeset git|107a4da122126e6d0e0ad12898d7511e472709a3.


[ruby/pp] Data#pretty_print handle privated or removed members

[Bug #20808]

The previous implementation assumed all members are accessible,
but it's possible for users to change the visibility of members or
to entirely remove the accessor.

https://github.com/ruby/pp/commit/fb19501434

Actions

Also available in: Atom PDF

Like0
Like1Like0Like1Like0Like0Like0Like0Like1Like1