Hash#fetch is not relevant here. That's because fetch
is the same as Hash#[] when, as here, fetch
has only a single argument. So let's concentrate on dig
.
A family of three dig
methods were introduced in Ruby v2.3: Hash#dig, Array#dig and OpenStruct#dig. An interesting thing about these methods is that they invoke each other (but that's not explained in the docs, not even in the examples). In your problem we can write:
response.dig(:results, 0, :value, :destination)
#=> "Rome"
response
is a hash so Hash#dig
evaluates response[:results]
. If it's value is nil
then the expression returns nil
. For example,
response.dig(:cat, 0, :value, :destination)
#=> nil
In fact, response[:results]
is an array:
arr = response[:results]
#=> [{:type=>"product_group", :value=>{:destination=>"Rome"}},
# {:type=>"product_group", :value=>{:destination=>"Paris"}},
# {:type=>"product_group", :value=>{:destination=>"Madrid"}}]
Hash#dig
therefore invokes Array#dig
on arr
, obtaining the hash
h = arr.dig(0)
#=> {:type=>"product_group", :value=>{:destination=>"Rome"}}
Array#dig
then invokes Hash#dig
on h
:
g = h.dig(:value)
#=> {:destination=>"Rome"}
Lastly, g
being a hash, Hash#dig
invokes Hash#dig
on g
:
g.dig(:destination)
#=> "Rome"
Caution needs to be exercised when using any of the dig
's. Suppose
arr = [[1,2], [3,[4,5]]]
and we wish to pull out the object that is now occupied by 4
. We could write either
arr[1][1][0]
#=> 4
or
arr.dig(1,1,0)
#=> 4
Now suppose arr
were changed as follows:
arr = [[1,2]]
Then
arr[1][1][0]
#=> NoMethodError: undefined method `[]' for nil:NilClass
and
arr.dig(1,1,0)
#=> nil
Both are indicative of there being an error in our code, so raising an exception would be preferable to nil
being returned, which may go unnoticed for some time.