Project

General

Profile

Actions

Bug #20808

closed

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

Added by maicolben (Maicol Bentancor) 2 months ago. Updated about 1 month 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) 2 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) 2 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) 2 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) 2 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) 2 months ago

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

Actions #6

Updated by byroot (Jean Boussier) 2 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) about 2 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) about 1 month 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