mc-settings 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +101 -29
- data/VERSION +1 -1
- data/lib/setting.rb +9 -3
- data/mc-settings.gemspec +3 -2
- data/spec/fixtures/joes-colors.yml +9 -0
- data/spec/fixtures/sample.yml +19 -0
- data/spec/mc_settings_spec.rb +35 -27
- metadata +5 -4
data/README.rdoc
CHANGED
@@ -1,13 +1,18 @@
|
|
1
1
|
= Application Settings Manager
|
2
2
|
|
3
|
+
== Summary
|
4
|
+
|
3
5
|
This gem provides an easy and capistrano-friendly way to manage application configuration across
|
4
6
|
multiple environments, such as development, QA, staging, production, etc.
|
5
7
|
|
6
8
|
Applications typically rely on configuration settings, such as host names, URLs, usernames and many
|
7
|
-
more. Some change between environemnts, some do not. This gem
|
8
|
-
|
9
|
+
more. Some change between environemnts, some do not. This gem assumes that application configuration
|
10
|
+
is represented by a Hash of arbitrary depth, and provides convenient and compact syntax to access the
|
11
|
+
settings through a singleton instance inside Setting class.
|
9
12
|
|
10
|
-
Configuration is stored in
|
13
|
+
Configuration is stored in one or more YAML files with the top-level data structure being a Hash,
|
14
|
+
with keys being the names of individual settings. For example, consider the following sample
|
15
|
+
application configuration file:
|
11
16
|
|
12
17
|
tax:
|
13
18
|
default: 0.0
|
@@ -22,55 +27,122 @@ Configuration is stored in YAML files, in the following format, with it's top le
|
|
22
27
|
- 'NY'
|
23
28
|
math_pi: 3.14159526
|
24
29
|
|
25
|
-
|
30
|
+
Setting Gem provides Setting.load(..) method to load configuration from files in a way that allows
|
31
|
+
some configuration files to override previously loaded values, and then offers a simple method API
|
32
|
+
to access the values, for example Setting.tax(:california) or Setting.tax. Supporting default values
|
33
|
+
in 2nd, 3rd, etc.. -level hashes is one of the advantages of using this gem.
|
34
|
+
|
35
|
+
By loading configuration from files, Setting is inherently compatible with Capistrano deployment
|
36
|
+
methodology, where a certain set of files may become "activated" by simply sym-linking them into
|
37
|
+
the appropriate settings folder.
|
38
|
+
|
39
|
+
Note: using example above, "1st level" hash is the one with keys "tax", "states" and "math_pi".
|
40
|
+
2nd-level hash is, for example, the tax definition one, with keys "default" and "california".
|
26
41
|
|
27
|
-
== Usage
|
42
|
+
== Usage in Code
|
28
43
|
|
29
|
-
Once
|
44
|
+
Once configuration is initialized using Setting#load or Setting#reload methods (see below), they can be used in
|
45
|
+
code in the following way:
|
30
46
|
|
31
|
-
* Setting.key_name is optimized to return default value if available.
|
32
|
-
* Setting.key_name(:sub_key_name) returns value from the 2nd level hash
|
33
|
-
* Setting
|
47
|
+
* Setting.key_name is optimized to return default value if available instead of a Hash.
|
48
|
+
* Setting.key_name(:sub_key_name) returns a value from the 2nd level hash.
|
49
|
+
* Setting.key_name(:sub_key_name, :sub_sub_key_name) returns value from the 3rd level hash if available. The algorithm is recursive, so only the maximum method stack depth will limit the number of nested hash values you can access this way.
|
50
|
+
* Special syntax Setting[:key_name], Setting[:key_name][:sub_key_name], etc also supported. This method, however, does not support default values (see below).
|
34
51
|
|
35
|
-
|
52
|
+
Method notation is recommended over square bracket notation for acessing single values. However, square bracket notation
|
53
|
+
may be useful when you want to fetch the entire 2nd level hash that includes the default value, instead of the
|
54
|
+
default value itself.
|
55
|
+
|
56
|
+
For example, given the above YAML file, you can access the settings in your code as follows:
|
36
57
|
|
37
58
|
Setting.tax => 0.0
|
38
59
|
Setting.tax(:california) => 7.5
|
39
|
-
Setting
|
60
|
+
Setting.math_pi => 3.14159526
|
61
|
+
Setting[:math_pi] => 3.14159526
|
40
62
|
Setting.states => [ 'CA', 'WA', 'NY' ]
|
41
63
|
Setting.states['ship_to'] => [ 'CA', 'NY' ]
|
42
64
|
|
43
|
-
|
44
|
-
|
65
|
+
Method calling notation allows passing an array of keys for nested hashes. It also supports default values
|
66
|
+
if provided.
|
67
|
+
|
68
|
+
Setting.tax => 0.0
|
69
|
+
|
70
|
+
Square bracket syntax returns the actual 2nd-level hash, without any regard for a default value:
|
45
71
|
|
46
|
-
Setting
|
47
|
-
Setting.available_settings['key_name']['sub_key_name']
|
72
|
+
Setting[:tax] => { 'default' => 0.0, 'california' => 7.5 }
|
48
73
|
|
49
|
-
== Settings
|
74
|
+
== Loading Settings
|
50
75
|
|
51
|
-
|
52
|
-
application initialization block.
|
76
|
+
The gem should be initialized in your environment.rb (if using Rails), or in any other
|
77
|
+
application initialization block. Setting.load() method is provided for loading settings, and it
|
78
|
+
can be called only once in application lifecycle, or it will throw an exception. If you need to reload
|
79
|
+
settings completely, you can use reload() method with similar arguments.
|
53
80
|
|
54
81
|
Consider an example:
|
55
82
|
|
56
|
-
Setting.load(:
|
57
|
-
:
|
83
|
+
Setting.load(:path => "#{Rails.root}/config/settings",
|
84
|
+
:files => ["default.yml", "environments/#{Rails.env}.yml"],
|
58
85
|
:local => true)
|
59
86
|
|
60
|
-
|
61
|
-
|
62
|
-
|
87
|
+
The argument is a parameter hash that configures which YML files to load, and in what order, and from where.
|
88
|
+
|
89
|
+
* :path specifies the "root" folder where settings files will be loaded from
|
90
|
+
* :files is an array that lists file names relative to the :path. In the example above, settings folder contains subfolder "environments" where Rails-specific environment files are located (such as "development.yml", "staging.yml", "production.yml", etc)
|
91
|
+
* :local can be optionally specified as a true value, and if specified Setting gem will load all *.yml files that live under the :path/local folder.
|
92
|
+
|
93
|
+
Below is list of YML files loaded in order specified in the above example, assuming that "development" is
|
94
|
+
the Rails environment, and "local" folder exists with 3 additional YML files in it:
|
63
95
|
|
64
96
|
config/settings/default.yml
|
65
97
|
config/settings/environments/development.yml
|
66
|
-
config/settings/local/
|
67
|
-
config/settings/local/
|
98
|
+
config/settings/local/authorize-net.yml
|
99
|
+
config/settings/local/paypal.yml
|
100
|
+
config/settings/local/other.yml
|
101
|
+
|
102
|
+
Each YML file defines a ruby Hash. During file loading, the hashes are merged, so that values loaded in early files may
|
103
|
+
be overwritten by values in subsequent files. This is deliberate and by design: it allows you to create
|
104
|
+
small "override" files for each environment, or even each machine you want to deploy to. Exactly how you split your
|
105
|
+
application settings in files is up to you.
|
106
|
+
|
107
|
+
== Nested Hashes and Default Values
|
108
|
+
|
109
|
+
MC Setting gem provides a convenient way to access nested values, including full support for the default values within
|
110
|
+
nested hashes (as of 0.1.1).
|
111
|
+
|
112
|
+
Consider the following nested hash example:
|
113
|
+
|
114
|
+
default.yml:
|
115
|
+
|
116
|
+
services:
|
117
|
+
inventory:
|
118
|
+
url: http://ims.mycompany.com:3443/inventory_manager
|
119
|
+
name: Inventory Management
|
120
|
+
shipping:
|
121
|
+
url: http://ship.mycompany.com:3443/shipper
|
122
|
+
name: Shipping
|
123
|
+
|
124
|
+
Setting.load(:files => ['default.yml'], :path => ...)
|
125
|
+
|
126
|
+
Setting.tax(:inventory) => { :url => "http://localhost:3443/inventory_manager" :name => "Inventory Management"}
|
127
|
+
Setting.tax(:inventory, :url) => "http://localhost:3443/inventory_manager"
|
128
|
+
|
129
|
+
staging.yml is changing URLs for services so they work in the staging environment. Service URLs have been changed for
|
130
|
+
staging only:
|
131
|
+
|
132
|
+
services:
|
133
|
+
inventory:
|
134
|
+
url: http://localhost:8009/inventory_manager
|
135
|
+
shipping:
|
136
|
+
url: http://localhost:8008/shipper
|
137
|
+
|
138
|
+
Setting.load(:files => ['default.yml', 'staging.yml'], :path => ...)
|
139
|
+
|
140
|
+
Setting.tax(:inventory) => { :url => "http://localhost:8009/inventory_manager" :name => "Inventory Management"}
|
141
|
+
Setting.tax(:inventory, :url) => "http://localhost:8008/inventory_manager"
|
68
142
|
|
69
|
-
|
143
|
+
== Capistrano Recommendations
|
70
144
|
|
71
|
-
|
72
|
-
* Last file loaded overrides recursively previous value (if already exist).
|
73
|
-
* Load all #{path}/local/*.yml files to Settings, overriding recursively common keys. Files are loaded in order sorted by name.
|
145
|
+
TBD.
|
74
146
|
|
75
147
|
== Copyright
|
76
148
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/lib/setting.rb
CHANGED
@@ -111,7 +111,7 @@ class Setting
|
|
111
111
|
if block_given?
|
112
112
|
v = yield(v, args)
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
if v.is_a?(Fixnum) && bool
|
116
116
|
v.to_i > 0
|
117
117
|
else
|
@@ -123,7 +123,7 @@ class Setting
|
|
123
123
|
# contains 'default' value, or just 1 element.
|
124
124
|
|
125
125
|
def collapse_hashes(v, args)
|
126
|
-
if v.is_a?(Hash)
|
126
|
+
out = if v.is_a?(Hash)
|
127
127
|
if args.empty?
|
128
128
|
if v.has_key?("default")
|
129
129
|
v['default'].nil? ? "" : v['default']
|
@@ -133,11 +133,17 @@ class Setting
|
|
133
133
|
v
|
134
134
|
end
|
135
135
|
else
|
136
|
-
v[args
|
136
|
+
v[args.shift.to_s]
|
137
137
|
end
|
138
138
|
else
|
139
139
|
v
|
140
140
|
end
|
141
|
+
|
142
|
+
if out.is_a?(Hash)
|
143
|
+
collapse_hashes(out, args)
|
144
|
+
else
|
145
|
+
out
|
146
|
+
end
|
141
147
|
end
|
142
148
|
|
143
149
|
def loaded?
|
data/mc-settings.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mc-settings}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Edwin Cruz", "Colin Shield"]
|
12
|
-
s.date = %q{2011-01-
|
12
|
+
s.date = %q{2011-01-18}
|
13
13
|
s.description = %q{implement custom keys indenendently of environment}
|
14
14
|
s.email = %q{rubydev@modcloth.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
"lib/mc-settings.rb",
|
28
28
|
"lib/setting.rb",
|
29
29
|
"mc-settings.gemspec",
|
30
|
+
"spec/fixtures/joes-colors.yml",
|
30
31
|
"spec/fixtures/sample.yml",
|
31
32
|
"spec/mc_settings_spec.rb",
|
32
33
|
"spec/spec_helper.rb",
|
data/spec/fixtures/sample.yml
CHANGED
@@ -14,3 +14,22 @@ boolean_true:
|
|
14
14
|
boolean_false:
|
15
15
|
default: false
|
16
16
|
negated: true
|
17
|
+
color:
|
18
|
+
default:
|
19
|
+
:grey
|
20
|
+
pants:
|
21
|
+
default:
|
22
|
+
:purple
|
23
|
+
favorite:
|
24
|
+
:red
|
25
|
+
school:
|
26
|
+
:blue
|
27
|
+
shorts:
|
28
|
+
default:
|
29
|
+
:plaid
|
30
|
+
favorite:
|
31
|
+
:yellow
|
32
|
+
school:
|
33
|
+
:black
|
34
|
+
|
35
|
+
|
data/spec/mc_settings_spec.rb
CHANGED
@@ -6,8 +6,8 @@ describe Setting do
|
|
6
6
|
before :each do
|
7
7
|
stub_setting_files
|
8
8
|
Setting.reload(
|
9
|
-
:files => ["default.yml", "environments/test.yml"],
|
10
9
|
:path => "config/settings",
|
10
|
+
:files => ["default.yml", "environments/test.yml"],
|
11
11
|
:local => true)
|
12
12
|
end
|
13
13
|
|
@@ -22,15 +22,11 @@ describe Setting do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
it "handles multiple values" do
|
25
|
-
Setting[
|
25
|
+
Setting[:six].should == {"default"=>"default value", "extra"=>"recursively overriden", "deep_level"=>{"value"=>"even deeper level"}}
|
26
26
|
Setting.available_settings['six']['default'].should == "default value"
|
27
27
|
Setting.seven.should == "seven from custom"
|
28
28
|
end
|
29
29
|
|
30
|
-
it "should support symbols as keys" do
|
31
|
-
Setting[:six].should == {"default"=>"default value", "extra"=>"recursively overriden"}
|
32
|
-
end
|
33
|
-
|
34
30
|
it "handles default key" do
|
35
31
|
Setting.default_setting.should == 1
|
36
32
|
Setting['seven']['default'].should == "seven from custom"
|
@@ -50,7 +46,7 @@ describe Setting do
|
|
50
46
|
|
51
47
|
it "should merge keys recursivelly" do
|
52
48
|
Setting.six(:extra).should == "recursively overriden"
|
53
|
-
Setting.six(:deep_level
|
49
|
+
Setting.six(:deep_level, :value).should == "even deeper level"
|
54
50
|
end
|
55
51
|
|
56
52
|
it "should create keys if it does not exist" do
|
@@ -62,45 +58,35 @@ describe Setting do
|
|
62
58
|
it "should keep its values" do
|
63
59
|
3.times do |time|
|
64
60
|
Thread.new {
|
65
|
-
|
66
|
-
Setting.available_settings.shoud_not be_empty
|
67
|
-
}
|
61
|
+
Setting.available_settings.shoud_not be_empty
|
68
62
|
}
|
69
63
|
end
|
70
64
|
end
|
71
65
|
end
|
72
66
|
|
73
|
-
context "When running inside a proc" do
|
74
|
-
it "should keep its values" do
|
75
|
-
Proc.new{
|
76
|
-
Setting.available_settings.shoud_not be_empty
|
77
|
-
}
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
67
|
context "Test from file" do
|
82
68
|
before :each do
|
83
69
|
Setting.reload(
|
84
|
-
|
85
|
-
|
70
|
+
:path => File.join(File.dirname(__FILE__)) + '/fixtures',
|
71
|
+
:files => ['sample.yml']
|
86
72
|
)
|
87
73
|
end
|
88
74
|
|
89
75
|
it 'should support [] syntax' do
|
90
76
|
Setting['tax']['default'].should == 0.0
|
91
|
-
Setting['tax'].should == {'default' => 0.0, 'california' => 7.5}
|
77
|
+
Setting['tax'].should == { 'default' => 0.0, 'california' => 7.5 }
|
92
78
|
end
|
93
79
|
|
94
80
|
it 'should support method invocation syntax' do
|
95
81
|
Setting.tax.should == 0.0
|
96
82
|
|
97
|
-
Setting.tax(:default).should
|
98
|
-
Setting.tax('default').should
|
99
|
-
Setting.tax(:california).should
|
83
|
+
Setting.tax(:default).should == Setting.tax
|
84
|
+
Setting.tax('default').should == Setting.tax
|
85
|
+
Setting.tax(:california).should == 7.5
|
100
86
|
|
101
|
-
Setting.states.should
|
102
|
-
Setting.states(:default).should
|
103
|
-
Setting.states(:ship_to).should
|
87
|
+
Setting.states.should == ['CA', 'WA', 'NY']
|
88
|
+
Setting.states(:default).should == Setting.states
|
89
|
+
Setting.states(:ship_to).should == ['CA', 'NY']
|
104
90
|
end
|
105
91
|
|
106
92
|
it 'should correctly process Boolean values' do
|
@@ -110,6 +96,28 @@ describe Setting do
|
|
110
96
|
Setting.boolean_false?(:default).should be(false)
|
111
97
|
Setting.boolean_false?(:negated).should be(true)
|
112
98
|
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "Test recursive overrides and nested hashes" do
|
102
|
+
before :each do
|
103
|
+
Setting.reload(
|
104
|
+
:path => File.join(File.dirname(__FILE__)) + '/fixtures',
|
105
|
+
:files => ['sample.yml', 'joes-colors.yml']
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should override colors with Joes and support nested hashes' do
|
110
|
+
Setting.color.should == :grey # default
|
111
|
+
Setting.color(:pants).should == :purple # default
|
112
|
+
|
113
|
+
Setting.color(:pants, :school).should == :blue # in sample
|
114
|
+
Setting.color(:pants, :favorite).should == :orange # joes override
|
115
|
+
|
116
|
+
Setting.color(:shorts, :school).should == :black # in sample
|
117
|
+
Setting.color(:shorts, :favorite).should == :white # joe's override
|
118
|
+
|
119
|
+
Setting.color(:shorts).should == :stripes # joe's override of default
|
120
|
+
end
|
113
121
|
|
114
122
|
end
|
115
123
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mc-settings
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Edwin Cruz
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-01-
|
19
|
+
date: 2011-01-18 00:00:00 -08:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -113,6 +113,7 @@ files:
|
|
113
113
|
- lib/mc-settings.rb
|
114
114
|
- lib/setting.rb
|
115
115
|
- mc-settings.gemspec
|
116
|
+
- spec/fixtures/joes-colors.yml
|
116
117
|
- spec/fixtures/sample.yml
|
117
118
|
- spec/mc_settings_spec.rb
|
118
119
|
- spec/spec_helper.rb
|