From 7709cefb31b621270b5829926909549d7fe9a3fd Mon Sep 17 00:00:00 2001 From: dominh <> Date: Fri, 8 Mar 2024 19:27:37 +0000 Subject: [PATCH 1/3] Allow arrays to be passed through env variables --- lib/config/sources/env_source.rb | 20 +++++++++++++++- spec/sources/env_source_spec.rb | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) 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 From b21d8c913655ecaae0ef5b9245f98113a57c1f88 Mon Sep 17 00:00:00 2001 From: Dominik Mlynek Date: Sat, 23 Mar 2024 21:03:57 +0000 Subject: [PATCH 2/3] Fix "Config::Sources::EnvSource configuration options default configuration arrays when loading nested configurations retains hashes for mixed types" spec --- spec/sources/env_source_spec.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/sources/env_source_spec.rb b/spec/sources/env_source_spec.rb index 53df7e85..356ea821 100644 --- a/spec/sources/env_source_spec.rb +++ b/spec/sources/env_source_spec.rb @@ -62,7 +62,6 @@ module Config::Sources 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') @@ -76,10 +75,10 @@ module Config::Sources 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') + 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 From 070b279a7d672fb624104d906b3ee5d5b2e760a9 Mon Sep 17 00:00:00 2001 From: Dominik Mlynek Date: Sat, 23 Mar 2024 22:09:07 +0000 Subject: [PATCH 3/3] add `Config.env_parse_arrays` --- lib/config.rb | 1 + lib/config/sources/env_source.rb | 7 +++++-- spec/config_env_spec.rb | 31 +++++++++++++++++++++++++++++++ spec/sources/env_source_spec.rb | 4 ++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lib/config.rb b/lib/config.rb index 0efde070..953e9c67 100644 --- a/lib/config.rb +++ b/lib/config.rb @@ -18,6 +18,7 @@ module Config env_separator: '.', env_converter: :downcase, env_parse_values: true, + env_parse_arrays: false, fail_on_missing: false, file_name: 'settings', dir_name: 'settings', diff --git a/lib/config/sources/env_source.rb b/lib/config/sources/env_source.rb index fdc424a1..ea527db4 100644 --- a/lib/config/sources/env_source.rb +++ b/lib/config/sources/env_source.rb @@ -6,17 +6,20 @@ class EnvSource attr_reader :separator attr_reader :converter attr_reader :parse_values + attr_reader :parse_arrays def initialize(env, prefix: Config.env_prefix || Config.const_name, separator: Config.env_separator, converter: Config.env_converter, - parse_values: Config.env_parse_values) + parse_values: Config.env_parse_values, + parse_arrays: Config.env_parse_arrays) @env = env @prefix = prefix.to_s.split(separator) @separator = separator @converter = converter @parse_values = parse_values + @parse_arrays = parse_arrays end def load @@ -52,7 +55,7 @@ def load leaf[keys.last] = parse_values ? __value(value) : value end - convert_hashes_to_arrays(hash) + parse_arrays ? convert_hashes_to_arrays(hash) : hash end private diff --git a/spec/config_env_spec.rb b/spec/config_env_spec.rb index 65e7da8b..a5eee612 100644 --- a/spec/config_env_spec.rb +++ b/spec/config_env_spec.rb @@ -22,6 +22,7 @@ Config.env_separator = '.' Config.env_converter = :downcase Config.env_parse_values = true + Config.env_parse_arrays = true end it 'should add new setting from ENV variable' do @@ -96,6 +97,36 @@ end end + context 'and parsing ENV variables arrays' do + context 'is enabled' do + before :each do + Config.env_parse_arrays = true + end + + it 'should recognize ENV variables with subsequent numeric suffixes starting from 0 as array' do + ENV['Settings.SomeConfig.0'] = 'first' + ENV['Settings.SomeConfig.1'] = 'second' + + expect(config.someconfig).to eq(['first', 'second']) + end + end + + context 'is disabled' do + before :each do + Config.env_parse_arrays = false + end + + it 'should not recognize ENV variables with subsequent numeric suffixes starting from 0 as array' do + ENV['Settings.SomeConfig.0'] = 'first' + ENV['Settings.SomeConfig.1'] = 'second' + + expect(config.someconfig).to be_a Config::Options + expect(config.someconfig['0']).to eq('first') + expect(config.someconfig['1']).to eq('second') + end + end + end + context 'and custom ENV variables prefix is defined' do before :each do Config.env_prefix = 'MyConfig' diff --git a/spec/sources/env_source_spec.rb b/spec/sources/env_source_spec.rb index 356ea821..08511a30 100644 --- a/spec/sources/env_source_spec.rb +++ b/spec/sources/env_source_spec.rb @@ -45,6 +45,10 @@ module Config::Sources end describe 'arrays' do + before(:each) do + Config.env_parse_arrays = true + end + let(:source) do Config.env_converter = nil EnvSource.new({