Print Statements in Ruby
November 4, 2021A multitude of ways to print information to the screen exist in Ruby.
At 9,029,8501 results the most popular seems to be puts
.
Nothing wrong with puts
— it’s a solid way to print out strings:
irb(main):010:0> puts 23, 42.0, "hello", {a: 1}
23
42.0
hello
{:a=>1}
=> nil
Well, until you try to print an Array
.
irb(main):011:0> puts 23, 42.0, "hello", {a: 1}, [1, 2, 3]
23
42.0
hello
{:a=>1}
1
2
3
=> nil
Why does this happen?
Thankfully Ruby comes with a built-in documentation command for methods.
It’s aptly named help
.
If we ask Ruby to tell us about puts
…
irb(main):012:0> help 'puts'
=> nil
Nothing.
Ruby allows implicit calls to Kernel
module procedures by your program, so we asked the wrong thing.
Trying again we get something more useful.
irb(main):013:0> help 'Kernel#puts'
= Kernel#puts
(from ruby core)
------------------------------------------------------------------------
puts(obj, ...) -> nil
------------------------------------------------------------------------
Equivalent to
$stdout.puts(obj, ...)
Well, marginally more useful anyway.
At least we know it’s equal to $stdout.puts(obj, ...)
now though, but what’s $stdout
?
Let’s ask!
irb(main):014:0> $stdout.class
=> IO
An instance of the IO
class.
Now we can ask about IO#puts
.
irb(main):015:0> help 'IO#puts'
= IO#puts
...
Writes the given object(s) to ios. Writes a newline after any that
do not already end with a newline sequence. Returns nil.
The stream must be opened for writing. If called with an array argument,
writes each element on a new line. Each given object that isn't a string
or array will be converted by calling its to_s method. If called without
arguments, outputs a single newline.
Here we are: iterate over arrays to print each element and everything else receives a to_s
call.2
These make puts
decent for quick scripts, but not so great for print debugging.
For debugging replace puts
with p
.
It’s shorter to type and works the same way as puts
except it calls the inspect
method instead of to_s
.
irb(main):016:0> p 23, 42.0, "hello", {a: 1}, [1, 2, 3]
23
42.0
"hello"
{:a=>1}
[1, 2, 3]
=> [23, 42.0, "hello", {:a=>1}, [1, 2, 3]]
If you’ve got a sharp eye you’ll have noticed p
returned an array of the values it received.
It handles a single value too.
irb(main):017:0> help 'Kernel#p'
= Kernel#p
(from ruby core)
------------------------------------------------------------------------
p(obj) -> obj
p(obj1, obj2, ...) -> [obj, ...]
p() -> nil
------------------------------------------------------------------------
For each object, directly writes obj.inspect followed by a newline
to the program's standard output.
Pass it a single object and it returns it after printing the representation.
Debugging the return values of method calls or expressions is as simple as placing p
in front.
irb(main):018:0> n = p rand(1..100)
29
=> 29
irb(main):019:0> n + 1
=> 30
Superbly unobtrusive.
-
Using this search at the time of writing. ↩︎
-
Neat! It also avoids writing a newline if the object’s string representation ends in one. I didn’t know this. ↩︎