spec/lib/conker_spec.rb in conker-0.11.0 vs spec/lib/conker_spec.rb in conker-0.12.0

- old
+ new

@@ -1,235 +1,321 @@ +require 'active_support/core_ext/hash/indifferent_access' + require 'conker' describe Conker do before :each do - @env_vars = ENV.keys @constants = Kernel.constants end after :each do - # N.B. this doesn't catch if we *changed* any env vars (rather than adding - # new ones). - (ENV.keys - @env_vars).each {|k| ENV.delete k } - # Same caveat doesn't apply here, because Ruby will whinge if we redefine a - # constant. + # Don't need to worry about changing (rather than adding) constants, + # because Ruby will whinge if we do that. (Kernel.constants - @constants).each do |k| Kernel.send :remove_const, k end end - describe 'basic usage' do - def setup!(env = :development) - Conker.module_eval do - setup_config! env, - A_SECRET: api_credential(development: nil), - PORT: required_in_production(type: :integer, default: 42) + describe 'reading config from a hash' do + describe 'basic usage' do + def setup!(env = :development, config = {}) + Conker.module_eval do + setup_config! env, config.with_indifferent_access, + A_SECRET: api_credential(development: nil), + PORT: required_in_production(type: :integer, default: 42) + end end - end - it 'exposes declared variables as top-level constants' do - setup! - ::A_SECRET.should be_nil - ::PORT.should == 42 - end + it 'exposes declared variables as top-level constants' do + setup! + ::A_SECRET.should be_nil + ::PORT.should == 42 + end - it 'does not turn random environment variables into constants' do - ENV['PATH'].should_not be_empty - setup! - expect { ::PATH }.to raise_error(NameError, /PATH/) - end + it 'lets values in the hash override defaults' do + setup! :development, PORT: 3000 + ::PORT.should == 3000 + end - it 'lets environment variables override environmental defaults' do - ENV['A_SECRET'] = 'beefbeefbeefbeef' - setup! - ::A_SECRET.should == 'beef' * 4 - end + it 'ignores environment variables' do + ENV['A_SECRET'] = 'beefbeefbeefbeef' + begin setup! ensure ENV.delete('A_SECRET') end + ::A_SECRET.should be_nil + end - it 'throws useful errors if required variables are missing' do - ENV['A_SECRET'].should be_nil - ENV['PORT'] = '42' - expect { setup! :production }.to raise_error(/A_SECRET/) + it 'does not turn random environment variables into constants' do + ENV['PATH'].should_not be_empty + setup! + expect { ::PATH }.to raise_error(NameError, /PATH/) + end + + it 'throws useful errors if required variables are missing' do + expect { setup! :production, PORT: 42 }.to raise_error(/A_SECRET/) + end end - end - describe 'required variables' do - def setup! - env = @env # capture it for block scope - Conker.module_eval do - setup_config! env, - APPNAME: optional(default: 'conker'), - PORT: required_in_production(type: :integer, default: 3000) + describe 'required variables' do + def setup!(config = {}) + env = @env # capture it for block scope + Conker.module_eval do + setup_config! env, config.with_indifferent_access, + APPNAME: optional(default: 'conker'), + PORT: required_in_production(type: :integer, default: 3000) + end end - end - describe 'in development' do - before { @env = :development } + describe 'in development' do + before { @env = :development } - it 'allows optional variables to be missing' do - ENV['APPNAME'].should be_nil - ENV['PORT'] = '80' - expect { setup! }.not_to raise_error + it 'allows optional variables to be missing' do + expect { setup! PORT: 80 }.not_to raise_error + end + + it 'allows required_in_production variables to be missing' do + expect { setup! APPNAME: 'widget' }.not_to raise_error + end end - it 'allows required_in_production variables to be missing' do - ENV['APPNAME'] = 'widget' - ENV['PORT'].should be_nil - expect { setup! }.not_to raise_error + describe 'in production' do + before { @env = :production } + + it 'allows optional variables to be missing' do + expect { setup! PORT: 80 }.not_to raise_error + end + + it 'throws a useful error if required_in_production variables are missing' do + expect { setup! APPNAME: 'widget' }.to raise_error(/PORT/) + end end end - describe 'in production' do - before { @env = :production } - it 'allows optional variables to be missing' do - ENV['APPNAME'].should be_nil - ENV['PORT'] = '80' - expect { setup! }.not_to raise_error + describe 'defaults' do + def setup!(env = :development, config = {}) + Conker.module_eval do + setup_config! env, config.with_indifferent_access, + NUM_THREADS: optional(type: :integer, test: 1, default: 2) + end end - it 'throws a useful error if required_in_production variables are missing' do - ENV['APPNAME'] = 'widget' - ENV['PORT'].should be_nil - expect { setup! }.to raise_error(/PORT/) + it 'uses the specified value if one is given' do + setup! :development, NUM_THREADS: 4 + NUM_THREADS.should == 4 end - end - end + it 'uses the default value if none is specified' do + setup! :development + NUM_THREADS.should == 2 + end - describe 'defaults' do - def setup!(env = :development) - Conker.module_eval do - setup_config! env, NUM_THREADS: optional(type: :integer, test: 1, default: 2) + it 'allows overriding defaults for specific environments' do + setup! :test + NUM_THREADS.should == 1 end end - it 'uses the specified value if one is given' do - ENV['NUM_THREADS'] = '4' - setup! - NUM_THREADS.should == 4 - end - it 'uses the default value if none is specified' do - ENV['NUM_THREADS'].should be_nil - setup! - NUM_THREADS.should == 2 - end + describe 'typed variables' do + describe 'boolean' do + def setup_sprocket_enabled!(value_string) + Conker.module_eval do + setup_config! :development, {'SPROCKET_ENABLED' => value_string}, + SPROCKET_ENABLED: optional(type: :boolean, default: false) + end + end - it 'allows overriding defaults for specific environments' do - ENV['NUM_THREADS'].should be_nil - setup! :test - NUM_THREADS.should == 1 - end - end + it 'parses "true"' do + setup_sprocket_enabled! 'true' + SPROCKET_ENABLED.should be_true + end + it 'parses "false"' do + setup_sprocket_enabled! 'false' + SPROCKET_ENABLED.should be_false + end - describe 'typed variables' do - describe 'boolean' do - def setup_sprocket_enabled!(value_string) - ENV['SPROCKET_ENABLED'] = value_string - Conker.module_eval do - setup_config! :development, :SPROCKET_ENABLED => optional(type: :boolean, default: false) + it 'accepts "1" as true' do + setup_sprocket_enabled! '1' + SPROCKET_ENABLED.should be_true end - end - it 'parses "true"' do - setup_sprocket_enabled! 'true' - SPROCKET_ENABLED.should be_true + it 'accepts "0" as false' do + setup_sprocket_enabled! '0' + SPROCKET_ENABLED.should be_false + end end - it 'parses "false"' do - setup_sprocket_enabled! 'false' - SPROCKET_ENABLED.should be_false - end + describe 'integer' do + def setup_num_threads!(value_string) + Conker.module_eval do + setup_config! :development, {'NUM_THREADS' => value_string}, + NUM_THREADS: optional(type: :integer, default: 2) + end + end - it 'accepts "1" as true' do - setup_sprocket_enabled! '1' - SPROCKET_ENABLED.should be_true + it 'parses "42"' do + setup_num_threads! '42' + NUM_THREADS.should == 42 + end + + it 'throws an error if the value is not an integer' do + expect { setup_num_threads! 'one hundred' }.to raise_error(/one hundred/) + end end - it 'accepts "0" as false' do - setup_sprocket_enabled! '0' - SPROCKET_ENABLED.should be_false + describe 'float' do + def setup_log_probability!(value_string) + Conker.module_eval do + setup_config! :development, {'LOG_PROBABILITY' => value_string}, + LOG_PROBABILITY: optional(type: :float, default: 1.0) + end + end + + it 'parses "0.5"' do + setup_log_probability! '0.5' + LOG_PROBABILITY.should == 0.5 + end + + it 'throws an error if the value is not a float' do + expect { setup_log_probability! 'zero' }.to raise_error(/zero/) + end end - end - describe 'integer' do - def setup_num_threads!(value_string) - ENV['NUM_THREADS'] = value_string - Conker.module_eval do - setup_config! :development, :NUM_THREADS => optional(type: :integer, default: 2) + describe 'url' do + def setup_api_url!(value_string) + Conker.module_eval do + setup_config! :development, {'API_URL' => value_string}, + API_URL: optional(type: :url, default: 'http://example.com/foo') + end end + + it 'exposes a URI object, not a string' do + setup_api_url! 'http://localhost:4321/' + API_URL.host.should == 'localhost' + end + + it 'parses the default value too' do + setup_api_url! nil + API_URL.host.should == 'example.com' + end end - it 'parses "42"' do - setup_num_threads! '42' - NUM_THREADS.should == 42 + describe 'addressable' do + def setup_api_url!(value_string) + Conker.module_eval do + setup_config! :development, {'API_URL' => value_string}, + API_URL: optional(type: :addressable, default: 'http://example.com/foo') + end + end + + it 'exposes an Addressable::URI object, not a string' do + setup_api_url! 'http://localhost:4321/' + API_URL.host.should == 'localhost' + end + + it 'parses the default value too' do + setup_api_url! nil + API_URL.host.should == 'example.com' + end end - it 'throws an error if the value is not an integer' do - expect { setup_num_threads! 'one hundred' }.to raise_error(/one hundred/) + describe 'timestamp' do + xit 'seems to have bit rotted' end end + end - describe 'float' do - def setup_log_probability!(value_string) - ENV['LOG_PROBABILITY'] = value_string + + describe 'reading config from environment variables' do + before :each do + @env_vars = ENV.keys + end + + after :each do + # N.B. this doesn't catch if we *changed* any env vars (rather than adding + # new ones). + (ENV.keys - @env_vars).each {|k| ENV.delete k } + end + + + describe 'basic usage' do + def setup!(env = :development) Conker.module_eval do - setup_config! :development, :LOG_PROBABILITY => optional(type: :float, default: 1.0) + setup_config! env, + A_SECRET: api_credential(development: nil), + PORT: required_in_production(type: :integer, default: 42) end end - it 'parses "0.5"' do - setup_log_probability! '0.5' - LOG_PROBABILITY.should == 0.5 + it 'exposes declared variables as top-level constants' do + setup! + ::A_SECRET.should be_nil + ::PORT.should == 42 end - it 'throws an error if the value is not a float' do - expect { setup_log_probability! 'zero' }.to raise_error(/zero/) + it 'does not turn random environment variables into constants' do + ENV['PATH'].should_not be_empty + setup! + expect { ::PATH }.to raise_error(NameError, /PATH/) end - end - describe 'url' do - def setup_api_url!(value_string) - ENV['API_URL'] = value_string - Conker.module_eval do - setup_config! :development, :API_URL => optional(type: :url, default: 'http://example.com/foo') - end + it 'lets environment variables override environmental defaults' do + ENV['A_SECRET'] = 'beefbeefbeefbeef' + setup! + ::A_SECRET.should == 'beef' * 4 end - it 'exposes a URI object, not a string' do - setup_api_url! 'http://localhost:4321/' - API_URL.host.should == 'localhost' + it 'throws useful errors if required variables are missing' do + ENV['A_SECRET'].should be_nil + ENV['PORT'] = '42' + expect { setup! :production }.to raise_error(/A_SECRET/) end + end + end - it 'parses the default value too' do - setup_api_url! nil - API_URL.host.should == 'example.com' - end + + describe 'reading config from a YAML file' do + def fixture(filename) + File.join(File.dirname(__FILE__), '..', 'fixtures', filename) end - describe 'addressable' do - def setup_api_url!(value_string) - ENV['API_URL'] = value_string + describe 'basic usage' do + def setup!(env = :development, filename = 'empty.yml') + fixture_path = fixture(filename) Conker.module_eval do - setup_config! :development, :API_URL => optional(type: :addressable, default: 'http://example.com/foo') + setup_config! env, fixture_path, + A_SECRET: api_credential(development: nil), + PORT: required_in_production(type: :integer, default: 42) end end - it 'exposes an Addressable::URI object, not a string' do - setup_api_url! 'http://localhost:4321/' - API_URL.host.should == 'localhost' + it 'exposes declared variables as top-level constants' do + setup! + ::A_SECRET.should be_nil + ::PORT.should == 42 end - it 'parses the default value too' do - setup_api_url! nil - API_URL.host.should == 'example.com' + it 'lets values in the file override defaults' do + setup! :development, 'port_3000.yml' + ::PORT.should == 3000 end - end - describe 'timestamp' do - xit 'seems to have bit rotted' + it 'ignores environment variables' do + ENV['A_SECRET'] = 'beefbeefbeefbeef' + begin setup! ensure ENV.delete('A_SECRET') end + ::A_SECRET.should be_nil + end + + it 'does not turn random environment variables into constants' do + ENV['PATH'].should_not be_empty + setup! + expect { ::PATH }.to raise_error(NameError, /PATH/) + end + + it 'throws useful errors if required variables are missing' do + expect { setup! :production, 'port_3000.yml' }.to raise_error(/A_SECRET/) + end end end end