Bug #20808
closedData#pretty_print doesn't handle private or remove attribute readers
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) about 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) about 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) about 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) about 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) about 2 months ago
The code in question is written by @osyo (manga osyo) and committed by @nobu (Nobuyoshi Nakada). Just FYI.
Updated by byroot (Jean Boussier) about 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 1 month ago
Discussed the dev meeting. @akr (Akira Tanaka) said using __send__
instead of public_send
would be good.
Updated by byroot (Jean Boussier) about 1 month ago
Proposed patch: https://github.com/ruby/pp/pull/29
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.