Вы можете создать метод, который продолжает вызывать метод #[]
для возвращаемого значения предыдущего вызова, если он возвращает что-либо:
def nested_accessor(object, *keys)
keys.reduce(object) do |current, key|
current[key] if current
end
end
и затем вы можете вызвать этот метод, например:
class Node
def initialize
@attributes = {
'my' => {
'application' => {
'version' => '0.0.1',
'name' => 'Test App'
},
'config' => {
'key' => 'value'
}
}
}
end
def [](attrib)
@attributes[attrib]
end
end
node = Node.new
nested_accessor(node, 'my', 'application', 'version') # => "0.0.1"
nested_accessor(node, 'my', 'config') # => {"key"=>"value"}
nested_accessor(node, 'someone elses', 'application', 'version') # => nil
если у вас уже есть нужные ключи в массиве, вам просто нужно разделить массив в списке параметров:
nested_accessor(node, *['my', 'application', 'version'])
Метод nested_accessor
будет работать с любым объектом, при условии, что этот объект и каждый объект, возвращенный из вызова #[]
, отвечают методу #[]
или nil
(или false
).
Кроме того, в Ruby есть метод для Hash
и Array
, называемый dig
, который делает что-то похожее на это, он будет продолжать вызывать dig
на каждом промежуточном шаге, пока не будет возвращено nil
или у него больше нет ключей, которые нужно проверять. Я бы обычно рекомендовал этот метод, но так как это пользовательский объект, который, похоже, не имеет метода dig
, я создал метод псевдокопания (см. Выше), который работает на #[]
вместо #dig