Published 2025-09-04.
Last modified 2025-09-05.
Time to read: 2 minutes.
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:
inspectis for debugging.to_sis 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(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.
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!
-
To just affect dumps from the Jekyll project you are working on,
place
monkey_patch_jekyll.rbin your project’s_plugins/folder, The full path from the Jekyll project root would be_plugins/monkey_patch_jekyll.rb. -
To affect dumps from every Jekyll project that uses your plugin,
place
monkey_patch_jekyll.rbin thelib/directory of the plugin andrequireit from any source file that is loaded.Ruby coderequire_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.
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(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\">"