简体   繁体   中英

override to_s while keeping output of inspect

i override the to_s method to get pretty output when i use puts but at the same time i seem to loose my ability to inspect the object. Is there a way to get the normal output of inspect while overriding to_s ?

class Person
  attr_accessor :first, :last, :birthdate
  def initialize(first=nil, last=nil, birthdate=nil)
    @first, @last, @birthdate = first, last, birthdate
  end
  def age
    if birthdate
      Time.now.year-birthdate
    else
      0
    end
  end
  def to_s
    "#{@first} #{@last} (#{age})"
  end
end

me = Person.new("Peter", "Marien", 1962)
p me  >>Peter Marien (50)
p me.inspect  >>"Peter Marien (50)"

#Need #<Person:0x1ec2550 @first="Peter", @last="Marien", @birthdate=1962>

Ruby documentation clearly states , that by default inspect uses to_s as its output.

If you don't need the address of the object, you could provide your own inspect, to have almost the same behavior:

class Person
  def inspect
    vars = self.instance_variables.
      map{|v| "#{v}=#{instance_variable_get(v).inspect}"}.join(", ")
    "<#{self.class}: #{vars}>"
  end
end

But you could also install a gem called awesome_print that will give very nice output. First in console:

$ gem install awesome_print

then in irb or your script:

require 'awesome_print'
ap Person.new("John")

There is also a built-in pp library, which have similar purpose. Still it is not immune (at least in Ruby 1.9.2-p290) to overriding of to_s .

A quick example of pp :

require 'pp'
pp Person.new("John")

I believe that by default inspect uses the to_s method.

However, you could also override inspect, including aliasing the old to_s method to it before overriding.

Here the sollution of Aleksander, the first p should give the overridden to_s but doesn't, you have to explictly call to_s like in the second p to get the result i want. I'm also not sure this inspect will give the same result as the original one with more complex objects, i'll try it at home. Anyone a still better shot ? I'm aware of the awesome_print gem but IMHO for something basic like this you shouldn't need to include gems.

class Person

  def initialize(first=nil, last=nil, birthdate=nil) 
    @first, @last, @birthdate = first, last, birthdate 
  end 

  # New implementation of to_s 
  def to_s 
    "#{@first} #{@last}" 
  end

  def inspect 
    vars = self.instance_variables. 
      map{|v| "#{v}=#{instance_variable_get(v).inspect}"}.join(", ") 
    "<#{self.class}: #{vars}>" 
  end 

end 

me = Person.new("John")
p me         #--><Person: @first="John", @last=nil, @birthdate=nil>
p me.to_s    #-->"John "
p me.inspect #-->"<Person: @first=\"John\", @last=nil, @birthdate=nil>"

Edit: i just tried awesome_print and i'm pleased, was afraid i had to use IRB to make use of it but it isn't, i run my scripts in my editor namely

require 'awesome_print'
ap me --> 
#<Person:0x027efe20
    @birthdate = nil,
    @first = "John",
    @last = nil
>

Edit, using pretty_print as suggested by Aleksander, doesn't interfere with the overridden to_s

require 'PP'
class Person

  def initialize(first=nil, last=nil, birthdate=nil) 
    @first, @last, @birthdate = first, last, birthdate 
  end 

  # New implementation of to_s 
  def to_s 
    "#{@first} #{@last}" 
  end
end 

me = Person.new("John")
pp me                   #--> <Person: @first="John", @last=nil, @birthdate=nil>
warn me.pretty_inspect  #--> <Person: @first="John", @last=nil, @birthdate=nil>

Perry, here one of the many combinations i tried to get alias or alias_method to work, if you think this works, can you submit a working snippet ?

class Person
  attr_accessor :first, :last, :birthdate
  def initialize(first=nil, last=nil, birthdate=nil)
    @first, @last, @birthdate = first, last, birthdate
  end

  alias old_to_s to_s
  def inspect
    old_to_s
  end
  def to_s
    "#{@first} #{@last}"
  end

end

me = Person.new("Peter")
p me         #-->#<Person:0x1da26b8>
p me.inspect #-->"#<Person:0x1da26b8>"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM