Предположим, мы выполняем
{ :a=>{:b=>{:c=>3 } } }.get_value(4, :a, :b, :c)
так что внутри метода
default #=> 4
args #=> [:a, :b, :c]
self #=> { :a=>{:b=>{:c=>3 } } }
Затем мы выполняем следующее1:
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
Если args #=> [:a, :b]
, мы выполняем следующее:
[:a, :b].empty? ? 4 : [:a, :b].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> {:c=>3}
Если args #=> [:a, :b, :cat]
, то возникает исключение KeyError
, а встроенный rescue
возвращает значение default
:
[:a, :b, :cat].empty? ? 4 : [:a, :b, :cat].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> 4
и если args #=> []
, [].empty?
равно true
, то снова возвращается значение default
:
[].empty? ? 4 : [].reduce({ :a=>{:b=>{:c=>3 } } }) { |acum, key|
acum.fetch(key) } rescue 4
#=> 4
К счастью, нам больше не приходится заниматься такой ерундой, как нам дали Hash#dig в Ruby 2.3.0, что позволяет нам написать следующее.
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
Обратите внимание, что получателем dig
по умолчанию является self
.
1 Обратите внимание, что вместо ...args.reduce(self) { |acum, key| acum.fetch(key) } rescue default
автор этого кода мог написать ...args.reduce(self) { |acum, key| acum.fetch(key, default) }
. См. раздел Hash#fetch.
person
Cary Swoveland
schedule
17.09.2016