├── spec
├── settings_empty.yml
├── settings_empty.rb
├── settings2.rb
├── settings3.rb
├── settings4.rb
├── settings.rb
├── spec_helper.rb
├── settings.yml
└── settingslogic_spec.rb
├── Gemfile
├── .travis.yml
├── .gitignore
├── Rakefile
├── Gemfile.lock
├── settingslogic.gemspec
├── LICENSE
├── README.rdoc
└── lib
└── settingslogic.rb
/spec/settings_empty.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | gemspec
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | rvm:
3 | - 1.8.7
4 | - 1.9.3
5 | - 2.0.0
6 | - 2.1.2
7 |
--------------------------------------------------------------------------------
/spec/settings_empty.rb:
--------------------------------------------------------------------------------
1 | class SettingsEmpty < Settingslogic
2 | source "#{File.dirname(__FILE__)}/settings_empty.yml"
3 | end
4 |
--------------------------------------------------------------------------------
/spec/settings2.rb:
--------------------------------------------------------------------------------
1 | class Settings2 < Settingslogic
2 | source "#{File.dirname(__FILE__)}/settings.yml"
3 | namespace "setting1"
4 | end
--------------------------------------------------------------------------------
/spec/settings3.rb:
--------------------------------------------------------------------------------
1 | class Settings3 < Settingslogic
2 | source "#{File.dirname(__FILE__)}/settings.yml"
3 | load! # test of load
4 | end
--------------------------------------------------------------------------------
/spec/settings4.rb:
--------------------------------------------------------------------------------
1 | class Settings4 < Settingslogic
2 | source "#{File.dirname(__FILE__)}/settings.yml"
3 | suppress_errors true
4 | end
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.log
3 | *.sqlite3
4 | pkg/*
5 | coverage/*
6 | doc/*
7 | benchmarks/*
8 | .bundle
9 | vendor/bundle
10 | .rvmrc
11 |
--------------------------------------------------------------------------------
/spec/settings.rb:
--------------------------------------------------------------------------------
1 | class Settings < Settingslogic
2 | source "#{File.dirname(__FILE__)}/settings.yml"
3 | end
4 |
5 | class SettingsInst < Settingslogic
6 | end
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'bundler'
2 | Bundler::GemHelper.install_tasks
3 |
4 | require 'rspec/core/rake_task'
5 | RSpec::Core::RakeTask.new
6 |
7 | task :default => :spec
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | $LOAD_PATH.unshift(File.dirname(__FILE__))
2 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3 | require 'rspec'
4 | require 'settingslogic'
5 | require 'settings'
6 | require 'settings2'
7 | require 'settings3'
8 | require 'settings4'
9 | require 'settings_empty'
10 |
11 | # Needed to test Settings3
12 | Object.send :define_method, 'collides' do
13 | 'collision'
14 | end
15 |
16 | RSpec.configure do |config|
17 | end
18 |
--------------------------------------------------------------------------------
/spec/settings.yml:
--------------------------------------------------------------------------------
1 | setting1:
2 | setting1_child: saweet
3 | deep:
4 | another: my value
5 | child:
6 | value: 2
7 |
8 | setting2: 5
9 | setting3: <%= 5 * 5 %>
10 | name: test
11 |
12 | language:
13 | haskell:
14 | paradigm: functional
15 | smalltalk:
16 | paradigm: object oriented
17 |
18 | collides:
19 | does: not
20 | nested:
21 | collides:
22 | does: not either
23 |
24 | array:
25 | -
26 | name: first
27 | -
28 | name: second
29 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | settingslogic (2.0.9)
5 |
6 | GEM
7 | remote: https://rubygems.org/
8 | specs:
9 | diff-lcs (1.1.3)
10 | rake (10.0.3)
11 | rspec (2.12.0)
12 | rspec-core (~> 2.12.0)
13 | rspec-expectations (~> 2.12.0)
14 | rspec-mocks (~> 2.12.0)
15 | rspec-core (2.12.2)
16 | rspec-expectations (2.12.1)
17 | diff-lcs (~> 1.1.3)
18 | rspec-mocks (2.12.1)
19 |
20 | PLATFORMS
21 | ruby
22 |
23 | DEPENDENCIES
24 | rake
25 | rspec
26 | settingslogic!
27 |
--------------------------------------------------------------------------------
/settingslogic.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | $:.push File.expand_path("../lib", __FILE__)
3 |
4 | Gem::Specification.new do |s|
5 | s.name = "settingslogic"
6 | s.version = "2.0.9"
7 | s.platform = Gem::Platform::RUBY
8 | s.authors = ["Ben Johnson"]
9 | s.email = ["bjohnson@binarylogic.com"]
10 | s.homepage = "http://github.com/binarylogic/settingslogic"
11 | s.summary = %q{A simple and straightforward settings solution that uses an ERB enabled YAML file and a singleton design pattern.}
12 | s.description = %q{A simple and straightforward settings solution that uses an ERB enabled YAML file and a singleton design pattern.}
13 |
14 | s.add_development_dependency 'rake'
15 | s.add_development_dependency 'rspec'
16 |
17 | s.files = `git ls-files`.split("\n")
18 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20 | s.require_paths = ["lib"]
21 | end
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008 Ben Johnson of Binary Logic (binarylogic.com)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.rdoc:
--------------------------------------------------------------------------------
1 | = Settingslogic
2 |
3 | == Project Moved: This project has been moved to https://github.com/settingslogic/settingslogic
4 |
5 | Settingslogic is a simple configuration / settings solution that uses an ERB enabled YAML file. It has been great for
6 | our apps, maybe you will enjoy it too. Settingslogic works with Rails, Sinatra, or any Ruby project.
7 |
8 | {
}[http://badge.fury.io/rb/settingslogic]
9 | {
}[https://travis-ci.org/settingslogic/settingslogic]
10 | {
}[http://inch-ci.org/github/settingslogic/settingslogic]
11 |
12 | == Helpful links
13 |
14 | * Documentation: http://rdoc.info/projects/binarylogic/settingslogic
15 | * Repository: http://github.com/binarylogic/settingslogic/tree/master
16 | * Issues: http://github.com/binarylogic/settingslogic/issues
17 |
18 | == Installation
19 |
20 | gem install settingslogic
21 |
22 | == Usage
23 |
24 | === 1. Define your class
25 |
26 | Instead of defining a Settings constant for you, that task is left to you. Simply create a class in your application
27 | that looks like:
28 |
29 | class Settings < Settingslogic
30 | source "#{Rails.root}/config/application.yml"
31 | namespace Rails.env
32 | end
33 |
34 | Name it Settings, name it Config, name it whatever you want. Add as many or as few as you like. A good place to put
35 | this file in a rails app is app/models/settings.rb
36 |
37 | I felt adding a settings file in your app was more straightforward, less tricky, and more flexible.
38 |
39 | === 2. Create your settings
40 |
41 | Notice above we specified an absolute path to our settings file called "application.yml". This is just a typical YAML file.
42 | Also notice above that we specified a namespace for our environment. A namespace is just an optional string that corresponds
43 | to a key in the YAML file.
44 |
45 | Using a namespace allows us to change our configuration depending on our environment:
46 |
47 | # config/application.yml
48 | defaults: &defaults
49 | cool:
50 | saweet: nested settings
51 | neat_setting: 24
52 | awesome_setting: <%= "Did you know 5 + 5 = #{5 + 5}?" %>
53 |
54 | development:
55 | <<: *defaults
56 | neat_setting: 800
57 |
58 | test:
59 | <<: *defaults
60 |
61 | production:
62 | <<: *defaults
63 |
64 | _Note_: Certain Ruby/Bundler versions include a version of the Psych YAML parser which incorrectly handles merges (the `<<` in the example above.)
65 | If your default settings seem to be overwriting your environment-specific settings, including the following lines in your config/boot.rb file may solve the problem:
66 |
67 | require 'yaml'
68 | YAML::ENGINE.yamler= 'syck'
69 |
70 | === 3. Access your settings
71 |
72 | >> Rails.env
73 | => "development"
74 |
75 | >> Settings.cool
76 | => "#"
77 |
78 | >> Settings.cool.saweet
79 | => "nested settings"
80 |
81 | >> Settings.neat_setting
82 | => 800
83 |
84 | >> Settings.awesome_setting
85 | => "Did you know 5 + 5 = 10?"
86 |
87 | You can use these settings anywhere, for example in a model:
88 |
89 | class Post < ActiveRecord::Base
90 | self.per_page = Settings.pagination.posts_per_page
91 | end
92 |
93 | === 4. Optional / dynamic settings
94 |
95 | Often, you will want to handle defaults in your application logic itself, to reduce the number of settings
96 | you need to put in your YAML file. You can access an optional setting by using Hash notation:
97 |
98 | >> Settings.messaging.queue_name
99 | => Exception: Missing setting 'queue_name' in 'message' section in 'application.yml'
100 |
101 | >> Settings.messaging['queue_name']
102 | => nil
103 |
104 | >> Settings.messaging['queue_name'] ||= 'user_mail'
105 | => "user_mail"
106 |
107 | >> Settings.messaging.queue_name
108 | => "user_mail"
109 |
110 | Modifying our model example:
111 |
112 | class Post < ActiveRecord::Base
113 | self.per_page = Settings.posts['per_page'] || Settings.pagination.per_page
114 | end
115 |
116 | This would allow you to specify a custom value for per_page just for posts, or
117 | to fall back to your default value if not specified.
118 |
119 | === 5. Suppressing Exceptions Conditionally
120 |
121 | Raising exceptions for missing settings helps highlight configuration problems. However, in a
122 | Rails app it may make sense to suppress this in production and return nil for missing settings.
123 | While it's useful to stop and highlight an error in development or test environments, this is
124 | often not the right answer for production.
125 |
126 | class Settings < Settingslogic
127 | source "#{Rails.root}/config/application.yml"
128 | namespace Rails.env
129 | suppress_errors Rails.env.production?
130 | end
131 |
132 | >> Settings.non_existent_key
133 | => nil
134 |
135 | == Note on Sinatra / Capistrano / Vlad
136 |
137 | Each of these frameworks uses a +set+ convention for settings, which actually defines methods
138 | in the global Object namespace:
139 |
140 | set :application, "myapp" # does "def application" globally
141 |
142 | This can cause collisions with Settingslogic, since those methods are global. Luckily, the
143 | solution is to just add a call to load! in your class:
144 |
145 | class Settings < Settingslogic
146 | source "#{Rails.root}/config/application.yml"
147 | namespace Rails.env
148 | load!
149 | end
150 |
151 | It's probably always safest to add load! to your class, since this guarantees settings will be
152 | loaded at that time, rather than lazily later via method_missing.
153 |
154 | Finally, you can reload all your settings later as well:
155 |
156 | Settings.reload!
157 |
158 | This is useful if you want to support changing your settings YAML without restarting your app.
159 |
160 | == Author
161 |
162 | Copyright (c) 2008-2010 {Ben Johnson}[http://github.com/binarylogic] of {Binary Logic}[http://www.binarylogic.com],
163 | released under the MIT license. Support for optional settings and reloading by {Nate Wiger}[http://nate.wiger.org].
164 |
--------------------------------------------------------------------------------
/lib/settingslogic.rb:
--------------------------------------------------------------------------------
1 | require "yaml"
2 | require "erb"
3 | require 'open-uri'
4 |
5 | # A simple settings solution using a YAML file. See README for more information.
6 | class Settingslogic < Hash
7 | class MissingSetting < StandardError; end
8 |
9 | class << self
10 | def name # :nodoc:
11 | self.superclass != Hash && instance.key?("name") ? instance.name : super
12 | end
13 |
14 | # Enables Settings.get('nested.key.name') for dynamic access
15 | def get(key)
16 | parts = key.split('.')
17 | curs = self
18 | while p = parts.shift
19 | curs = curs.send(p)
20 | end
21 | curs
22 | end
23 |
24 | def source(value = nil)
25 | @source ||= value
26 | end
27 |
28 | def namespace(value = nil)
29 | @namespace ||= value
30 | end
31 |
32 | def suppress_errors(value = nil)
33 | @suppress_errors ||= value
34 | end
35 |
36 | def [](key)
37 | instance.fetch(key.to_s, nil)
38 | end
39 |
40 | def []=(key, val)
41 | # Setting[:key][:key2] = 'value' for dynamic settings
42 | val = new(val, source) if val.is_a? Hash
43 | instance.store(key.to_s, val)
44 | instance.create_accessor_for(key, val)
45 | end
46 |
47 | def load!
48 | instance
49 | true
50 | end
51 |
52 | def reload!
53 | @instance = nil
54 | load!
55 | end
56 |
57 | private
58 | def instance
59 | return @instance if @instance
60 | @instance = new
61 | create_accessors!
62 | @instance
63 | end
64 |
65 | def method_missing(name, *args, &block)
66 | instance.send(name, *args, &block)
67 | end
68 |
69 | # It would be great to DRY this up somehow, someday, but it's difficult because
70 | # of the singleton pattern. Basically this proxies Setting.foo to Setting.instance.foo
71 | def create_accessors!
72 | instance.each do |key,val|
73 | create_accessor_for(key)
74 | end
75 | end
76 |
77 | def create_accessor_for(key)
78 | return unless key.to_s =~ /^\w+$/ # could have "some-setting:" which blows up eval
79 | instance_eval "def #{key}; instance.send(:#{key}); end"
80 | end
81 |
82 | end
83 |
84 | # Initializes a new settings object. You can initialize an object in any of the following ways:
85 | #
86 | # Settings.new(:application) # will look for config/application.yml
87 | # Settings.new("application.yaml") # will look for application.yaml
88 | # Settings.new("/var/configs/application.yml") # will look for /var/configs/application.yml
89 | # Settings.new(:config1 => 1, :config2 => 2)
90 | #
91 | # Basically if you pass a symbol it will look for that file in the configs directory of your rails app,
92 | # if you are using this in rails. If you pass a string it should be an absolute path to your settings file.
93 | # Then you can pass a hash, and it just allows you to access the hash via methods.
94 | def initialize(hash_or_file = self.class.source, section = nil)
95 | #puts "new! #{hash_or_file}"
96 | case hash_or_file
97 | when nil
98 | raise Errno::ENOENT, "No file specified as Settingslogic source"
99 | when Hash
100 | self.replace hash_or_file
101 | else
102 | file_contents = open(hash_or_file).read
103 | hash = file_contents.empty? ? {} : YAML.load(ERB.new(file_contents).result).to_hash
104 | if self.class.namespace
105 | hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}")
106 | end
107 | self.replace hash
108 | end
109 | @section = section || self.class.source # so end of error says "in application.yml"
110 | create_accessors!
111 | end
112 |
113 | # Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used.
114 | # Otherwise, create_accessors! (called by new) will have created actual methods for each key.
115 | def method_missing(name, *args, &block)
116 | key = name.to_s
117 | return missing_key("Missing setting '#{key}' in #{@section}") unless has_key? key
118 | value = fetch(key)
119 | create_accessor_for(key)
120 | value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value
121 | end
122 |
123 | def [](key)
124 | fetch(key.to_s, nil)
125 | end
126 |
127 | def []=(key,val)
128 | # Setting[:key][:key2] = 'value' for dynamic settings
129 | val = self.class.new(val, @section) if val.is_a? Hash
130 | store(key.to_s, val)
131 | create_accessor_for(key, val)
132 | end
133 |
134 | # Returns an instance of a Hash object
135 | def to_hash
136 | Hash[self]
137 | end
138 |
139 | # This handles naming collisions with Sinatra/Vlad/Capistrano. Since these use a set()
140 | # helper that defines methods in Object, ANY method_missing ANYWHERE picks up the Vlad/Sinatra
141 | # settings! So settings.deploy_to title actually calls Object.deploy_to (from set :deploy_to, "host"),
142 | # rather than the app_yml['deploy_to'] hash. Jeezus.
143 | def create_accessors!
144 | self.each do |key,val|
145 | create_accessor_for(key)
146 | end
147 | end
148 |
149 | # Use instance_eval/class_eval because they're actually more efficient than define_method{}
150 | # http://stackoverflow.com/questions/185947/ruby-definemethod-vs-def
151 | # http://bmorearty.wordpress.com/2009/01/09/fun-with-rubys-instance_eval-and-class_eval/
152 | def create_accessor_for(key, val=nil)
153 | return unless key.to_s =~ /^\w+$/ # could have "some-setting:" which blows up eval
154 | instance_variable_set("@#{key}", val)
155 | self.class.class_eval <<-EndEval
156 | def #{key}
157 | return @#{key} if @#{key}
158 | return missing_key("Missing setting '#{key}' in #{@section}") unless has_key? '#{key}'
159 | value = fetch('#{key}')
160 | @#{key} = if value.is_a?(Hash)
161 | self.class.new(value, "'#{key}' section in #{@section}")
162 | elsif value.is_a?(Array) && value.all?{|v| v.is_a? Hash}
163 | value.map{|v| self.class.new(v)}
164 | else
165 | value
166 | end
167 | end
168 | EndEval
169 | end
170 |
171 | def symbolize_keys
172 |
173 | inject({}) do |memo, tuple|
174 |
175 | k = (tuple.first.to_sym rescue tuple.first) || tuple.first
176 |
177 | v = k.is_a?(Symbol) ? send(k) : tuple.last # make sure the value is accessed the same way Settings.foo.bar works
178 |
179 | memo[k] = v && v.respond_to?(:symbolize_keys) ? v.symbolize_keys : v #recurse for nested hashes
180 |
181 | memo
182 | end
183 |
184 | end
185 |
186 | def missing_key(msg)
187 | return nil if self.class.suppress_errors
188 |
189 | raise MissingSetting, msg
190 | end
191 | end
192 |
--------------------------------------------------------------------------------
/spec/settingslogic_spec.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
2 |
3 | describe "Settingslogic" do
4 | it "should access settings" do
5 | Settings.setting2.should == 5
6 | end
7 |
8 | it "should access nested settings" do
9 | Settings.setting1.setting1_child.should == "saweet"
10 | end
11 |
12 | it "should access settings in nested arrays" do
13 | Settings.array.first.name.should == "first"
14 | end
15 |
16 | it "should access deep nested settings" do
17 | Settings.setting1.deep.another.should == "my value"
18 | end
19 |
20 | it "should access extra deep nested settings" do
21 | Settings.setting1.deep.child.value.should == 2
22 | end
23 |
24 | it "should enable erb" do
25 | Settings.setting3.should == 25
26 | end
27 |
28 | it "should namespace settings" do
29 | Settings2.setting1_child.should == "saweet"
30 | Settings2.deep.another.should == "my value"
31 | end
32 |
33 | it "should return the namespace" do
34 | Settings.namespace.should be_nil
35 | Settings2.namespace.should == 'setting1'
36 | end
37 |
38 | it "should distinguish nested keys" do
39 | Settings.language.haskell.paradigm.should == 'functional'
40 | Settings.language.smalltalk.paradigm.should == 'object oriented'
41 | end
42 |
43 | it "should not collide with global methods" do
44 | Settings3.nested.collides.does.should == 'not either'
45 | Settings3[:nested] = 'fooey'
46 | Settings3[:nested].should == 'fooey'
47 | Settings3.nested.should == 'fooey'
48 | Settings3.collides.does.should == 'not'
49 | end
50 |
51 | it "should raise a helpful error message" do
52 | e = nil
53 | begin
54 | Settings.missing
55 | rescue => e
56 | e.should be_kind_of Settingslogic::MissingSetting
57 | end
58 | e.should_not be_nil
59 | e.message.should =~ /Missing setting 'missing' in/
60 |
61 | e = nil
62 | begin
63 | Settings.language.missing
64 | rescue => e
65 | e.should be_kind_of Settingslogic::MissingSetting
66 | end
67 | e.should_not be_nil
68 | e.message.should =~ /Missing setting 'missing' in 'language' section/
69 | end
70 |
71 | it "should handle optional / dynamic settings" do
72 | e = nil
73 | begin
74 | Settings.language.erlang
75 | rescue => e
76 | e.should be_kind_of Settingslogic::MissingSetting
77 | end
78 | e.should_not be_nil
79 | e.message.should =~ /Missing setting 'erlang' in 'language' section/
80 |
81 | Settings.language['erlang'].should be_nil
82 | Settings.language['erlang'] = 5
83 | Settings.language['erlang'].should == 5
84 |
85 | Settings.language['erlang'] = {'paradigm' => 'functional'}
86 | Settings.language.erlang.paradigm.should == 'functional'
87 | Settings.respond_to?('erlang').should be_false
88 |
89 | Settings.reload!
90 | Settings.language['erlang'].should be_nil
91 |
92 | Settings.language[:erlang] ||= 5
93 | Settings.language[:erlang].should == 5
94 |
95 | Settings.language[:erlang] = {}
96 | Settings.language[:erlang][:paradigm] = 'functional'
97 | Settings.language.erlang.paradigm.should == 'functional'
98 |
99 | Settings[:toplevel] = '42'
100 | Settings.toplevel.should == '42'
101 | end
102 |
103 | it "should raise an error on a nil source argument" do
104 | class NoSource < Settingslogic; end
105 | e = nil
106 | begin
107 | NoSource.foo.bar
108 | rescue => e
109 | e.should be_kind_of Errno::ENOENT
110 | end
111 | e.should_not be_nil
112 | end
113 |
114 | it "should allow suppressing errors" do
115 | Settings4.non_existent_key.should be_nil
116 | end
117 |
118 | # This one edge case currently does not pass, because it requires very
119 | # esoteric code in order to make it pass. It was judged not worth fixing,
120 | # as it introduces significant complexity for minor gain.
121 | # it "should handle reloading top-level settings"
122 | # Settings[:inspect] = 'yeah baby'
123 | # Settings.inspect.should == 'yeah baby'
124 | # Settings.reload!
125 | # Settings.inspect.should == 'Settings'
126 | # end
127 |
128 | it "should handle oddly-named settings" do
129 | Settings.language['some-dash-setting#'] = 'dashtastic'
130 | Settings.language['some-dash-setting#'].should == 'dashtastic'
131 | end
132 |
133 | it "should handle settings with nil value" do
134 | Settings["flag"] = true
135 | Settings["flag"] = nil
136 | Settings.flag.should == nil
137 | end
138 |
139 | it "should handle settings with false value" do
140 | Settings["flag"] = true
141 | Settings["flag"] = false
142 | Settings.flag.should == false
143 | end
144 |
145 | it "should support instance usage as well" do
146 | settings = SettingsInst.new(Settings.source)
147 | settings.setting1.setting1_child.should == "saweet"
148 | end
149 |
150 | it "should be able to get() a key with dot.notation" do
151 | Settings.get('setting1.setting1_child').should == "saweet"
152 | Settings.get('setting1.deep.another').should == "my value"
153 | Settings.get('setting1.deep.child.value').should == 2
154 | end
155 |
156 | # If .name is not a property, delegate to superclass
157 | it "should respond with Module.name" do
158 | Settings2.name.should == "Settings2"
159 | end
160 |
161 | # If .name is called on Settingslogic itself, handle appropriately
162 | # by delegating to Hash
163 | it "should have the parent class always respond with Module.name" do
164 | Settingslogic.name.should == 'Settingslogic'
165 | end
166 |
167 | # If .name is a property, respond with that instead of delegating to superclass
168 | it "should allow a name setting to be overriden" do
169 | Settings.name.should == 'test'
170 | end
171 |
172 | it "should allow symbolize_keys" do
173 | Settings.reload!
174 | result = Settings.language.haskell.symbolize_keys
175 | result.class.should == Hash
176 | result.should == {:paradigm => "functional"}
177 | end
178 |
179 | it "should allow symbolize_keys on nested hashes" do
180 | Settings.reload!
181 | result = Settings.language.symbolize_keys
182 | result.class.should == Hash
183 | result.should == {
184 | :haskell => {:paradigm => "functional"},
185 | :smalltalk => {:paradigm => "object oriented"}
186 | }
187 | end
188 |
189 | it "should handle empty file" do
190 | SettingsEmpty.keys.should eql([])
191 | end
192 |
193 | # Put this test last or else call to .instance will load @instance,
194 | # masking bugs.
195 | it "should be a hash" do
196 | Settings.send(:instance).should be_is_a(Hash)
197 | end
198 |
199 | describe "#to_hash" do
200 | it "should return a new instance of a Hash object" do
201 | Settings.to_hash.should be_kind_of(Hash)
202 | Settings.to_hash.class.name.should == "Hash"
203 | Settings.to_hash.object_id.should_not == Settings.object_id
204 | end
205 | end
206 |
207 | end
208 |
--------------------------------------------------------------------------------