dc-settingslogic 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +30 -0
- data/LICENSE +20 -0
- data/README.rdoc +157 -0
- data/Rakefile +7 -0
- data/lib/settingslogic.rb +196 -0
- data/settingslogic.gemspec +21 -0
- data/spec/multi_source_config.rb +4 -0
- data/spec/override.yml +3 -0
- data/spec/settings.rb +6 -0
- data/spec/settings.yml +28 -0
- data/spec/settings2.rb +4 -0
- data/spec/settings3.rb +4 -0
- data/spec/settings4.rb +4 -0
- data/spec/settings_empty.rb +3 -0
- data/spec/settings_empty.yml +0 -0
- data/spec/settingslogic_spec.rb +184 -0
- data/spec/spec_helper.rb +17 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3b99784f5ea316afb0a97ad07755540a89bf0e55
|
4
|
+
data.tar.gz: ccdfb941953d43fa57d70236807ab6fa5f548f92
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c04822d02195eb8c005167b8a7cb0630060c0413ee6b686ad918da5e5bdcbf099f9b6bbb72ab39057a1966286e175da50df05bf20227dafbc5ce151ca669417f
|
7
|
+
data.tar.gz: 4733c6ddca69d39aa9434e20cdbcd07bfefb94e16efddb07aeb608b484f69eb1584bef0d5a040321be400e42050995ee0d22d2d92668e1ccee3e7c04e5a75867
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
dc-settingslogic (2.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.5)
|
10
|
+
rake (10.3.2)
|
11
|
+
rspec (3.0.0)
|
12
|
+
rspec-core (~> 3.0.0)
|
13
|
+
rspec-expectations (~> 3.0.0)
|
14
|
+
rspec-mocks (~> 3.0.0)
|
15
|
+
rspec-core (3.0.2)
|
16
|
+
rspec-support (~> 3.0.0)
|
17
|
+
rspec-expectations (3.0.2)
|
18
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
19
|
+
rspec-support (~> 3.0.0)
|
20
|
+
rspec-mocks (3.0.2)
|
21
|
+
rspec-support (~> 3.0.0)
|
22
|
+
rspec-support (3.0.2)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
dc-settingslogic!
|
29
|
+
rake
|
30
|
+
rspec
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
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.
|
data/README.rdoc
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
= Settingslogic
|
2
|
+
|
3
|
+
Settingslogic is a simple configuration / settings solution that uses an ERB enabled YAML file. It has been great for
|
4
|
+
our apps, maybe you will enjoy it too. Settingslogic works with Rails, Sinatra, or any Ruby project.
|
5
|
+
|
6
|
+
== Helpful links
|
7
|
+
|
8
|
+
* <b>Documentation:</b> http://rdoc.info/projects/binarylogic/settingslogic
|
9
|
+
* <b>Repository:</b> http://github.com/binarylogic/settingslogic/tree/master
|
10
|
+
* <b>Issues:</b> http://github.com/binarylogic/settingslogic/issues
|
11
|
+
|
12
|
+
== Installation
|
13
|
+
|
14
|
+
gem install settingslogic
|
15
|
+
|
16
|
+
== Usage
|
17
|
+
|
18
|
+
=== 1. Define your class
|
19
|
+
|
20
|
+
Instead of defining a Settings constant for you, that task is left to you. Simply create a class in your application
|
21
|
+
that looks like:
|
22
|
+
|
23
|
+
class Settings < Settingslogic
|
24
|
+
source "#{Rails.root}/config/application.yml"
|
25
|
+
namespace Rails.env
|
26
|
+
end
|
27
|
+
|
28
|
+
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
|
29
|
+
this file in a rails app is app/models/settings.rb
|
30
|
+
|
31
|
+
I felt adding a settings file in your app was more straightforward, less tricky, and more flexible.
|
32
|
+
|
33
|
+
=== 2. Create your settings
|
34
|
+
|
35
|
+
Notice above we specified an absolute path to our settings file called "application.yml". This is just a typical YAML file.
|
36
|
+
Also notice above that we specified a namespace for our environment. A namespace is just an optional string that corresponds
|
37
|
+
to a key in the YAML file.
|
38
|
+
|
39
|
+
Using a namespace allows us to change our configuration depending on our environment:
|
40
|
+
|
41
|
+
# config/application.yml
|
42
|
+
defaults: &defaults
|
43
|
+
cool:
|
44
|
+
saweet: nested settings
|
45
|
+
neat_setting: 24
|
46
|
+
awesome_setting: <%= "Did you know 5 + 5 = #{5 + 5}?" %>
|
47
|
+
|
48
|
+
development:
|
49
|
+
<<: *defaults
|
50
|
+
neat_setting: 800
|
51
|
+
|
52
|
+
test:
|
53
|
+
<<: *defaults
|
54
|
+
|
55
|
+
production:
|
56
|
+
<<: *defaults
|
57
|
+
|
58
|
+
_Note_: Certain Ruby/Bundler versions include a version of the Psych YAML parser which incorrectly handles merges (the `<<` in the example above.)
|
59
|
+
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:
|
60
|
+
|
61
|
+
require 'yaml'
|
62
|
+
YAML::ENGINE.yamler= 'syck'
|
63
|
+
|
64
|
+
=== 3. Access your settings
|
65
|
+
|
66
|
+
>> Rails.env
|
67
|
+
=> "development"
|
68
|
+
|
69
|
+
>> Settings.cool
|
70
|
+
=> "#<Settingslogic::Settings ... >"
|
71
|
+
|
72
|
+
>> Settings.cool.saweet
|
73
|
+
=> "nested settings"
|
74
|
+
|
75
|
+
>> Settings.neat_setting
|
76
|
+
=> 800
|
77
|
+
|
78
|
+
>> Settings.awesome_setting
|
79
|
+
=> "Did you know 5 + 5 = 10?"
|
80
|
+
|
81
|
+
You can use these settings anywhere, for example in a model:
|
82
|
+
|
83
|
+
class Post < ActiveRecord::Base
|
84
|
+
self.per_page = Settings.pagination.posts_per_page
|
85
|
+
end
|
86
|
+
|
87
|
+
=== 4. Optional / dynamic settings
|
88
|
+
|
89
|
+
Often, you will want to handle defaults in your application logic itself, to reduce the number of settings
|
90
|
+
you need to put in your YAML file. You can access an optional setting by using Hash notation:
|
91
|
+
|
92
|
+
>> Settings.messaging.queue_name
|
93
|
+
=> Exception: Missing setting 'queue_name' in 'message' section in 'application.yml'
|
94
|
+
|
95
|
+
>> Settings.messaging['queue_name']
|
96
|
+
=> nil
|
97
|
+
|
98
|
+
>> Settings.messaging['queue_name'] ||= 'user_mail'
|
99
|
+
=> "user_mail"
|
100
|
+
|
101
|
+
>> Settings.messaging.queue_name
|
102
|
+
=> "user_mail"
|
103
|
+
|
104
|
+
Modifying our model example:
|
105
|
+
|
106
|
+
class Post < ActiveRecord::Base
|
107
|
+
self.per_page = Settings.posts['per_page'] || Settings.pagination.per_page
|
108
|
+
end
|
109
|
+
|
110
|
+
This would allow you to specify a custom value for per_page just for posts, or
|
111
|
+
to fall back to your default value if not specified.
|
112
|
+
|
113
|
+
=== 5. Suppressing Exceptions Conditionally
|
114
|
+
|
115
|
+
Raising exceptions for missing settings helps highlight configuration problems. However, in a
|
116
|
+
Rails app it may make sense to suppress this in production and return nil for missing settings.
|
117
|
+
While it's useful to stop and highlight an error in development or test environments, this is
|
118
|
+
often not the right answer for production.
|
119
|
+
|
120
|
+
class Settings < Settingslogic
|
121
|
+
source "#{Rails.root}/config/application.yml"
|
122
|
+
namespace Rails.env
|
123
|
+
suppress_errors Rails.env.production?
|
124
|
+
end
|
125
|
+
|
126
|
+
>> Settings.non_existent_key
|
127
|
+
=> nil
|
128
|
+
|
129
|
+
== Note on Sinatra / Capistrano / Vlad
|
130
|
+
|
131
|
+
Each of these frameworks uses a +set+ convention for settings, which actually defines methods
|
132
|
+
in the global Object namespace:
|
133
|
+
|
134
|
+
set :application, "myapp" # does "def application" globally
|
135
|
+
|
136
|
+
This can cause collisions with Settingslogic, since those methods are global. Luckily, the
|
137
|
+
solution is to just add a call to load! in your class:
|
138
|
+
|
139
|
+
class Settings < Settingslogic
|
140
|
+
source "#{Rails.root}/config/application.yml"
|
141
|
+
namespace Rails.env
|
142
|
+
load!
|
143
|
+
end
|
144
|
+
|
145
|
+
It's probably always safest to add load! to your class, since this guarantees settings will be
|
146
|
+
loaded at that time, rather than lazily later via method_missing.
|
147
|
+
|
148
|
+
Finally, you can reload all your settings later as well:
|
149
|
+
|
150
|
+
Settings.reload!
|
151
|
+
|
152
|
+
This is useful if you want to support changing your settings YAML without restarting your app.
|
153
|
+
|
154
|
+
== Author
|
155
|
+
|
156
|
+
Copyright (c) 2008-2010 {Ben Johnson}[http://github.com/binarylogic] of {Binary Logic}[http://www.binarylogic.com],
|
157
|
+
released under the MIT license. Support for optional settings and reloading by {Nate Wiger}[http://nate.wiger.org].
|
data/Rakefile
ADDED
@@ -0,0 +1,196 @@
|
|
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 ||= []
|
26
|
+
@source << value
|
27
|
+
end
|
28
|
+
|
29
|
+
def namespace(value = nil)
|
30
|
+
@namespace ||= value
|
31
|
+
end
|
32
|
+
|
33
|
+
def suppress_errors(value = nil)
|
34
|
+
@suppress_errors ||= value
|
35
|
+
end
|
36
|
+
|
37
|
+
def [](key)
|
38
|
+
instance.fetch(key.to_s, nil)
|
39
|
+
end
|
40
|
+
|
41
|
+
def []=(key, val)
|
42
|
+
# Setting[:key][:key2] = 'value' for dynamic settings
|
43
|
+
val = new(val, source) if val.is_a? Hash
|
44
|
+
instance.store(key.to_s, val)
|
45
|
+
instance.create_accessor_for(key, val)
|
46
|
+
end
|
47
|
+
|
48
|
+
def load!
|
49
|
+
instance
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
def reload!
|
54
|
+
@instance = nil
|
55
|
+
load!
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def instance
|
60
|
+
return @instance if @instance
|
61
|
+
@instance = new
|
62
|
+
create_accessors!
|
63
|
+
@instance
|
64
|
+
end
|
65
|
+
|
66
|
+
def method_missing(name, *args, &block)
|
67
|
+
instance.send(name, *args, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
# It would be great to DRY this up somehow, someday, but it's difficult because
|
71
|
+
# of the singleton pattern. Basically this proxies Setting.foo to Setting.instance.foo
|
72
|
+
def create_accessors!
|
73
|
+
instance.each do |key,val|
|
74
|
+
create_accessor_for(key)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def create_accessor_for(key)
|
79
|
+
return unless key.to_s =~ /^\w+$/ # could have "some-setting:" which blows up eval
|
80
|
+
instance_eval "def #{key}; instance.send(:#{key}); end"
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
# Initializes a new settings object. You can initialize an object in any of the following ways:
|
86
|
+
#
|
87
|
+
# Settings.new(:application) # will look for config/application.yml
|
88
|
+
# Settings.new("application.yaml") # will look for application.yaml
|
89
|
+
# Settings.new("/var/configs/application.yml") # will look for /var/configs/application.yml
|
90
|
+
# Settings.new(:config1 => 1, :config2 => 2)
|
91
|
+
#
|
92
|
+
# Basically if you pass a symbol it will look for that file in the configs directory of your rails app,
|
93
|
+
# if you are using this in rails. If you pass a string it should be an absolute path to your settings file.
|
94
|
+
# Then you can pass a hash, and it just allows you to access the hash via methods.
|
95
|
+
def initialize(hash_or_file = self.class.source, section = nil)
|
96
|
+
#puts "new! #{hash_or_file}"
|
97
|
+
case hash_or_file
|
98
|
+
when nil
|
99
|
+
raise Errno::ENOENT, "No file specified as Settingslogic source"
|
100
|
+
when Hash
|
101
|
+
self.replace hash_or_file
|
102
|
+
else
|
103
|
+
hash = {}
|
104
|
+
files = hash_or_file.reject { |file| file.nil? }
|
105
|
+
files.each do |file|
|
106
|
+
next unless File.exist? file
|
107
|
+
|
108
|
+
file_contents = open(file).read
|
109
|
+
single_hash = file_contents.empty? ? {} : YAML.load(ERB.new(file_contents).result).to_hash
|
110
|
+
hash.merge! single_hash
|
111
|
+
end
|
112
|
+
if self.class.namespace
|
113
|
+
hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{files.join(', ')}")
|
114
|
+
end
|
115
|
+
self.replace hash
|
116
|
+
end
|
117
|
+
@section = section || self.class.source.reject { |file| file.nil? }.join(', ') # so end of error says "in application.yml"
|
118
|
+
create_accessors!
|
119
|
+
end
|
120
|
+
|
121
|
+
# Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used.
|
122
|
+
# Otherwise, create_accessors! (called by new) will have created actual methods for each key.
|
123
|
+
def method_missing(name, *args, &block)
|
124
|
+
key = name.to_s
|
125
|
+
return missing_key("Missing setting '#{key}' in #{@section}") unless has_key? key
|
126
|
+
value = fetch(key)
|
127
|
+
create_accessor_for(key)
|
128
|
+
value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value
|
129
|
+
end
|
130
|
+
|
131
|
+
def [](key)
|
132
|
+
fetch(key.to_s, nil)
|
133
|
+
end
|
134
|
+
|
135
|
+
def []=(key,val)
|
136
|
+
# Setting[:key][:key2] = 'value' for dynamic settings
|
137
|
+
val = self.class.new(val, @section) if val.is_a? Hash
|
138
|
+
store(key.to_s, val)
|
139
|
+
create_accessor_for(key, val)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns an instance of a Hash object
|
143
|
+
def to_hash
|
144
|
+
Hash[self]
|
145
|
+
end
|
146
|
+
|
147
|
+
# This handles naming collisions with Sinatra/Vlad/Capistrano. Since these use a set()
|
148
|
+
# helper that defines methods in Object, ANY method_missing ANYWHERE picks up the Vlad/Sinatra
|
149
|
+
# settings! So settings.deploy_to title actually calls Object.deploy_to (from set :deploy_to, "host"),
|
150
|
+
# rather than the app_yml['deploy_to'] hash. Jeezus.
|
151
|
+
def create_accessors!
|
152
|
+
self.each do |key,val|
|
153
|
+
create_accessor_for(key)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Use instance_eval/class_eval because they're actually more efficient than define_method{}
|
158
|
+
# http://stackoverflow.com/questions/185947/ruby-definemethod-vs-def
|
159
|
+
# http://bmorearty.wordpress.com/2009/01/09/fun-with-rubys-instance_eval-and-class_eval/
|
160
|
+
def create_accessor_for(key, val=nil)
|
161
|
+
return unless key.to_s =~ /^\w+$/ # could have "some-setting:" which blows up eval
|
162
|
+
instance_variable_set("@#{key}", val)
|
163
|
+
self.class.class_eval <<-EndEval
|
164
|
+
def #{key}
|
165
|
+
return @#{key} if @#{key}
|
166
|
+
return missing_key("Missing setting '#{key}' in #{@section}") unless has_key? '#{key}'
|
167
|
+
value = fetch('#{key}')
|
168
|
+
@#{key} = if value.is_a?(Hash)
|
169
|
+
self.class.new(value, "'#{key}' section in #{@section}")
|
170
|
+
elsif value.is_a?(Array) && value.all?{|v| v.is_a? Hash}
|
171
|
+
value.map{|v| self.class.new(v)}
|
172
|
+
else
|
173
|
+
value
|
174
|
+
end
|
175
|
+
end
|
176
|
+
EndEval
|
177
|
+
end
|
178
|
+
|
179
|
+
def symbolize_keys
|
180
|
+
inject({}) do |memo, tuple|
|
181
|
+
k = (tuple.first.to_sym rescue tuple.first) || tuple.first
|
182
|
+
|
183
|
+
v = k.is_a?(Symbol) ? send(k) : tuple.last # make sure the value is accessed the same way Settings.foo.bar works
|
184
|
+
|
185
|
+
memo[k] = v && v.respond_to?(:symbolize_keys) ? v.symbolize_keys : v #recurse for nested hashes
|
186
|
+
|
187
|
+
memo
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def missing_key(msg)
|
192
|
+
return nil if self.class.suppress_errors
|
193
|
+
|
194
|
+
raise MissingSetting, msg
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "dc-settingslogic"
|
6
|
+
s.version = "2.1.0"
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Ben Johnson", "Jeong, Jiung"]
|
9
|
+
s.email = ["bjohnson@binarylogic.com", "ethernuiel@sanultari.com"]
|
10
|
+
s.homepage = "http://github.com/sanultari/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
|
data/spec/override.yml
ADDED
data/spec/settings.rb
ADDED
data/spec/settings.yml
ADDED
@@ -0,0 +1,28 @@
|
|
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
|
data/spec/settings2.rb
ADDED
data/spec/settings3.rb
ADDED
data/spec/settings4.rb
ADDED
File without changes
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
|
2
|
+
|
3
|
+
describe "Settingslogic" do
|
4
|
+
it "should access settings" do
|
5
|
+
expect(Settings.setting2).to eq(5)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should access nested settings" do
|
9
|
+
expect(Settings.setting1.setting1_child).to eq("saweet")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should access settings in nested arrays" do
|
13
|
+
expect(Settings.array.first.name).to eq("first")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should access deep nested settings" do
|
17
|
+
expect(Settings.setting1.deep.another).to eq("my value")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should access extra deep nested settings" do
|
21
|
+
expect(Settings.setting1.deep.child.value).to eq(2)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should enable erb" do
|
25
|
+
expect(Settings.setting3).to eq(25)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should namespace settings" do
|
29
|
+
expect(Settings2.setting1_child).to eq("saweet")
|
30
|
+
expect(Settings2.deep.another).to eq("my value")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return the namespace" do
|
34
|
+
expect(Settings.namespace).to be_nil
|
35
|
+
expect(Settings2.namespace).to eq('setting1')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should distinguish nested keys" do
|
39
|
+
expect(Settings.language.haskell.paradigm).to eq('functional')
|
40
|
+
expect(Settings.language.smalltalk.paradigm).to eq('object oriented')
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not collide with global methods" do
|
44
|
+
expect(Settings3.nested.collides.does).to eq('not either')
|
45
|
+
Settings3[:nested] = 'fooey'
|
46
|
+
expect(Settings3[:nested]).to eq('fooey')
|
47
|
+
expect(Settings3.nested).to eq('fooey')
|
48
|
+
expect(Settings3.collides.does).to eq('not')
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should raise a helpful error message" do
|
52
|
+
expect { Settings.missing }.to raise_error(Settingslogic::MissingSetting, /Missing setting 'missing' in/)
|
53
|
+
expect { Settings.language.missing }.to raise_error(Settingslogic::MissingSetting, /Missing setting 'missing' in 'language' section/)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should handle optional / dynamic settings" do
|
57
|
+
expect { Settings.language.erlang }.to raise_error(Settingslogic::MissingSetting, /Missing setting 'erlang' in 'language' section/)
|
58
|
+
|
59
|
+
expect(Settings.language['erlang']).to be_nil
|
60
|
+
Settings.language['erlang'] = 5
|
61
|
+
expect(Settings.language['erlang']).to eq(5)
|
62
|
+
|
63
|
+
Settings.language['erlang'] = {'paradigm' => 'functional'}
|
64
|
+
expect(Settings.language.erlang.paradigm).to eq('functional')
|
65
|
+
expect(Settings).not_to respond_to :erlang
|
66
|
+
|
67
|
+
Settings.reload!
|
68
|
+
expect(Settings.language['erlang']).to be_nil
|
69
|
+
|
70
|
+
Settings.language[:erlang] ||= 5
|
71
|
+
expect(Settings.language[:erlang]).to eq(5)
|
72
|
+
|
73
|
+
Settings.language[:erlang] = {}
|
74
|
+
Settings.language[:erlang][:paradigm] = 'functional'
|
75
|
+
expect(Settings.language.erlang.paradigm).to eq('functional')
|
76
|
+
|
77
|
+
Settings[:toplevel] = '42'
|
78
|
+
expect(Settings.toplevel).to eq('42')
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should raise an error on a nil source argument" do
|
82
|
+
class NoSource < Settingslogic; end
|
83
|
+
|
84
|
+
expect { NoSource.foo.bar }.to raise_error Settingslogic::MissingSetting
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should allow suppressing errors" do
|
88
|
+
expect(Settings4.non_existent_key).to be_nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# This one edge case currently does not pass, because it requires very
|
92
|
+
# esoteric code in order to make it pass. It was judged not worth fixing,
|
93
|
+
# as it introduces significant complexity for minor gain.
|
94
|
+
# it "should handle reloading top-level settings"
|
95
|
+
# Settings[:inspect] = 'yeah baby'
|
96
|
+
# Settings.inspect.should == 'yeah baby'
|
97
|
+
# Settings.reload!
|
98
|
+
# Settings.inspect.should == 'Settings'
|
99
|
+
# end
|
100
|
+
|
101
|
+
it "should handle oddly-named settings" do
|
102
|
+
Settings.language['some-dash-setting#'] = 'dashtastic'
|
103
|
+
expect(Settings.language['some-dash-setting#']).to eq('dashtastic')
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should handle settings with nil value" do
|
107
|
+
Settings["flag"] = true
|
108
|
+
Settings["flag"] = nil
|
109
|
+
expect(Settings.flag).to be_nil
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should handle settings with false value" do
|
113
|
+
Settings["flag"] = true
|
114
|
+
Settings["flag"] = false
|
115
|
+
expect(Settings.flag).to eq(false)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should support instance usage as well" do
|
119
|
+
settings = SettingsInst.new(Settings.source)
|
120
|
+
expect(settings.setting1.setting1_child).to eq("saweet")
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should be able to get() a key with dot.notation" do
|
124
|
+
expect(Settings.get('setting1.setting1_child')).to eq("saweet")
|
125
|
+
expect(Settings.get('setting1.deep.another')).to eq("my value")
|
126
|
+
expect(Settings.get('setting1.deep.child.value')).to eq(2)
|
127
|
+
end
|
128
|
+
|
129
|
+
# If .name is not a property, delegate to superclass
|
130
|
+
it "should respond with Module.name" do
|
131
|
+
expect(Settings2.name).to eq("Settings2")
|
132
|
+
end
|
133
|
+
|
134
|
+
# If .name is called on Settingslogic itself, handle appropriately
|
135
|
+
# by delegating to Hash
|
136
|
+
it "should have the parent class always respond with Module.name" do
|
137
|
+
expect(Settingslogic.name).to eq('Settingslogic')
|
138
|
+
end
|
139
|
+
|
140
|
+
# If .name is a property, respond with that instead of delegating to superclass
|
141
|
+
it "should allow a name setting to be overriden" do
|
142
|
+
expect(Settings.name).to eq('test')
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should allow symbolize_keys" do
|
146
|
+
Settings.reload!
|
147
|
+
result = Settings.language.haskell.symbolize_keys
|
148
|
+
expect(result).to be_a Hash
|
149
|
+
expect(result).to eq({:paradigm => "functional"})
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should allow symbolize_keys on nested hashes" do
|
153
|
+
Settings.reload!
|
154
|
+
result = Settings.language.symbolize_keys
|
155
|
+
expect(result).to be_a Hash
|
156
|
+
expect(result).to eq({
|
157
|
+
:haskell => {:paradigm => "functional"},
|
158
|
+
:smalltalk => {:paradigm => "object oriented"}
|
159
|
+
})
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should handle empty file" do
|
163
|
+
expect(SettingsEmpty.keys).to be_empty
|
164
|
+
end
|
165
|
+
|
166
|
+
# Put this test last or else call to .instance will load @instance,
|
167
|
+
# masking bugs.
|
168
|
+
it "should be a hash" do
|
169
|
+
expect(Settings.send(:instance)).to be_a Hash
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should override configuration from multiple source" do
|
173
|
+
expect(MultiSourceConfig.setting2).to eq(10)
|
174
|
+
expect(MultiSourceConfig.override).to eq(true)
|
175
|
+
expect(MultiSourceConfig.name).to eq("test")
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "#to_hash" do
|
179
|
+
it "should return a new instance of a Hash object" do
|
180
|
+
expect(Settings.to_hash).to be_a Hash
|
181
|
+
expect(Settings.to_hash.object_id).not_to eq(Settings.object_id)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'rspec'
|
3
|
+
require 'settingslogic'
|
4
|
+
require_relative 'settings'
|
5
|
+
require_relative 'settings2'
|
6
|
+
require_relative 'settings3'
|
7
|
+
require_relative 'settings4'
|
8
|
+
require_relative 'multi_source_config'
|
9
|
+
require_relative '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
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dc-settingslogic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Johnson
|
8
|
+
- Jeong, Jiung
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-07-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rspec
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
description: A simple and straightforward settings solution that uses an ERB enabled
|
43
|
+
YAML file and a singleton design pattern.
|
44
|
+
email:
|
45
|
+
- bjohnson@binarylogic.com
|
46
|
+
- ethernuiel@sanultari.com
|
47
|
+
executables: []
|
48
|
+
extensions: []
|
49
|
+
extra_rdoc_files: []
|
50
|
+
files:
|
51
|
+
- ".gitignore"
|
52
|
+
- Gemfile
|
53
|
+
- Gemfile.lock
|
54
|
+
- LICENSE
|
55
|
+
- README.rdoc
|
56
|
+
- Rakefile
|
57
|
+
- lib/settingslogic.rb
|
58
|
+
- settingslogic.gemspec
|
59
|
+
- spec/multi_source_config.rb
|
60
|
+
- spec/override.yml
|
61
|
+
- spec/settings.rb
|
62
|
+
- spec/settings.yml
|
63
|
+
- spec/settings2.rb
|
64
|
+
- spec/settings3.rb
|
65
|
+
- spec/settings4.rb
|
66
|
+
- spec/settings_empty.rb
|
67
|
+
- spec/settings_empty.yml
|
68
|
+
- spec/settingslogic_spec.rb
|
69
|
+
- spec/spec_helper.rb
|
70
|
+
homepage: http://github.com/sanultari/settingslogic
|
71
|
+
licenses: []
|
72
|
+
metadata: {}
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 2.2.2
|
90
|
+
signing_key:
|
91
|
+
specification_version: 4
|
92
|
+
summary: A simple and straightforward settings solution that uses an ERB enabled YAML
|
93
|
+
file and a singleton design pattern.
|
94
|
+
test_files:
|
95
|
+
- spec/multi_source_config.rb
|
96
|
+
- spec/override.yml
|
97
|
+
- spec/settings.rb
|
98
|
+
- spec/settings.yml
|
99
|
+
- spec/settings2.rb
|
100
|
+
- spec/settings3.rb
|
101
|
+
- spec/settings4.rb
|
102
|
+
- spec/settings_empty.rb
|
103
|
+
- spec/settings_empty.yml
|
104
|
+
- spec/settingslogic_spec.rb
|
105
|
+
- spec/spec_helper.rb
|