Project

General

Profile

Feature #15563

Updated by sawa (Tsuyoshi Sawada) about 4 years ago

Ruby 2.3.0 introduced `#dig` for `Array`, `Hash` *Array*, *Hash* and `Struct`. *Struct*. Both `Array` *Array* and `Hash` *Hash* have `#fetch`, `#fetch` which works does the same way as `#[]`, but instead of returning the default value, raises value an exception is raised (unless a second argument or block is given). `Hash` *Hash* also has `#fetch_values`, `#fetch_values` which works does the same way as `#values_at`, raising an exception if a an key is missing. For `#dig`, `#dig` there is no such option. 

 My proposal is to add a method that works which does the same way as `#dig`, but instead of using the `#[]` accessor, accessor it uses `#fetch`. 

 This method would look something like this: 

 ```Ruby 
 module Traversable 
   def traverse(key, *others) 
     value = fetch(key) 
     return value if others.empty? 

     if value.respond_to?(__method__, true) 
       value.send(__method__, *others) 
     else 
       raise TypeError, "#{value.class} does not have ##{__method__} method" 
     end 
   end 
 end 

 Array.include(Traversable) 
 Hash.include(Traversable) 
 ``` 

 The exception raised is taken from `#dig` (`[1].dig(0, 1) #=> TypeError: Integer does not have #dig method`). 

 ```Ruby 
 yaml = YAML.load_file('some_file.yml') 

 # this change is meant to make chaining #fetch calls more easy 
 yaml.fetch('foo').fetch('bar').fetch('baz') 

 # would be replaced with 
 yaml.traverse('foo', 'bar', 'baz') 
 ``` 

 I'm curious to hear what you guys think about the idea as a whole and the method name. 
 

Back