Load current environment settings regardless of support for other environments in settings file.

This commit is contained in:
Jon Hope 2017-01-28 02:50:54 +00:00 committed by John Hope
parent 5074c1e342
commit dac516088e
No known key found for this signature in database
GPG Key ID: 838CEBF96D036230
3 changed files with 66 additions and 30 deletions

View File

@ -8,7 +8,7 @@ module Sinatra
# #
# <tt>Sinatra::ConfigFile</tt> is an extension that allows you to load the # <tt>Sinatra::ConfigFile</tt> is an extension that allows you to load the
# application's configuration from YAML files. It automatically detects if # application's configuration from YAML files. It automatically detects if
# the files contains specific environment settings and it will use the # the files contain specific environment settings and it will use those
# corresponding to the current one. # corresponding to the current one.
# #
# You can access those options through +settings+ within the application. If # You can access those options through +settings+ within the application. If
@ -94,18 +94,11 @@ module Sinatra
# In either case, <tt>settings.foo</tt> will return the environment name, and # In either case, <tt>settings.foo</tt> will return the environment name, and
# <tt>settings.bar</tt> will return <tt>"bar"</tt>. # <tt>settings.bar</tt> will return <tt>"bar"</tt>.
# #
# Be aware that if you have a different environment, besides development, # If you wish to provide defaults that may be shared among all the
# test and production, you will also need to adjust the +environments+ # environments, this can be done by using a YAML alias, and then overwriting
# setting, otherwise the settings will not load. For instance, when # values in environments where appropriate:
# you also have a staging environment:
# #
# set :environments, %w{development test production staging} # default: &common_settings
#
# If you wish to provide defaults that may be shared among all the environments,
# this can be done by using one of the existing environments as the default using
# the YAML alias, and then overwriting values in the other environments:
#
# development: &common_settings
# foo: 'foo' # foo: 'foo'
# bar: 'bar' # bar: 'bar'
# #
@ -131,11 +124,9 @@ module Sinatra
raise UnsupportedConfigType unless ['.yml', '.erb'].include?(File.extname(file)) raise UnsupportedConfigType unless ['.yml', '.erb'].include?(File.extname(file))
logger.info "loading config file '#{file}'" if logging? && respond_to?(:logger) logger.info "loading config file '#{file}'" if logging? && respond_to?(:logger)
document = ERB.new(IO.read(file)).result document = ERB.new(IO.read(file)).result
yaml = config_for_env(YAML.load(document)) || {} yaml = YAML.load(document)
yaml.each_pair do |key, value| config = config_for_env(yaml)
for_env = config_for_env(value) config.each_pair { |key, value| set(key, value) }
set key, for_env unless value and for_env.nil? and respond_to? key
end
end end
end end
end end
@ -149,23 +140,32 @@ module Sinatra
private private
# Given a +hash+ with some application configuration it returns the # Given a +hash+ containing application configuration it returns
# settings applicable to the current environment. Note that this can only # settings applicable to the current environment. Note: It gives
# be done when all the keys of +hash+ are environment names included in the # precedence to environment settings defined at the root-level.
# +environments+ setting (which is an Array of Strings). Also, the
# returned config is a indifferently accessible Hash, which means that you
# can get its values using Strings or Symbols as keys.
def config_for_env(hash) def config_for_env(hash)
if hash.respond_to?(:keys) && hash.keys.all? { |k| environments.include?(k.to_s) } return from_environment_key(hash) if environment_keys?(hash)
hash = hash[environment.to_s] || hash[environment.to_sym]
end
if hash.respond_to?(:to_hash) hash.each_with_object(IndifferentHash[]) do |(k, v), acc|
IndifferentHash[hash.to_hash] if environment_keys?(v)
else acc.merge!(k => v[environment.to_s]) if v.key?(environment.to_s)
hash else
acc.merge!(k => v)
end
end end
end end
# Given a +hash+ returns the settings corresponding to the current
# environment.
def from_environment_key(hash)
hash[environment.to_s] || hash[environment.to_sym] || {}
end
# Returns true if supplied with a hash that has any recognized
# +environments+ in its root keys.
def environment_keys?(hash)
hash.is_a?(Hash) && hash.any? { |k, _| environments.include?(k.to_s) }
end
end end
register ConfigFile register ConfigFile

View File

@ -0,0 +1,16 @@
---
default: &default
foo: default
bar: baz
development:
<<: *default
foo: development
production:
<<: *default
foo: production
test:
<<: *default
foo: test

View File

@ -73,4 +73,24 @@ describe Sinatra::ConfigFile do
config_file 'key_value_override.yml' config_file 'key_value_override.yml'
expect(settings.foo).to eq('foo') expect(settings.foo).to eq('foo')
end end
context 'when file contains superfluous environments' do
before { config_file 'with_env_defaults.yml' }
it 'loads settings for the current environment anyway' do
expect { settings.foo }.not_to raise_error
end
end
context 'when file contains defaults' do
before { config_file 'with_env_defaults.yml' }
it 'uses the overridden value' do
expect(settings.foo).to eq('test')
end
it 'uses the default value' do
expect(settings.bar).to eq('baz')
end
end
end end