Customize your Ruby classes with to_s and inspect
Share this
You just did an “extract class” refactor, and now your program’s output is all wrong. How do you fix it?
Take this simple program as a starting point:
print "What is your name? "
name = gets.strip
print "Hello ", name, "\n"
The program asks for your name, and says hello. Simple.
Did you know you can run Ruby programs from the command line, without saving them to a file first? Just run ruby from the command line, with no arguments. It will wait for input. Then paste your code and hit return. Finally, type ctrl-d to close the input. Ruby now runs the program, and all you had to do was a simple copy and paste!
Now you want to create your own class, to encapsulate the concept of a person in your application:
class Person
def initialize(name)
@name = name
end
end
print "What is your name? "
person = Person.new(gets.strip)
print "Hello ", person, "\n"
Uh-oh! You get some hideous output: Hello #<Person:0x007ffdb9833600>
(the random numbers will be different for you). What gives?
Work your way from the top-down to see what’s going on. The class is a straight-forward class definition. Line 7 simply prints a string to the screen. On line 8, you call gets.strip
- what does it do?
According to the official Ruby documentation, gets
returns a string object read from standard input, and then strip
removes any leading and trailing whitespace (e.g. spaces, newlines).
The built-in print
method prints a string representation of any objects that you pass to it. The first example works because gets
returns a string object, so you don’t need to do anything special. But for other kinds of objects, you have a bit more work to do… print
will convert a non-string object to a string using the object’s to_s
method - shorthand for “to string”.
To customize how Ruby displays a Person
object in this program, you need to define a custom to_s
method:
class Person
def initialize(name)
@name = name
end
def to_s
@name
end
end
print "What is your name? "
person = Person.new(gets.strip)
print "Hello ", person, "\n"
This example just returns the string object stored in the @name
instance variable… but with a custom to_s
method, you can define any behavior that you want:
class Person
def initialize(name)
@name = name
end
def to_s
case @name
when "Oz"
"Oz, the great and powerful"
else
@name
end
end
end
print "What is your name? "
person = Person.new(gets.strip)
print "Hello ", person, "\n"
Another way to to_s
In the examples so far, you’ve used print
with multiple arguments. You can also convert an object to a string using the #{}
operator inside of a double-quoted string:
print "Hello #{person}\n"
This is known as “string interpolation.”
Finally, you can simplify the last line by using puts
instead of print
. puts
works the same as print, but automatically includes a newline character:
puts "Hello #{person}"
It’s not all about output…sometimes you need to debug
You’ve learned how to customize how your object displays on screen, but there’s one case where your custom to_s
method will still fall short: when you have an error message that involves your object.
Run the following code, which will fail with a NoMethodError
:
class Person
def initialize(name)
@name = name
end
def to_s
case @name
when "Oz"
"Oz, the great and powerful"
else
@name
end
end
end
print "What is your name? "
person = Person.new(gets.strip)
person.foo
You’ll get an error message that looks something like: undefined method 'foo' for #<Person:0x007f8b122977b0 @name="Pat"> (NoMethodError)
. That looks kind of like a combination of the earlier, non-customized to_s
, and the newly customized version. What’s going on now?
Ruby uses another method called inspect
in situations where you might want to get a bit more info on the objects than the simple string representation you use for regular output.
Add a bit of private information that you don’t want to display all over the app… like a social security number:
class Person
def initialize(name)
@name = name
@ssn = "111-11-1111"
end
def to_s
@name
end
end
print "What is your name? "
person = Person.new(gets.strip)
print "Hello ", person, "\n"
When the program says hello, it will hide the person’s social security number - which is what you probably want! But that extra information can come in really handy when you’re debugging. Define a custom inspect
method, and Ruby will show you that extra information whenever you have an error involving that object:
class Person
def initialize(name)
@name = name
@ssn = "111-11-1111"
end
def to_s
@name
end
def inspect
"Person(name: #{@name}, ssn: #{@ssn}, object_id: #{"0x00%x" % (object_id << 1)})"
end
end
print "What is your name? "
person = Person.new(gets.strip)
person.foo
Now you have complete control over the debug output and get something like undefined method 'foo' for Person(name: Pat, ssn: 111-11-1111, object_id: 0x007fddfb2171f0):Person (NoMethodError)
.
The awesome_print gem provides a really nifty way of printing entire object structures in a readable way, so you don’t even have to create your own custom method.
Wrap up
Output plays a big role in any application, and knowing the different ways you can customize an object’s output will help you write programs that work the way you want, and help you with debugging.
Go ahead and customize your own Ruby classes with to_s
and inspect
!
Share this
You spent $15,000 and 6 months learning Ruby... so why won't anyone hire you?
What if you could get Ruby on Rails companies to fight over you?
Learn how in my free video, The 3 most important skills you need to become a successful Ruby developer.