Found this on code wars as one of the solutions. Can someone explain to me how "args.reduce(self)" works in this code; the block after makes sense.
config = { :files => { :mode => 0x777 }, :name => "config" }
class Hash
def get_value( default, *args )
args.empty? ? default : args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
end
end
config.get_value("", :files,:mode)
Suppose we execute
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :c)
so that within the method
default #=> 4
args #=> [:a, :b, :c]
self #=> { :a=>{:b=>{:c=>3 } } }
We then execute the following1:
args.empty? ? default : args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
#=> [:a, :b, :c].empty? ? 4 : [:a, :b, :c].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
# acum.fetch(key) } rescue 4
#=> 3
If args #=> [:a, :b]
, we execute the following:
[:a, :b].empty? ? 4 : [:a, :b].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> {:c=>3}
If args #=> [:a, :b, :cat]
, then a KeyError
exception is raised and the inline rescue
returns the value of default
:
[:a, :b, :cat].empty? ? 4 : [:a, :b, :cat].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> 4
and if args #=> []
, [].empty?
is true
, so the value of default
is again returned:
[].empty? ? 4 : [].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> 4
Fortunately, we no longer have to deal with such nonsense as we were given Hash#dig in Ruby 2.3.0, allowing us to write the following.
class Hash
def get_value( default, *keys )
keys.empty? ? default : dig(*keys) || default
end
end
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :c)
#=> 3
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b)
#=> {:c=>3}
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :cat)
#=> 4
{ :a=>{:b=>{:c=>3 } } }.get_value(4)
#=> 4
Note that the default receiver of dig
is self
.
1 Note that instead of ...args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
the author of that code could have written ...args.reduce(self) { |acum, key| acum.fetch(key, default) }
. See Hash#fetch.