Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Adds an environment_vars_fallback to the Settingslogic class #63

Open
wants to merge 2 commits into from

2 participants

@leonelgalan

I wrote this to play nicer with Heroku or Travis-ci, where it's easier to set environment variables.

If set to true, non existing settings attempt to retrieve value from
environment variables. For example:

class Settings < Settingslogic
   source "#{File.dirname(__FILE__)}/settings.yml"
   suppress_errors true
   environment_vars_fallback true
 end

ENV['SETTINGS_NON_EXISTENT_KEY']='foo'
Settings.non_existent_key.should == 'foo'
leonelgalan added some commits
@leonelgalan leonelgalan Stores an array of @sections instead of a single string in @section
Before `Setting.a.b.c` had `@section == "'b' section in 'a' section in
'[PATH]/settings.yml'"`, now it has `@sections == ['b', 'a',
'Settting']`. The purpose of this commit, is to have the section's
"stack" available and not just a string.

The only use of `@section` was to show a meaningful MissingSetting
message, this is not change in this commit and the message is so
similar, all tests are passing.
14c313d
@leonelgalan leonelgalan Adds an environment_vars_fallback to the Settingslogic class
If set to true, non existing settings attempt to retrieve value from
environment variables. For example:

`Settings.non_existent_key == 'foo' ` if
`ENV['SETTINGS_NON_EXISTENT_KEY']='foo'` and Settings has
`environment_vars_fallback true`
ff2741b
@m5rk

@leonelgalan You may be interested in chamber, which supports overriding from the environment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 11, 2013
  1. @leonelgalan

    Stores an array of @sections instead of a single string in @section

    leonelgalan authored
    Before `Setting.a.b.c` had `@section == "'b' section in 'a' section in
    '[PATH]/settings.yml'"`, now it has `@sections == ['b', 'a',
    'Settting']`. The purpose of this commit, is to have the section's
    "stack" available and not just a string.
    
    The only use of `@section` was to show a meaningful MissingSetting
    message, this is not change in this commit and the message is so
    similar, all tests are passing.
  2. @leonelgalan

    Adds an environment_vars_fallback to the Settingslogic class

    leonelgalan authored
    If set to true, non existing settings attempt to retrieve value from
    environment variables. For example:
    
    `Settings.non_existent_key == 'foo' ` if
    `ENV['SETTINGS_NON_EXISTENT_KEY']='foo'` and Settings has
    `environment_vars_fallback true`
This page is out of date. Refresh to see the latest.
View
33 lib/settingslogic.rb
@@ -33,6 +33,10 @@ def suppress_errors(value = nil)
@suppress_errors ||= value
end
+ def environment_vars_fallback(value = nil)
+ @environment_vars_fallback ||= value
+ end
+
def [](key)
instance.fetch(key.to_s, nil)
end
@@ -91,7 +95,7 @@ def create_accessor_for(key)
# Basically if you pass a symbol it will look for that file in the configs directory of your rails app,
# if you are using this in rails. If you pass a string it should be an absolute path to your settings file.
# Then you can pass a hash, and it just allows you to access the hash via methods.
- def initialize(hash_or_file = self.class.source, section = nil)
+ def initialize(hash_or_file = self.class.source, key = nil, section = nil)
#puts "new! #{hash_or_file}"
case hash_or_file
when nil
@@ -102,11 +106,12 @@ def initialize(hash_or_file = self.class.source, section = nil)
file_contents = open(hash_or_file).read
hash = file_contents.empty? ? {} : YAML.load(ERB.new(file_contents).result).to_hash
if self.class.namespace
- hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}")
+ hash = hash[self.class.namespace] or return missing_key(self.class.namespace)
end
self.replace hash
end
- @section = section || self.class.source # so end of error says "in application.yml"
+ section = section + [key] unless section.nil? && key.nil?
+ @sections = section || [self.class.to_s] # so end of error says "in application.yml"
create_accessors!
end
@@ -114,10 +119,10 @@ def initialize(hash_or_file = self.class.source, section = nil)
# Otherwise, create_accessors! (called by new) will have created actual methods for each key.
def method_missing(name, *args, &block)
key = name.to_s
- return missing_key("Missing setting '#{key}' in #{@section}") unless has_key? key
+ return missing_key(key) unless has_key? key
value = fetch(key)
create_accessor_for(key)
- value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value
+ value.is_a?(Hash) ? self.class.new(value, key, @sections) : value
end
def [](key)
@@ -126,7 +131,7 @@ def [](key)
def []=(key,val)
# Setting[:key][:key2] = 'value' for dynamic settings
- val = self.class.new(val, @section) if val.is_a? Hash
+ val = self.class.new(val, key, @sections) if val.is_a? Hash
store(key.to_s, val)
create_accessor_for(key, val)
end
@@ -155,10 +160,10 @@ def create_accessor_for(key, val=nil)
self.class.class_eval <<-EndEval
def #{key}
return @#{key} if @#{key}
- return missing_key("Missing setting '#{key}' in #{@section}") unless has_key? '#{key}'
+ return missing_key(key) unless has_key? '#{key}'
value = fetch('#{key}')
@#{key} = if value.is_a?(Hash)
- self.class.new(value, "'#{key}' section in #{@section}")
+ self.class.new(value, '#{key}', @sections)
elsif value.is_a?(Array) && value.all?{|v| v.is_a? Hash}
value.map{|v| self.class.new(v)}
else
@@ -182,10 +187,16 @@ def symbolize_keys
end
end
-
- def missing_key(msg)
+
+ def environment_var_for(key)
+ (@sections + [key]).join('_').upcase
+ end
+
+ def missing_key(key)
+ return ENV[environment_var_for(key)] if self.class.environment_vars_fallback && ENV[environment_var_for(key)]
+
return nil if self.class.suppress_errors
- raise MissingSetting, msg
+ raise MissingSetting, "Missing setting '#{key}' #{@sections.reverse.map{|section| "in '#{section}' section"}.join(' ')}"
end
end
View
5 spec/settings5.rb
@@ -0,0 +1,5 @@
+class Settings5 < Settingslogic
+ source "#{File.dirname(__FILE__)}/settings.yml"
+ suppress_errors true
+ environment_vars_fallback true
+end
View
6 spec/settingslogic_spec.rb
@@ -115,6 +115,12 @@ class NoSource < Settingslogic; end
Settings4.non_existent_key.should be_nil
end
+ it "should allow environment variables fallback" do
+ Settings5.non_existent_key.should be_nil
+ ENV['SETTINGS5_NON_EXISTENT_KEY']='foo'
+ Settings5.non_existent_key.should == 'foo'
+ end
+
# This one edge case currently does not pass, because it requires very
# esoteric code in order to make it pass. It was judged not worth fixing,
# as it introduces significant complexity for minor gain.
View
1  spec/spec_helper.rb
@@ -6,6 +6,7 @@
require 'settings2'
require 'settings3'
require 'settings4'
+require 'settings5'
require 'settings_empty'
# Needed to test Settings3
Something went wrong with that request. Please try again.