Skip to content

Commit

Permalink
Add support for multiple files in order to support overrides; Update
Browse files Browse the repository at this point in the history
for rspec2 change
  • Loading branch information
greghaygood committed Jul 16, 2011
1 parent 4519763 commit 6495fc8
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 14 deletions.
7 changes: 7 additions & 0 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ this file in a rails app is app/models/settings.rb

I felt adding a settings file in your app was more straightforward, less tricky, and more flexible.

If multiple files are passed on the source line, comma-separated, they will be loaded in order, with settings in later files overriding any existing keys. This allows you to, for instance, maintain a global settings file in source control, while allowing each developer to override individual settings as needed. Files that are specified but which do not exist will simply be ignored. Thus you can safely do the following without requiring the presence of application_local.yml:

class Settings < Settingslogic
source "#{Rails.root}/config/application.yml", "#{Rails.root}/config/application_local.yml"
namespace Rails.env
end

=== 2. Create your settings

Notice above we specified an absolute path to our settings file called "application.yml". This is just a typical YAML file.
Expand Down
42 changes: 30 additions & 12 deletions lib/settingslogic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ def get(key)
curs
end

def source(value = nil)
if value.nil?
@source
def source(*value)
#puts "source! #{value}"
if value.nil? or value == []
@sources
else
@source = value
@sources= value
end
end

Expand Down Expand Up @@ -94,24 +95,41 @@ 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)
#puts "new! #{hash_or_file}"
case hash_or_file
def initialize(hash_or_file_or_array = self.class.source, section = nil)
#puts "new! #{hash_or_file_or_array.inspect} (section: #{section})"
case hash_or_file_or_array
when nil
raise Errno::ENOENT, "No file specified as Settingslogic source"
when Hash
self.replace hash_or_file
else
hash = YAML.load(ERB.new(File.read(hash_or_file)).result).to_hash
if self.class.namespace
hash = hash[self.class.namespace] or raise MissingSetting, "Missing setting '#{self.class.namespace}' in #{hash_or_file}"
self.replace hash_or_file_or_array
when Array
hash = {}
hash_or_file_or_array.each do |filename|
#puts "loading from #{filename}"
hash.merge!(load_into_hash(filename))
end
self.replace hash
else
hash = load_into_hash(hash_or_file_or_array)
self.replace hash
end
@section = section || self.class.source # so end of error says "in application.yml"
if @section.is_a?(Array)
@section = @section.first # TODO: is there a better way to preserve which file was used?
end
create_accessors!
end

def load_into_hash(file)
return {} unless FileTest.exist?(file)
#puts "loading into hash from #{file} (namespace: #{self.class.namespace})"
hash = YAML.load(ERB.new(File.read(file)).result).to_hash
if self.class.namespace
hash = hash[self.class.namespace] or raise MissingSetting, "Missing setting '#{self.class.namespace}' in #{file}"
end
hash
end

# Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used.
# Otherwise, create_accessors! (called by new) will have created actual methods for each key.
def method_missing(name, *args, &block)
Expand Down
3 changes: 3 additions & 0 deletions spec/settings4.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Settings4 < Settingslogic
source "#{File.dirname(__FILE__)}/settings.yml", "#{File.dirname(__FILE__)}/settings_local.yml", "#{File.dirname(__FILE__)}/settings_local2.yml"
end
1 change: 1 addition & 0 deletions spec/settings_local.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
setting2: 10
4 changes: 4 additions & 0 deletions spec/settingslogic_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
Settings3.collides.does.should == 'not'
end

it "should override with local settings" do
Settings4.setting2.should == 10
end

it "should raise a helpful error message" do
e = nil
begin
Expand Down
5 changes: 3 additions & 2 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require 'spec'
require 'rspec'
require 'rubygems'
require 'ruby-debug' if RUBY_VERSION < '1.9' # ruby-debug does not work on 1.9.1 yet

Expand All @@ -8,11 +8,12 @@
require 'settings'
require 'settings2'
require 'settings3'
require 'settings4'

# Needed to test Settings3
Object.send :define_method, 'collides' do
'collision'
end

Spec::Runner.configure do |config|
RSpec.configure do |config|
end

0 comments on commit 6495fc8

Please sign in to comment.