diff --git a/lib/config/sources/env_source.rb b/lib/config/sources/env_source.rb index df59e35e..fdc424a1 100644 --- a/lib/config/sources/env_source.rb +++ b/lib/config/sources/env_source.rb @@ -52,10 +52,28 @@ def load leaf[keys.last] = parse_values ? __value(value) : value end - hash + convert_hashes_to_arrays(hash) end private + def convert_hashes_to_arrays(hash) + hash.each_with_object({}) do |(key, value), new_hash| + if value.is_a?(Hash) + value = convert_hashes_to_arrays(value) + if consecutive_numeric_keys?(value.keys) + new_hash[key] = value.keys.sort_by(&:to_i).map { |k| value[k] } + else + new_hash[key] = value + end + else + new_hash[key] = value + end + end + end + + def consecutive_numeric_keys?(keys) + keys.map(&:to_i).sort == (0...keys.size).to_a && keys.all? { |k| k == k.to_i.to_s } + end # Try to convert string to a correct type def __value(v) diff --git a/spec/sources/env_source_spec.rb b/spec/sources/env_source_spec.rb index ad86f9a7..53df7e85 100644 --- a/spec/sources/env_source_spec.rb +++ b/spec/sources/env_source_spec.rb @@ -43,6 +43,46 @@ module Config::Sources results = source.load expect(results['action_mailer']['enabled']).to eq('true') end + + describe 'arrays' do + let(:source) do + Config.env_converter = nil + EnvSource.new({ + 'Settings.SomeConfig.0.0' => 'value1', + 'Settings.SomeConfig.0.1' => 'value2', + 'Settings.SomeConfig.1.1' => 'value3', + 'Settings.SomeConfig.1.2' => 'value4', + 'Settings.MixedConfig.1.0' => 'value5', + 'Settings.MixedConfig.1.1' => 'value6', + 'Settings.MixedConfig.1.custom' => 'value7' + }) + end + + let(:results) { source.load } + + context 'when loading nested configurations' do + it 'converts numeric-keyed hashes to arrays' do + puts results.inspect + expect(results['SomeConfig']).to be_an Array + expect(results['SomeConfig'][0]).to be_an Array + expect(results['SomeConfig'][0][0]).to eq('value1') + expect(results['SomeConfig'][0][1]).to eq('value2') + end + + it 'retains hashes for non-sequential numeric keys' do + expect(results['SomeConfig'][1]).to be_a Hash + expect(results['SomeConfig'][1]['1']).to eq('value3') + expect(results['SomeConfig'][1]['2']).to eq('value4') + end + + it 'retains hashes for mixed types' do + expect(results['MixedConfig'][1]).to be_a Hash + expect(results['MixedConfig'][1]['0']).to eq('value5') + expect(results['MixedConfig'][1]['1']).to eq('value6') + expect(results['MixedConfig'][1]['custom']).to eq('value7') + end + end + end end context 'configuration overrides' do