Вот мое решение (оно похоже на proxygear, но оно не исправляет хеш-патч и работает правильно, когда вызывается без аргументов).Я думаю, что это лучше, чем два решения на основе инъекций, потому что они взорвутся, если вы попытаетесь получить доступ к путям этого DNE.
class TraversibleHash
attr_accessor :hash
def initialize(hash)
self.hash = hash
end
def access(*keys)
recursive_access keys, hash
end
private
def recursive_access(keys, hash)
return nil if keys.empty?
element = hash.fetch(keys.shift) { return nil }
return element if keys.empty?
return nil unless element.kind_of? Hash # <-- should maybe raise an error?
recursive_access keys, element
end
end
Вот набор тестов:
describe TraversibleHash do
let(:traversible) { TraversibleHash.new 'key1' => { 'sub1' => 1, 'sub2' => 2 }, 'key2' => 3, nil => 1 }
it 'returns nil when invoked without args' do
traversible.access.should be_nil
end
it 'returns nil when accessing nonexistent keys' do
traversible.access('key3').should be_nil
traversible.access('key2', 'key3').should be_nil
traversible.access('key1', 'sub3').should be_nil
traversible.access('key1', 'sub2', 'subsub1').should be_nil
traversible.access('abc', 'def', 'ghi').should be_nil
end
it 'finds toplevel keys' do
traversible.access('key2').should == 3
traversible.access('key1').should == {'sub1' => 1, 'sub2' => 2}
end
it 'traverses nested hashes to find nested keys' do
traversible.access('key1', 'sub1').should == 1
traversible.access('key1', 'sub2').should == 2
TraversibleHash.new(1=>{2=>{3=>4}}).access(1, 2, 3).should == 4
end
end