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:
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(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.rb
in 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.rb
in thelib/
directory of the plugin andrequire
it 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_stringend
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\">"