Ruby’s dig methods are useful for accessing nested data
structures.
Consider this data:
item = { id: "0001", type: "donut", name: "Cake", ppu: 0.55, batters: { batter: [ {id: "1001", type: "Regular"}, {id: "1002", type: "Chocolate"}, {id: "1003", type: "Blueberry"}, {id: "1004", type: "Devil's Food"} ] }, topping: [ {id: "5001", type: "None"}, {id: "5002", type: "Glazed"}, {id: "5005", type: "Sugar"}, {id: "5007", type: "Powdered Sugar"}, {id: "5006", type: "Chocolate with Sprinkles"}, {id: "5003", type: "Chocolate"}, {id: "5004", type: "Maple"} ] }
Without a dig method, you can write:
item[:batters][:batter][1][:type] # => "Chocolate"
With a dig method, you can write:
item.dig(:batters, :batter, 1, :type) # => "Chocolate"
Without a dig method, you can write, erroneously (raises
NoMethodError (undefined method `[]' for nil:NilClass)):
item[:batters][:BATTER][1][:type]
With a dig method, you can write (still erroneously, but
avoiding the exception):
item.dig(:batters, :BATTER, 1, :type) # => nil
dig Better?¶ ↑It has fewer syntactical elements (to get wrong).
It reads better.
It does not raise an exception if an item is not found.
dig Work?¶ ↑The call sequence is:
obj.dig(*identifiers)
The identifiers define a “path” into the nested data
structures:
For each identifier in identifiers, calls method #dig on a
receiver with that identifier.
The first receiver is self.
Each successive receiver is the value returned by the previous call to
dig.
The value finally returned is the value returned by the last call to
dig.
A dig method raises an exception if any receiver does not
respond to #dig:
h = { foo: 1 } # Raises TypeError (Integer does not have #dig method): h.dig(:foo, :bar)
The structure above has Hash objects and Array objects, both of which have
instance method dig.
Altogether there are six built-in Ruby classes that have method
dig, three in the core classes and three in the standard
library.
In the core:
Array#dig: the first argument is an Integer index.
Hash#dig: the first argument is a key.
Struct#dig: the first argument is a key.
In the standard library:
OpenStruct#dig: the first argument is a String name.
CSV::Table#dig: the first argument is an Integer index or a String header.
CSV::Row#dig: the first argument is an Integer index or a String header.