Support symbol keys in ObjectTraverser (#2221)

As detected in #2036, it is not possible to extract values from
a YAML file if the key is a symbol. This change refactors ObjectTraverser
to support symbol keys before attempting to stringify them.

Signed-off-by: Adam Leff <adam@leff.co>
This commit is contained in:
Adam Leff 2017-10-06 13:24:31 -04:00 committed by Dominik Richter
parent 359fd48af0
commit 9d8c53cf31
4 changed files with 59 additions and 12 deletions

View file

@ -3,22 +3,47 @@
# author: Christoph Hartmann
module ObjectTraverser
def extract_value(keys, value)
key = keys.shift
return nil if key.nil? || value.nil?
return nil if value.nil?
if value.is_a?(Array)
value = if key.is_a?(Fixnum)
value[key]
elsif value.respond_to?(key.to_sym)
value.send(key.to_sym)
end
else
value = value[key.to_s].nil? ? nil : value[key.to_s]
end
key = keys.shift
return nil if key.nil?
# if the current value is not a Hash or Array, it is undefined
# behavior so value will be assigned nil by default.
value = if value.is_a?(Array)
extract_from_array(key, value)
elsif value.is_a?(Hash)
extract_from_hash(key, value)
end
# if there are no more keys, just return the value
return value if keys.first.nil?
# if there are more keys, extract more
extract_value(keys.clone, value)
end
private
# If the values to return from is an Array, allow returning by index.
# Otherwise, support methods on the Array itself.
def extract_from_array(key, value)
if key.is_a?(Fixnum)
value[key]
elsif value.respond_to?(key.to_sym)
value.send(key.to_sym)
end
end
# for Hashes, try to return the value by the key.
# We first try to find by the raw key before we stringify
# if the keys themselves are symbols, for example.
#
# This will return nil default if we can't find the key.
def extract_from_hash(key, value)
if value.key?(key)
value[key]
elsif value.key?(key.to_s)
value[key.to_s]
end
end
end

View file

@ -5,3 +5,6 @@ driver:
platforms:
- linux
- mac
:symbol_key: 123
:symbol_key_deep:
foo: bar

View file

@ -30,5 +30,13 @@ describe 'Inspec::Resources::YAML' do
it 'doesnt resolve symbol-notation names' do
_(resource.send(:'driver.customize.memory')).must_be_nil
end
it 'supports fetching by symbol keys' do
_(resource.send(:symbol_key)).must_equal 123
end
it 'support fetching by symbol keys in array syntax for rspec-its' do
_(resource.send(:[], :symbol_key_deep, 'foo')).must_equal 'bar'
end
end
end

View file

@ -25,7 +25,12 @@ describe ObjectTraverser do
123,
456,
{ 'array1hashkey1' => 1, 'array1hashkey2' => 2 },
]
],
:symbol_key_1 => 123,
:symbol_key_2 => {
:symbol_under_symbol => 456,
'string_under_symbol' => 789
}
}
end
@ -77,4 +82,10 @@ describe ObjectTraverser do
subject.extract_value(['array2', 'last', 'array1hashkey1'], sample_data).must_equal(1)
subject.extract_value(['array2', 'last', 'array1hashkey2'], sample_data).must_equal(2)
end
it 'supports returning values with symbol keys' do
subject.extract_value([:symbol_key_1], sample_data).must_equal(123)
subject.extract_value([:symbol_key_2, :symbol_under_symbol], sample_data).must_equal(456)
subject.extract_value([:symbol_key_2, 'string_under_symbol'], sample_data).must_equal(789)
end
end