A Deep Dive Into the Ruby Puts Method


Most programmers are familiar with the traidition of the “Hello World” program. New programmers use it as their first program. Experienced programmers use it to prove that their new project can run correctly.

Ruby makes “Hello World” trivially easy:

puts "Hello World"

The puts method is one of the workhorses of the ruby core library. It is the most common of the methods in the IO module. But what is actually going on here?

The method signature of puts is as follows:

puts(obj,...) -> nil

That is, puts takes zero or more objects and returns nil.

Puts is defined in the IO core class1. This class ships with the core of ruby and provides ‘the basis for all input and output in ruby’ 2.

When you call puts without an explicit context, as with the hello world program, the method call is delegated through the main object that exists at the top level of all ruby programs to an IO object that is bound to the standard input and standard output. Ruby provides constant objects STDOUT, STDIN, and STDERR by default, which are all IO objects bound to the appropriate ‘files’3.

Hence, the two lines are functionally equivalent:

puts "Hello World"
STDOUT.puts "Hello World!"

Where is puts defined? Like many of the core ruby classes, IO is defined directly in the underlying C code. The current source of the IO code can be found in io.c.

puts is actually defined in two places; once using the rb_define_method C function to associate the rb_io_puts C function with the puts method on the ruby IO class, found around line 12187 in io.c. puts is also defined with the rb_define_global_function C function on line 12106, to associate a special version of puts, rb_f_puts, with the ruby Kernel class. These methods provide the actual functionality of puts, which is a thin wrapper around the more basic write method.

Puts provides the following functionality:

The last bit means that calling puts on nested arrays will print each element of each array with .to_s on a separate line. To print an array in the format to which you are accustomed to defining them, use .to_s on the array explicitly.

The fact that puts will not add a newline if the string to be printed already ends in a newline is worth noting. Because of this functionality, the following lines are equivalent, which can be an issue when debugging:

puts "Hello"
puts "Hello\n"

Happy Coding!

  1. http://ruby-doc.org/core-2.2.0/IO.html#method-i-puts

  2. http://ruby-doc.org/core-2.2.0/IO.html

  3. Philosophically, in Unix, ‘everything is a file’. So writing to or reading from the terminal is just reading and writing to a file that is connected to the terminal.

I'm looking for better ways to build software businesses. Find out if I find something.