forked from rubyconfig/config
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor environment variable handling into new Sources::EnvSource (r…
…ubyconfig#299) * Extract env var handling to new EnvSource class * Allow overriding settings for parsing env sources By default, EnvSource will use "global" settings specified like `Config.env_prefix`, `Config.env_separator`, `Config.env_separator`, and `Config.env_parse_values`. Those configurations will be used when parsing the ENV hash. But when using EnvSource to load settings from some unrelated flat string-keyed Hash source, we want to allow folks to override the settings. * Update CHANGELOG * Add AWS Secrets Manager usage to README
- Loading branch information
Showing
6 changed files
with
204 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
module Config | ||
module Sources | ||
# Allows settings to be loaded from a "flat" hash with string keys, like ENV. | ||
class EnvSource | ||
attr_reader :prefix | ||
attr_reader :separator | ||
attr_reader :converter | ||
attr_reader :parse_values | ||
|
||
def initialize(env, | ||
prefix: Config.env_prefix || Config.const_name, | ||
separator: Config.env_separator, | ||
converter: Config.env_converter, | ||
parse_values: Config.env_parse_values) | ||
@env = env | ||
@prefix = prefix.to_s.split(separator) | ||
@separator = separator | ||
@converter = converter | ||
@parse_values = parse_values | ||
end | ||
|
||
def load | ||
return {} if @env.nil? || @env.empty? | ||
|
||
hash = Hash.new | ||
|
||
@env.each do |variable, value| | ||
keys = variable.to_s.split(separator) | ||
|
||
next if keys.shift(prefix.size) != prefix | ||
|
||
keys.map! { |key| | ||
case converter | ||
when :downcase then | ||
key.downcase | ||
when nil then | ||
key | ||
else | ||
raise "Invalid ENV variables name converter: #{converter}" | ||
end | ||
} | ||
|
||
leaf = keys[0...-1].inject(hash) { |h, key| | ||
h[key] ||= {} | ||
} | ||
|
||
unless leaf.is_a?(Hash) | ||
conflicting_key = (prefix + keys[0...-1]).join(separator) | ||
raise "Environment variable #{variable} conflicts with variable #{conflicting_key}" | ||
end | ||
|
||
leaf[keys.last] = parse_values ? __value(value) : value | ||
end | ||
|
||
hash | ||
end | ||
|
||
private | ||
|
||
# Try to convert string to a correct type | ||
def __value(v) | ||
case v | ||
when 'false' | ||
false | ||
when 'true' | ||
true | ||
else | ||
Integer(v) rescue Float(v) rescue v | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
require 'spec_helper' | ||
|
||
module Config::Sources | ||
describe EnvSource do | ||
context 'configuration options' do | ||
before :each do | ||
Config.reset | ||
Config.env_prefix = nil | ||
Config.env_separator = '.' | ||
Config.env_converter = :downcase | ||
Config.env_parse_values = true | ||
end | ||
|
||
context 'default configuration' do | ||
it 'should use global prefix configuration by default' do | ||
Config.env_prefix = 'MY_CONFIG' | ||
|
||
source = EnvSource.new({ 'MY_CONFIG.ACTION_MAILER' => 'enabled' }) | ||
results = source.load | ||
expect(results['action_mailer']).to eq('enabled') | ||
end | ||
|
||
it 'should use global separator configuration by default' do | ||
Config.env_separator = '__' | ||
|
||
source = EnvSource.new({ 'Settings__ACTION_MAILER__ENABLED' => 'yes' }) | ||
results = source.load | ||
expect(results['action_mailer']['enabled']).to eq('yes') | ||
end | ||
|
||
it 'should use global converter configuration by default' do | ||
Config.env_converter = nil | ||
|
||
source = EnvSource.new({ 'Settings.ActionMailer.Enabled' => 'yes' }) | ||
results = source.load | ||
expect(results['ActionMailer']['Enabled']).to eq('yes') | ||
end | ||
|
||
it 'should use global parse_values configuration by default' do | ||
Config.env_parse_values = false | ||
|
||
source = EnvSource.new({ 'Settings.ACTION_MAILER.ENABLED' => 'true' }) | ||
results = source.load | ||
expect(results['action_mailer']['enabled']).to eq('true') | ||
end | ||
end | ||
|
||
context 'configuration overrides' do | ||
it 'should allow overriding prefix configuration' do | ||
source = EnvSource.new({ 'MY_CONFIG.ACTION_MAILER' => 'enabled' }, | ||
prefix: 'MY_CONFIG') | ||
results = source.load | ||
expect(results['action_mailer']).to eq('enabled') | ||
end | ||
|
||
it 'should allow overriding separator configuration' do | ||
source = EnvSource.new({ 'Settings__ACTION_MAILER__ENABLED' => 'yes' }, | ||
separator: '__') | ||
results = source.load | ||
expect(results['action_mailer']['enabled']).to eq('yes') | ||
end | ||
|
||
it 'should allow overriding converter configuration' do | ||
source = EnvSource.new({ 'Settings.ActionMailer.Enabled' => 'yes' }, | ||
converter: nil) | ||
results = source.load | ||
expect(results['ActionMailer']['Enabled']).to eq('yes') | ||
end | ||
|
||
it 'should allow overriding parse_values configuration' do | ||
source = EnvSource.new({ 'Settings.ACTION_MAILER.ENABLED' => 'true' }, | ||
parse_values: false) | ||
results = source.load | ||
expect(results['action_mailer']['enabled']).to eq('true') | ||
end | ||
end | ||
end | ||
end | ||
end |