Skip to content

Latest commit

 

History

History
72 lines (56 loc) · 3.37 KB

overriding_inspect.md

File metadata and controls

72 lines (56 loc) · 3.37 KB

Inspecting Complex Objects

When we start dealing with complex objects, and in particular objects that hold recursive references to other objects, the information provided to us by inspect (what you see when you use p instead of puts) can quickly become overwhelming and unreadable. To see an example of this, take a look at the output for a failed spec on the PolyTreeNode class:

1) PolyTreeNode#parent= does not add the same node twice
     Failure/Error: expect(node1.children).to eq([node2, node3])

       expected: [#<PolyTreeNode:0x007f8092bbc0f0 @parent=#<PolyTreeNode:0x007f8092bbc078 @parent=nil, @children=[#<PolyTreeNode:0x007f8092bbc0f0 ...>, #<PolyTreeNode:0x007f8092bc7f90 @parent=#<PolyTreeNode:0x007f8092bbc078 ...>, @children=[], @value="child2">, #<PolyTreeNode:0x007f8092bc7f90 @parent=#<PolyTreeNode:0x007f8092bbc078 ...>, @children=[], @value="child2">], @value="root">, @children=[], @value="child1">, #<PolyTreeNode:0x007f8092bc7f90 @parent=#<PolyTreeNode:0x007f8092bbc078 @parent=nil, @children=[#<PolyTreeNode:0x007f8092bbc0f0 @parent=#<PolyTreeNode:0x007f8092bbc078 ...>, @children=[], @value="child1">, #<PolyTreeNode:0x007f8092bc7f90 ...>, #<PolyTreeNode:0x007f8092bc7f90 ...>], @value="root">, @children=[], @value="child2">]
            got: [#<PolyTreeNode:0x007f8092bbc0f0 @parent=#<PolyTreeNode:0x007f8092bbc078 @parent=nil, @children=[...], @value="root">, @children=[], @value="child1">, #<PolyTreeNode:0x007f8092bc7f90 @parent=#<PolyTreeNode:0x007f8092bbc078 @parent=nil, @children=[...], @value="root">, @children=[], @value="child2">, #<PolyTreeNode:0x007f8092bc7f90 @parent=#<PolyTreeNode:0x007f8092bbc078 @parent=nil, @children=[...], @value="root">, @children=[], @value="child2">]

We may have a good guess, but it's tough to verify the problem based on the expected: / got: difference. Which nodes are supposed to be in the children array, and which are actually there?

One way we can simplify this process is by specifying what information we want to see when we inspect an object. In this case, we may only be interested in what a Node's value is. We can do this by overriding the default inspect instance method for our class (this is inherited from Object).

class PolyTreeNode
  # ...
  # ...
  def inspect
    @value.inspect
  end
end

The rspec output now looks like this:

1) PolyTreeNode#parent= does not add the same node twice
   Failure/Error: expect(node1.children).to eq([node2, node3])

     expected: ["child1", "child2"]
          got: ["child1", "child2", "child2"]

Much better!

We can output more complex information as well, for example:

class PolyTreeNode
  # ...
  # ...
  def inspect
    { 'value' => @value, 'parent_value' => @parent.value }.inspect
  end
end

This causes the rspec output to display as below.

1) PolyTreeNode#parent= does not add the same node twice
     Failure/Error: expect(node1.children).to eq([node2, node3])

       expected: [{"value"=>"child1", "parent_value"=>"root"}, {"value"=>"child2", "parent_value"=>"root"}]
            got: [{"value"=>"child1", "parent_value"=>"root"}, {"value"=>"child2", "parent_value"=>"root"}, {"value"=>"child2", "parent_value"=>"root"}]

Overriding inspect isn't always necessary, and you won't do it in every case. However it's an excellent option if you're having trouble reading rspec output or finding needed data in your objects when debugging.