Mike Slinn

Ruby’s to_s and inspect Methods

Published 2025-09-04. Last modified 2025-09-05.
Time to read: 2 minutes.

This page is part of the ruby collection.

The to_s and inspect methods are defined in Object and all classes inherit them. To be precise, Object#to_s is inherited from Kernel#to_s. Many core classes override inspect to show more detail.

Output from recursive processes can be so enormous that the system stops functioning effectively.

Normal Output Vs Debug Output

Each method has a different purpose:

  • inspect is for debugging.
  • to_s is for normal operation.

To compare with Python, to_s is like __str__ and returns a string. In contrast, inspect is like __repr__; for example, inspecting a class instance displays the class name, the instance’s object_id in hexadecimal, and then the method recursively calls itself for each instance variable within the class instance.

The default output of both methods can be very different, as shown in this irb session:

irb
$ irb
irb(main):001> nil.to_s
=> ""
irb(main):002>
nil.inspect => "nil"

Stack Dumps

Stack dumps can be problematic when working with large data structures. For example, when debugging Jekyll plugins and a stack dump occurs, even a powerful computer can be brought to its virtual knees for 10 minutes or longer as the default implementation of inspect painfully traverses the entire data structure and displays it on screen after screen of mostly useless information. The only way to terminate the dump is to terminate the Visual Studio Code process or press the reset button on your computer.

When defining a custom class that has a large data structure to traverse, be sure to define inspect in such a way that it displays a minimum of information. Your code could respond to an environment variable that determines whether recursive data structures should be traversed or not, for example. This will eliminate the superfluous output when dumping stacks containing your custom classes.

Monkey Patching

If you are working with a Ruby gem that is dumping huge amounts of output as it raises exceptions, fear not, you can monkey patch the gem quite easily. For example, the Jekyll gem has large recursive data structures that really get in your face when the plugin you are working on raises StandardError. The solution is to selectively override the problematic inspect method definitions in the gem with significantly less verbose definitions. Some of the classes that you will probably need to override are Jekyll::Page, Jekyll::Post, and Jekyll::Document.

The following example code below demonstrates a minimal set of monkey patches for Jekyll. With this in place, stack dumps will be a lot easier to understand at a high level. You could tweak the code to display more information if desired.

monkey_patch_jekyll.rb
module Jekyll
  class Page
    def inspect
      "#<Jekyll::Page path=#{path}>"
    end
  end

  class Document
    def inspect
      "#<Jekyll::Document relative_path=#{relative_path}>"
    end
  end

  class Site
    def inspect
      "#<Jekyll::Site source=#{source}>"
    end
  end

  class Post
    def inspect
      "#<Jekyll::Post path=#{path}>"
    end
  end
end
😁

There are two ways of invoking the above. Once invoked, stack dumps that reference Jekyll data structures will be dramatically shorter. Life will be so much better!

  1. To just affect dumps from the Jekyll project you are working on, place monkey_patch_jekyll.rb in your project’s _plugins/ folder, The full path from the Jekyll project root would be _plugins/monkey_patch_jekyll.rb.
  2. To affect dumps from every Jekyll project that uses your plugin, place monkey_patch_jekyll.rb in the lib/ directory of the plugin and require it from any source file that is loaded.
    Ruby code
    require_relative 'monkey_patch_jekyll.rb'

The Joy of Aliases

The following code sets up to_s and a minimal version of inspect, but also makes the original version of inspect available as inspect_original.

Ruby code
class MyClass
  def initialize
    @x = 1
    @y = 'a'
  end

  def to_string = "x=#{@x} y=#{@y}"

# Order is important: alias inspect_original inspect alias inspect to_string alias to_s to_string
end

We can exercise the above code to verify that to_s and inspect are aliased to the to_string method, and the original inspect method is still available as inspect_original.

irb
irb(main):013> my_class = MyClass.new
=> x=1 y=a 
irb(main):014>
my_class.to_s => "x=1 y=a"
irb(main):015>
my_class.to_string => "x=1 y=a"
irb(main):016>
my_class.inspect => "x=1 y=a"
irb(main):017>
my_class.inspect_original => "#<MyClass:0x000074ce7f3aab98 @x=1, @y=\"a\">"
* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.