runcoderun-configatron 2.2.1.1
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.
- data/README +132 -0
- data/lib/configatron/configatron.rb +54 -0
- data/lib/configatron/errors.rb +13 -0
- data/lib/configatron/kernel.rb +8 -0
- data/lib/configatron/store.rb +255 -0
- data/lib/configatron.rb +7 -0
- data/spec/lib/configatron_spec.rb +449 -0
- data/spec/lib/futurama.yml +6 -0
- data/spec/lib/lost.yml +14 -0
- data/spec/lib/the_wire.yml +5 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +4 -0
- metadata +72 -0
data/README
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
=Configatron
|
2
|
+
|
3
|
+
Configatron makes configuring your applications and scripts incredibly easy. No longer is a there a need to use constants or global variables. Now you can use a simple and painless system to configure your life. And, because it's all Ruby, you can do any crazy thing you would like to!
|
4
|
+
|
5
|
+
==Examples
|
6
|
+
|
7
|
+
===Simple
|
8
|
+
configatron.email = 'me@example.com'
|
9
|
+
configatron.database_url = "postgres://localhost/mack_framework_rocks"
|
10
|
+
|
11
|
+
Now, anywhere in your code you can do the following:
|
12
|
+
|
13
|
+
configatron.email # => "me@example.com"
|
14
|
+
configatron.database_url # => "postgres://localhost/mack_framework_rocks"
|
15
|
+
|
16
|
+
Viola! Simple as can be.
|
17
|
+
|
18
|
+
Now you're saying, what if I want to have a 'default' set of options, but then override them later, based on other information? Simple again. Let's use our above example. We've configured our 'database_url' option to be "postgres://localhost/mack_framework_rocks". The problem with that is that is our production database url, not our development url. Fair enough, all you have to do is redeclare it:
|
19
|
+
|
20
|
+
configatron.database_url = "postgres://localhost/mack_framework_rocks_development"
|
21
|
+
|
22
|
+
|
23
|
+
becomes:
|
24
|
+
|
25
|
+
configatron.email # => "me@example.com"
|
26
|
+
configatron.database_url # => "postgres://localhost/mack_framework_rocks_development"
|
27
|
+
|
28
|
+
Notice how our other configuration parameters haven't changed? Cool, eh?
|
29
|
+
|
30
|
+
===Hash/YAML
|
31
|
+
You can configure configatron from a hash as well:
|
32
|
+
|
33
|
+
configatron.configure_from_hash({:email => {:pop => {:address => 'pop.example.com', :port => 110}}, :smtp => {:address => 'smtp.example.com'}})
|
34
|
+
|
35
|
+
configatron.email.pop.address # => 'pop.example.com'
|
36
|
+
configatron.email.pop.port # => 110
|
37
|
+
# and so on...
|
38
|
+
|
39
|
+
Notice how they're all namespaced for your as well. The same holds true for YAML files:
|
40
|
+
|
41
|
+
configuration.configure_from_yaml('/path/to/file.yml')
|
42
|
+
|
43
|
+
When the 'reload' method is called on configatron then the YAML file will be re-read in case changes have been made.
|
44
|
+
|
45
|
+
===Namespaces
|
46
|
+
|
47
|
+
The question that should be on your lips is what I need to have namespaced configuration parameters. It's easy! Configatron allows you to create namespaces.
|
48
|
+
|
49
|
+
configatron.website_url = "http://www.mackframework.com"
|
50
|
+
configatron.email.pop.address = "pop.example.com"
|
51
|
+
configatron.email.pop.port = 110
|
52
|
+
configatron.email.smtp.address = "smtp.example.com"
|
53
|
+
configatron.email.smtp.port = 25
|
54
|
+
|
55
|
+
becomes:
|
56
|
+
|
57
|
+
configatron.email.pop.address # => "pop.example.com"
|
58
|
+
configatron.email.smtp.address # => "smtp.example.com"
|
59
|
+
configatron.website_url # => "http://www.mackframework.com"
|
60
|
+
|
61
|
+
Configatron allows you to nest namespaces to your hearts content! Just keep going, it's that easy.
|
62
|
+
|
63
|
+
Of course you can update a single parameter n levels deep as well:
|
64
|
+
|
65
|
+
configatron.email.pop.address = "pop2.example.com"
|
66
|
+
|
67
|
+
configatron.email.pop.address # => "pop2.example.com"
|
68
|
+
configatron.email.smtp.address # => "smtp.example.com"
|
69
|
+
|
70
|
+
===Misc.
|
71
|
+
|
72
|
+
Even if parameters haven't been set, you can still call them, and you'll get nil back:
|
73
|
+
|
74
|
+
configatron.i.dont.exist.nil? # => true
|
75
|
+
configatron.i.dont.exist # => nil
|
76
|
+
|
77
|
+
You can set 'default' values for parameters. If there is already a setting, it won't be replaced. This is useful if you've already done your 'configuration' and you call a library, that needs to have parameters set. The library can set it's defaults, without worrying that it might have overridden your custom settings.
|
78
|
+
|
79
|
+
configatron.set_default(:name, 'Mark Bates')
|
80
|
+
configatron.name # => 'Mark Bates'
|
81
|
+
configatron.set_default(:name, 'Me')
|
82
|
+
configatron.name # => 'Mark Bates'
|
83
|
+
|
84
|
+
Sometimes in testing, or other situations, you want to temporarily change some settings. You can do this with the <tt>temp</tt> method:
|
85
|
+
|
86
|
+
configatron.one = 1
|
87
|
+
configatron.letters.a = 'A'
|
88
|
+
configatron.letters.b = 'B'
|
89
|
+
configatron.temp do
|
90
|
+
configatron.letters.b = 'bb'
|
91
|
+
configatron.letters.c = 'c'
|
92
|
+
configatron.one # => 1
|
93
|
+
configatron.letters.a # => 'A'
|
94
|
+
configatron.letters.b # => 'bb'
|
95
|
+
configatron.letters.c # => 'c'
|
96
|
+
end
|
97
|
+
configatron.one # => 1
|
98
|
+
configatron.letters.a # => 'A'
|
99
|
+
configatron.letters.b # => 'B'
|
100
|
+
configatron.letters.c # => nil
|
101
|
+
|
102
|
+
You can also pass in an optional Hash to the <tt>temp</tt>:
|
103
|
+
|
104
|
+
configatron.one = 1
|
105
|
+
configatron.letters.a = 'A'
|
106
|
+
configatron.letters.b = 'B'
|
107
|
+
configatron.temp(:letters => {:b => 'bb', :c => 'c'}) do
|
108
|
+
configatron.one == 1
|
109
|
+
configatron.letters.a # => 'A'
|
110
|
+
configatron.letters.b # => 'bb'
|
111
|
+
configatron.letters.c # => 'c'
|
112
|
+
end
|
113
|
+
configatron.one == 1
|
114
|
+
configatron.letters.a # => 'A'
|
115
|
+
configatron.letters.b # => 'B'
|
116
|
+
configatron.letters.c # => nil
|
117
|
+
|
118
|
+
Enjoy!
|
119
|
+
|
120
|
+
==Contact
|
121
|
+
Please mail bugs, suggestions and patches to <bugs@mackframework.com>.
|
122
|
+
|
123
|
+
On the web at: http://www.mackframework.com
|
124
|
+
|
125
|
+
==License and Copyright
|
126
|
+
Copyright (C) 2008 Mark Bates, http://www.mackframework.com
|
127
|
+
|
128
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
129
|
+
|
130
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
131
|
+
|
132
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
class Configatron
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
alias_method :send!, :send
|
7
|
+
|
8
|
+
def initialize # :nodoc:
|
9
|
+
@_namespace = [:default]
|
10
|
+
reset!
|
11
|
+
end
|
12
|
+
|
13
|
+
# Forwards the method call onto the 'namespaced' Configatron::Store
|
14
|
+
def method_missing(sym, *args)
|
15
|
+
@_store[@_namespace.last].send(sym, *args)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Removes ALL configuration parameters
|
19
|
+
def reset!
|
20
|
+
@_store = {:default => Configatron::Store.new}
|
21
|
+
end
|
22
|
+
|
23
|
+
# Allows for the temporary overriding of parameters in a block.
|
24
|
+
# Takes an optional Hash of parameters that will be applied before
|
25
|
+
# the block gets called. At the end of the block, the temporary
|
26
|
+
# settings are deleted and the original settings are reinstated.
|
27
|
+
def temp(options = nil)
|
28
|
+
begin
|
29
|
+
temp_start(options)
|
30
|
+
yield
|
31
|
+
rescue Exception => e
|
32
|
+
raise e
|
33
|
+
ensure
|
34
|
+
temp_end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def temp_start(options = nil)
|
39
|
+
n_space = rand
|
40
|
+
@_store[n_space] = @_store[@_namespace.last].deep_clone
|
41
|
+
@_namespace << n_space
|
42
|
+
if options
|
43
|
+
self.method_missing(:configure_from_hash, options)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def temp_end
|
48
|
+
@_store.delete(@_namespace.pop)
|
49
|
+
end
|
50
|
+
|
51
|
+
undef :inspect # :nodoc:
|
52
|
+
undef :nil? # :nodoc:
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Configatron
|
2
|
+
class ProtectedParameter < StandardError
|
3
|
+
def intialize(name)
|
4
|
+
super("Can not modify protected parameter: '#{name}'")
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class LockedNamespace < StandardError
|
9
|
+
def initialize(name)
|
10
|
+
super("Cannot add new parameters to locked namespace: #{name.inspect}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
class Configatron
|
2
|
+
class Store
|
3
|
+
alias_method :send!, :send
|
4
|
+
|
5
|
+
# Takes an optional Hash of parameters
|
6
|
+
def initialize(options = {}, name = nil, parent = nil)
|
7
|
+
@_name = name
|
8
|
+
@_parent = parent
|
9
|
+
@_store = {}
|
10
|
+
configure_from_hash(options)
|
11
|
+
@_protected = []
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns a Hash representing the configurations
|
15
|
+
def to_hash
|
16
|
+
@_store
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
path = [@_name]
|
21
|
+
parent = @_parent
|
22
|
+
until parent.nil?
|
23
|
+
path << parent.instance_variable_get('@_name')
|
24
|
+
parent = parent.instance_variable_get('@_parent')
|
25
|
+
end
|
26
|
+
path << 'configatron'
|
27
|
+
path.compact!
|
28
|
+
path.reverse!
|
29
|
+
f_out = []
|
30
|
+
@_store.each do |k, v|
|
31
|
+
if v.is_a?(Configatron::Store)
|
32
|
+
v.inspect.each_line do |line|
|
33
|
+
if line.match(/\n/)
|
34
|
+
line.each_line do |l|
|
35
|
+
l.strip!
|
36
|
+
f_out << l
|
37
|
+
end
|
38
|
+
else
|
39
|
+
line.strip!
|
40
|
+
f_out << line
|
41
|
+
end
|
42
|
+
end
|
43
|
+
else
|
44
|
+
f_out << "#{path.join('.')}.#{k} = #{v.inspect}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
f_out.compact.sort.join("\n")
|
48
|
+
end
|
49
|
+
|
50
|
+
# Allows for the configuration of the system via a Hash
|
51
|
+
def configure_from_hash(options)
|
52
|
+
parse_options(options)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Allows for the configuration of the system from a YAML file.
|
56
|
+
# Takes the path to the YAML file. Also takes an optional parameter,
|
57
|
+
# <tt>:hash</tt>, that indicates a specific hash that should be
|
58
|
+
# loaded from the file.
|
59
|
+
def configure_from_yaml(path, opts = {})
|
60
|
+
begin
|
61
|
+
yml = YAML.load(ERB.new(File.read(path)).result)
|
62
|
+
yml = yml[opts[:hash]] unless opts[:hash].nil?
|
63
|
+
configure_from_hash(yml)
|
64
|
+
rescue Errno::ENOENT => e
|
65
|
+
puts e.message
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns true if there are no configuration parameters
|
70
|
+
def nil?
|
71
|
+
return @_store.empty?
|
72
|
+
end
|
73
|
+
|
74
|
+
# Retrieves a certain parameter and if that parameter
|
75
|
+
# doesn't exist it will return the default_value specified.
|
76
|
+
def retrieve(name, default_value = nil)
|
77
|
+
@_store[name.to_sym] || default_value
|
78
|
+
end
|
79
|
+
|
80
|
+
# Removes a parameter. In the case of a nested parameter
|
81
|
+
# it will remove all below it.
|
82
|
+
def remove(name)
|
83
|
+
@_store.delete(name.to_sym)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Sets a 'default' value. If there is already a value specified
|
87
|
+
# it won't set the value.
|
88
|
+
def set_default(name, default_value)
|
89
|
+
unless @_store[name.to_sym]
|
90
|
+
@_store[name.to_sym] = parse_options(default_value)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def method_missing(sym, *args) # :nodoc:
|
95
|
+
if sym.to_s.match(/(.+)=$/)
|
96
|
+
name = sym.to_s.gsub("=", '').to_sym
|
97
|
+
raise Configatron::ProtectedParameter.new(name) if @_protected.include?(name) || methods_include?(name)
|
98
|
+
raise Configatron::LockedNamespace.new(@_name) if @_locked && !@_store.has_key?(name)
|
99
|
+
@_store[name] = parse_options(*args)
|
100
|
+
elsif @_store.has_key?(sym)
|
101
|
+
return @_store[sym]
|
102
|
+
else
|
103
|
+
store = Configatron::Store.new({}, sym, self)
|
104
|
+
@_store[sym] = store
|
105
|
+
return store
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def ==(other) # :nodoc:
|
110
|
+
self.to_hash == other
|
111
|
+
end
|
112
|
+
|
113
|
+
# Prevents a parameter from being reassigned. If called on a 'namespace' then
|
114
|
+
# all parameters below it will be protected as well.
|
115
|
+
def protect(name)
|
116
|
+
@_protected << name.to_sym
|
117
|
+
end
|
118
|
+
|
119
|
+
# Prevents all parameters from being reassigned.
|
120
|
+
def protect_all!
|
121
|
+
@_protected.clear
|
122
|
+
@_store.keys.each do |k|
|
123
|
+
val = self.send(k)
|
124
|
+
val.protect_all! if val.class == Configatron::Store
|
125
|
+
@_protected << k
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Removes the protection of a parameter.
|
130
|
+
def unprotect(name)
|
131
|
+
@_protected.reject! { |e| e == name.to_sym }
|
132
|
+
end
|
133
|
+
|
134
|
+
def unprotect_all!
|
135
|
+
@_protected.clear
|
136
|
+
@_store.keys.each do |k|
|
137
|
+
val = self.send(k)
|
138
|
+
val.unprotect_all! if val.class == Configatron::Store
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Prevents a namespace from having new parameters set. The lock is applied
|
143
|
+
# recursively to any namespaces below it.
|
144
|
+
def lock(name)
|
145
|
+
namespace = @_store[name.to_sym]
|
146
|
+
raise ArgumentError, "Namespace #{name.inspect} does not exist" if namespace.nil?
|
147
|
+
namespace.lock!
|
148
|
+
end
|
149
|
+
|
150
|
+
def unlock(name)
|
151
|
+
namespace = @_store[name.to_sym]
|
152
|
+
raise ArgumentError, "Namespace #{name.inspect} does not exist" if namespace.nil?
|
153
|
+
namespace.unlock!
|
154
|
+
end
|
155
|
+
|
156
|
+
# = DeepClone
|
157
|
+
#
|
158
|
+
# == Version
|
159
|
+
# 1.2006.05.23 (change of the first number means Big Change)
|
160
|
+
#
|
161
|
+
# == Description
|
162
|
+
# Adds deep_clone method to an object which produces deep copy of it. It means
|
163
|
+
# if you clone a Hash, every nested items and their nested items will be cloned.
|
164
|
+
# Moreover deep_clone checks if the object is already cloned to prevent endless recursion.
|
165
|
+
#
|
166
|
+
# == Usage
|
167
|
+
#
|
168
|
+
# (see examples directory under the ruby gems root directory)
|
169
|
+
#
|
170
|
+
# require 'rubygems'
|
171
|
+
# require 'deep_clone'
|
172
|
+
#
|
173
|
+
# include DeepClone
|
174
|
+
#
|
175
|
+
# obj = []
|
176
|
+
# a = [ true, false, obj ]
|
177
|
+
# b = a.deep_clone
|
178
|
+
# obj.push( 'foo' )
|
179
|
+
# p obj # >> [ 'foo' ]
|
180
|
+
# p b[2] # >> []
|
181
|
+
#
|
182
|
+
# == Source
|
183
|
+
# http://simplypowerful.1984.cz/goodlibs/1.2006.05.23
|
184
|
+
#
|
185
|
+
# == Author
|
186
|
+
# jan molic (/mig/at_sign/1984/dot/cz/)
|
187
|
+
#
|
188
|
+
# == Licence
|
189
|
+
# You can redistribute it and/or modify it under the same terms of Ruby's license;
|
190
|
+
# either the dual license version in 2003, or any later version.
|
191
|
+
#
|
192
|
+
def deep_clone( obj=self, cloned={} )
|
193
|
+
if cloned.has_key?( obj.object_id )
|
194
|
+
return cloned[obj.object_id]
|
195
|
+
else
|
196
|
+
begin
|
197
|
+
cl = obj.clone
|
198
|
+
rescue Exception
|
199
|
+
# unclonnable (TrueClass, Fixnum, ...)
|
200
|
+
cloned[obj.object_id] = obj
|
201
|
+
return obj
|
202
|
+
else
|
203
|
+
cloned[obj.object_id] = cl
|
204
|
+
cloned[cl.object_id] = cl
|
205
|
+
if cl.is_a?( Hash )
|
206
|
+
cl.clone.each { |k,v|
|
207
|
+
cl[k] = deep_clone( v, cloned )
|
208
|
+
}
|
209
|
+
elsif cl.is_a?( Array )
|
210
|
+
cl.collect! { |v|
|
211
|
+
deep_clone( v, cloned )
|
212
|
+
}
|
213
|
+
end
|
214
|
+
cl.instance_variables.each do |var|
|
215
|
+
v = cl.instance_eval( var.to_s )
|
216
|
+
v_cl = deep_clone( v, cloned )
|
217
|
+
cl.instance_eval( "#{var} = v_cl" )
|
218
|
+
end
|
219
|
+
return cl
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
protected
|
225
|
+
def lock!
|
226
|
+
@_locked = true
|
227
|
+
@_store.values.each { |store| store.lock! if store.is_a?(Configatron::Store) }
|
228
|
+
end
|
229
|
+
|
230
|
+
def unlock!
|
231
|
+
@_locked = false
|
232
|
+
@_store.values.each { |store| store.unlock! if store.is_a?(Configatron::Store) }
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
def methods_include?(name)
|
237
|
+
self.methods.include?(RUBY_VERSION > '1.9.0' ? name.to_sym : name.to_s)
|
238
|
+
end
|
239
|
+
|
240
|
+
def parse_options(options)
|
241
|
+
if options.is_a?(Hash)
|
242
|
+
options.each do |k,v|
|
243
|
+
if v.is_a?(Hash)
|
244
|
+
self.method_missing(k.to_sym).configure_from_hash(v)
|
245
|
+
else
|
246
|
+
self.method_missing("#{k.to_sym}=", v)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
else
|
250
|
+
return options
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
end
|
data/lib/configatron.rb
ADDED
@@ -0,0 +1,449 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe "configatron" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
configatron.reset!
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'protect' do
|
10
|
+
|
11
|
+
it 'should protect a parameter and prevent it from being set' do
|
12
|
+
configatron.one = 1
|
13
|
+
configatron.protect(:one)
|
14
|
+
lambda{configatron.one = 'one'}.should raise_error(Configatron::ProtectedParameter)
|
15
|
+
configatron.one.should == 1
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should protect basic methods' do
|
19
|
+
lambda{configatron.object_id = 123456}.should raise_error(Configatron::ProtectedParameter)
|
20
|
+
lambda{configatron.foo.object_id = 123456}.should raise_error(Configatron::ProtectedParameter)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should work with nested parameters' do
|
24
|
+
configatron.one = 1
|
25
|
+
configatron.letters.a = 'A'
|
26
|
+
configatron.letters.b = 'B'
|
27
|
+
configatron.letters.protect(:a)
|
28
|
+
lambda{configatron.letters.a = 'a'}.should raise_error(Configatron::ProtectedParameter)
|
29
|
+
configatron.letters.a.should == 'A'
|
30
|
+
configatron.protect(:letters)
|
31
|
+
lambda{configatron.letters.a = 'a'}.should raise_error(Configatron::ProtectedParameter)
|
32
|
+
lambda{configatron.letters = 'letter'}.should raise_error(Configatron::ProtectedParameter)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should work with configure_from_hash' do
|
36
|
+
configatron.one = 1
|
37
|
+
configatron.letters.a = 'A'
|
38
|
+
configatron.letters.b = 'B'
|
39
|
+
configatron.letters.protect(:a)
|
40
|
+
lambda{configatron.configure_from_hash(:letters => {:a => 'a'})}.should raise_error(Configatron::ProtectedParameter)
|
41
|
+
configatron.letters.a.should == 'A'
|
42
|
+
configatron.protect(:letters)
|
43
|
+
lambda{configatron.letters.configure_from_hash(:a => 'a')}.should raise_error(Configatron::ProtectedParameter)
|
44
|
+
lambda{configatron.configure_from_hash(:letters => 'letters')}.should raise_error(Configatron::ProtectedParameter)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be able to protect all parameters at once" do
|
48
|
+
configatron.one = 1
|
49
|
+
configatron.letters.a = 'A'
|
50
|
+
configatron.letters.b = 'B'
|
51
|
+
configatron.protect_all!
|
52
|
+
[:a,:b].each do |l|
|
53
|
+
lambda{configatron.configure_from_hash(:letters => {l => l.to_s})}.should raise_error(Configatron::ProtectedParameter)
|
54
|
+
configatron.letters.send(l).should == l.to_s.upcase
|
55
|
+
end
|
56
|
+
lambda{configatron.letters.configure_from_hash(:a => 'a')}.should raise_error(Configatron::ProtectedParameter)
|
57
|
+
lambda{configatron.configure_from_hash(:letters => 'letters')}.should raise_error(Configatron::ProtectedParameter)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should be able to unprotect a parameter" do
|
61
|
+
configatron.one = 1
|
62
|
+
configatron.protect(:one)
|
63
|
+
configatron.unprotect(:one)
|
64
|
+
lambda{configatron.one = 2}.should_not raise_error
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should be able to unprotect all parameters at once" do
|
68
|
+
configatron.one = 1
|
69
|
+
configatron.letters.a = 'A'
|
70
|
+
configatron.letters.b = 'B'
|
71
|
+
configatron.protect_all!
|
72
|
+
configatron.unprotect_all!
|
73
|
+
lambda{configatron.one = 2}.should_not raise_error
|
74
|
+
lambda{configatron.letters.configure_from_hash(:a => 'a')}.should_not raise_error
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'lock' do
|
80
|
+
before :each do
|
81
|
+
configatron.letters.a = 'A'
|
82
|
+
configatron.letters.b = 'B'
|
83
|
+
configatron.letters.greek.alpha = 'alpha'
|
84
|
+
configatron.lock(:letters)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should allow setting of existing parameters in locked parameter' do
|
88
|
+
lambda { configatron.letters.a = 'a' }.should_not raise_error
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should not allow setting of a parameter that is not already set' do
|
92
|
+
lambda { configatron.letters.c = 'C' }.should raise_error(Configatron::LockedNamespace)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should allow setting of existing parameters in child of locked parameter' do
|
96
|
+
lambda { configatron.letters.greek.alpha = 'a' }.should_not raise_error
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should not allow setting of new parameters in child of locked parameter' do
|
100
|
+
lambda { configatron.letters.greek.beta = 'beta' }.should raise_error(Configatron::LockedNamespace)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should not affect parameters below the locked namespace' do
|
104
|
+
lambda { configatron.one = 1 }.should_not raise_error
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should raise an ArgumentError if unknown namespace is locked' do
|
108
|
+
lambda { configatron.lock(:numbers).should raise_error(ArgumentError) }
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'then unlock' do
|
112
|
+
before :each do
|
113
|
+
configatron.unlock(:letters)
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should allow setting of new parameter in unlocked namespace' do
|
117
|
+
lambda { configatron.letters.d = 'd' }.should_not raise_error
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should allow setting of new parameter in unlocked namespace\'s child' do
|
121
|
+
lambda { configatron.letters.greek.zeta = 'z' }.should_not raise_error
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should raise an ArgumentError if unknown namespace is unlocked' do
|
125
|
+
lambda { configatron.unlock(:numbers).should raise_error(ArgumentError) }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe 'temp' do
|
131
|
+
|
132
|
+
it 'should revert back to the original parameters when the block ends' do
|
133
|
+
configatron.one = 1
|
134
|
+
configatron.letters.a = 'A'
|
135
|
+
configatron.letters.b = 'B'
|
136
|
+
configatron.temp do
|
137
|
+
configatron.letters.b = 'bb'
|
138
|
+
configatron.letters.c = 'c'
|
139
|
+
configatron.one.should == 1
|
140
|
+
configatron.letters.a.should == 'A'
|
141
|
+
configatron.letters.b.should == 'bb'
|
142
|
+
configatron.letters.c.should == 'c'
|
143
|
+
end
|
144
|
+
configatron.one.should == 1
|
145
|
+
configatron.letters.a.should == 'A'
|
146
|
+
configatron.letters.b.should == 'B'
|
147
|
+
configatron.letters.c.should be_nil
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should take an optional hash of parameters' do
|
151
|
+
configatron.one = 1
|
152
|
+
configatron.letters.a = 'A'
|
153
|
+
configatron.letters.b = 'B'
|
154
|
+
configatron.temp(:letters => {:b => 'bb', :c => 'c'}) do
|
155
|
+
configatron.one.should == 1
|
156
|
+
configatron.letters.a.should == 'A'
|
157
|
+
configatron.letters.b.should == 'bb'
|
158
|
+
configatron.letters.c.should == 'c'
|
159
|
+
end
|
160
|
+
configatron.one.should == 1
|
161
|
+
configatron.letters.a.should == 'A'
|
162
|
+
configatron.letters.b.should == 'B'
|
163
|
+
configatron.letters.c.should be_nil
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should work the same as temp_start/temp_end' do
|
167
|
+
configatron.one = 1
|
168
|
+
configatron.temp_start
|
169
|
+
configatron.one = 'ONE'
|
170
|
+
configatron.one.should == 'ONE'
|
171
|
+
configatron.temp_end
|
172
|
+
configatron.one.should == 1
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'should be able to nest' do
|
176
|
+
configatron.one = 1
|
177
|
+
configatron.letters.a = 'A'
|
178
|
+
configatron.letters.b = 'B'
|
179
|
+
configatron.temp do
|
180
|
+
configatron.letters.b = 'bb'
|
181
|
+
configatron.letters.c = 'c'
|
182
|
+
configatron.one.should == 1
|
183
|
+
configatron.letters.a.should == 'A'
|
184
|
+
configatron.letters.b.should == 'bb'
|
185
|
+
configatron.letters.c.should == 'c'
|
186
|
+
configatron.temp do
|
187
|
+
configatron.letters.b = 'bbb'
|
188
|
+
configatron.one.should == 1
|
189
|
+
configatron.letters.a.should == 'A'
|
190
|
+
configatron.letters.b.should == 'bbb'
|
191
|
+
configatron.letters.c.should == 'c'
|
192
|
+
end
|
193
|
+
end
|
194
|
+
configatron.one.should == 1
|
195
|
+
configatron.letters.a.should == 'A'
|
196
|
+
configatron.letters.b.should == 'B'
|
197
|
+
configatron.letters.c.should be_nil
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
describe 'configure_from_hash' do
|
203
|
+
|
204
|
+
it 'should configure itself from a hash' do
|
205
|
+
configatron.foo.should be_nil
|
206
|
+
configatron.configure_from_hash(:foo => :bar)
|
207
|
+
configatron.foo.should == :bar
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'should handled deeply nested params' do
|
211
|
+
configatron.friends.rachel.should be_nil
|
212
|
+
configatron.configure_from_hash(:friends => {:rachel => 'Rachel Green'})
|
213
|
+
configatron.friends.rachel.should == 'Rachel Green'
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should not remove previously defined params' do
|
217
|
+
configatron.friends.rachel = 'Rachel Green'
|
218
|
+
configatron.friends.ross = 'Ross Gellar'
|
219
|
+
configatron.friends.monica = 'Monica Gellar'
|
220
|
+
configatron.configure_from_hash(:friends => {:rachel => 'R. Green', :monica => 'Monica Bing'})
|
221
|
+
configatron.friends.ross.should == 'Ross Gellar'
|
222
|
+
configatron.friends.rachel.should == 'R. Green'
|
223
|
+
configatron.friends.monica.should == 'Monica Bing'
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
|
228
|
+
describe 'configure_from_yaml' do
|
229
|
+
|
230
|
+
it 'should configure itself from a yaml file' do
|
231
|
+
configatron.futurama.should be_nil
|
232
|
+
configatron.configure_from_yaml(File.join(File.dirname(__FILE__), 'futurama.yml'))
|
233
|
+
configatron.futurama.robots.bender.should == 'Bender The Robot'
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'should not remove previously defined params' do
|
237
|
+
configatron.futurama.mutants.leela = 'Leela'
|
238
|
+
configatron.configure_from_yaml(File.join(File.dirname(__FILE__), 'futurama.yml'))
|
239
|
+
configatron.futurama.robots.bender.should == 'Bender The Robot'
|
240
|
+
configatron.futurama.mutants.leela = 'Leela'
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should fail silently if the file doesn't exist" do
|
244
|
+
lambda{configatron.configure_from_yaml('i_dont_exist.yml')}.should_not raise_error
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should be able to load a specific hash from the file" do
|
248
|
+
configatron.others.should be_nil
|
249
|
+
configatron.survivors.should be_nil
|
250
|
+
configatron.configure_from_yaml(File.join(File.dirname(__FILE__), 'lost.yml'), :hash => "survivors")
|
251
|
+
configatron.others.should be_nil
|
252
|
+
configatron.survivors.should be_nil
|
253
|
+
configatron.on_island.jack.should == 'Jack Shepherd'
|
254
|
+
end
|
255
|
+
|
256
|
+
class WireHelper
|
257
|
+
def self.best_show_on_tv?
|
258
|
+
true
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should be able to use ERB in yaml" do
|
263
|
+
AVON = "Avon Barksdale"
|
264
|
+
configatron.simpsons.should be_nil
|
265
|
+
configatron.configure_from_yaml(File.join(File.dirname(__FILE__), 'the_wire.yml'))
|
266
|
+
configatron.police.jimmy.should == "Jimmy McNulty"
|
267
|
+
configatron.best_show_on_tv.should == true
|
268
|
+
configatron.dealers.avon.should == "Avon Barksdale"
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'should return a parameter' do
|
274
|
+
configatron.foo = :bar
|
275
|
+
configatron.foo.should == :bar
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'should return a nested parameter' do
|
279
|
+
configatron.children.dylan = 'Dylan Bates'
|
280
|
+
configatron.children.dylan.should == 'Dylan Bates'
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'should set a nested parameter and not remove previously defined params' do
|
284
|
+
configatron.friends.rachel = 'Rachel Green'
|
285
|
+
configatron.friends.rachel.should == 'Rachel Green'
|
286
|
+
configatron.friends.ross = 'Ross Gellar'
|
287
|
+
configatron.friends.ross.should == 'Ross Gellar'
|
288
|
+
configatron.friends.monica = 'Monica Gellar'
|
289
|
+
configatron.friends.monica.should == 'Monica Gellar'
|
290
|
+
configatron.friends.rachel = 'R. Green'
|
291
|
+
configatron.friends.monica = 'Monica Bing'
|
292
|
+
configatron.friends.rachel.should == 'R. Green'
|
293
|
+
configatron.friends.ross.should == 'Ross Gellar'
|
294
|
+
configatron.friends.monica.should == 'Monica Bing'
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'should return the Configatron instance' do
|
298
|
+
configatron.should be_is_a(Configatron)
|
299
|
+
end
|
300
|
+
|
301
|
+
describe 'to_hash' do
|
302
|
+
|
303
|
+
it 'should return a hash of all the params' do
|
304
|
+
configatron.one = 1
|
305
|
+
configatron.letters.a = 'A'
|
306
|
+
configatron.letters.b = 'B'
|
307
|
+
configatron.to_hash.should == {:one => 1, :letters => {:a => 'A', :b => 'B'}}
|
308
|
+
end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
describe 'inspect' do
|
313
|
+
|
314
|
+
it 'should call return the inspect method of the to_hash method' do
|
315
|
+
configatron.one = 1
|
316
|
+
configatron.letters.a = 'A'
|
317
|
+
configatron.letters.b = 'B'
|
318
|
+
configatron.numbers.small.one = 1
|
319
|
+
configatron.numbers.small.others = [2,3]
|
320
|
+
configatron.numbers.big.one.hundred = '100'
|
321
|
+
|
322
|
+
configatron.inspect.should == %{
|
323
|
+
configatron.letters.a = "A"
|
324
|
+
configatron.letters.b = "B"
|
325
|
+
configatron.numbers.big.one.hundred = "100"
|
326
|
+
configatron.numbers.small.one = 1
|
327
|
+
configatron.numbers.small.others = [2, 3]
|
328
|
+
configatron.one = 1
|
329
|
+
}.strip
|
330
|
+
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
describe 'nil?' do
|
336
|
+
|
337
|
+
it 'should return true if there are no parameters' do
|
338
|
+
configatron.should be_nil
|
339
|
+
configatron.friends.should be_nil
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'should return true if there are no parameters on a nested parameter' do
|
343
|
+
configatron.friends.monica.should be_nil
|
344
|
+
end
|
345
|
+
|
346
|
+
end
|
347
|
+
|
348
|
+
describe 'retrieve' do
|
349
|
+
|
350
|
+
it 'should retrieve a parameter' do
|
351
|
+
configatron.office = 'Michael'
|
352
|
+
configatron.retrieve(:office).should == 'Michael'
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'should return the optional second parameter if the config setting is nil' do
|
356
|
+
configatron.retrieve(:office, 'Stanley').should == 'Stanley'
|
357
|
+
end
|
358
|
+
|
359
|
+
it 'should work with a symbol or a string' do
|
360
|
+
configatron.office = 'Michael'
|
361
|
+
configatron.retrieve(:office).should == 'Michael'
|
362
|
+
configatron.retrieve('office').should == 'Michael'
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'should work on nested parameters' do
|
366
|
+
configatron.the.office = 'Michael'
|
367
|
+
configatron.the.retrieve(:office).should == 'Michael'
|
368
|
+
configatron.the.retrieve('office').should == 'Michael'
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
describe 'remove' do
|
374
|
+
|
375
|
+
it 'should remove a parameter' do
|
376
|
+
configatron.movies = 'Pulp Fiction'
|
377
|
+
configatron.movies.should == 'Pulp Fiction'
|
378
|
+
configatron.remove(:movies)
|
379
|
+
configatron.movies.should be_nil
|
380
|
+
end
|
381
|
+
|
382
|
+
it 'should remove a nested parameter' do
|
383
|
+
configatron.the.movies = 'Pulp Fiction'
|
384
|
+
configatron.the.movies.should == 'Pulp Fiction'
|
385
|
+
configatron.the.remove(:movies)
|
386
|
+
configatron.the.movies.should be_nil
|
387
|
+
end
|
388
|
+
|
389
|
+
it 'should work with a symbol or a string' do
|
390
|
+
configatron.the.movies = 'Pulp Fiction'
|
391
|
+
configatron.the.office = 'Michael'
|
392
|
+
configatron.the.remove(:movies)
|
393
|
+
configatron.the.movies.should be_nil
|
394
|
+
configatron.the.remove('office')
|
395
|
+
configatron.the.office.should be_nil
|
396
|
+
end
|
397
|
+
|
398
|
+
it 'should remove all sub-parameters' do
|
399
|
+
configatron.the.movies = 'Pulp Fiction'
|
400
|
+
configatron.the.office = 'Michael'
|
401
|
+
configatron.remove(:the)
|
402
|
+
configatron.the.should be_nil
|
403
|
+
configatron.the.movies.should be_nil
|
404
|
+
end
|
405
|
+
|
406
|
+
end
|
407
|
+
|
408
|
+
describe 'set_default' do
|
409
|
+
|
410
|
+
it 'should set a default parameter value' do
|
411
|
+
configatron.set_default(:movies, 'Pulp Fiction')
|
412
|
+
configatron.movies.should == 'Pulp Fiction'
|
413
|
+
end
|
414
|
+
|
415
|
+
it 'should set a default parameter value for a nested parameter' do
|
416
|
+
configatron.the.set_default(:movies, 'Pulp Fiction')
|
417
|
+
configatron.the.movies.should == 'Pulp Fiction'
|
418
|
+
end
|
419
|
+
|
420
|
+
it 'should not set the parameter if it is already set' do
|
421
|
+
configatron.movies = 'Transformers'
|
422
|
+
configatron.set_default(:movies, 'Pulp Fiction')
|
423
|
+
configatron.movies.should == 'Transformers'
|
424
|
+
end
|
425
|
+
|
426
|
+
it 'should not set the nested parameter if it is already set' do
|
427
|
+
configatron.the.movies = 'Transformers'
|
428
|
+
configatron.the.set_default(:movies, 'Pulp Fiction')
|
429
|
+
configatron.the.movies.should == 'Transformers'
|
430
|
+
end
|
431
|
+
|
432
|
+
end
|
433
|
+
|
434
|
+
describe 'reset!' do
|
435
|
+
|
436
|
+
it 'should clear out all parameter' do
|
437
|
+
configatron.one = 1
|
438
|
+
configatron.letters.a = 'A'
|
439
|
+
configatron.letters.b = 'B'
|
440
|
+
configatron.one.should == 1
|
441
|
+
configatron.letters.a.should == 'A'
|
442
|
+
configatron.reset!
|
443
|
+
configatron.one.should be_nil
|
444
|
+
configatron.letters.a.should be_nil
|
445
|
+
end
|
446
|
+
|
447
|
+
end
|
448
|
+
|
449
|
+
end
|
data/spec/lib/lost.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
others:
|
2
|
+
on_island:
|
3
|
+
ben: Benjamin Linus
|
4
|
+
richard: Richard Alpert
|
5
|
+
deceased:
|
6
|
+
goodwin: Goodwin Stanhope
|
7
|
+
mikhail: Mikhail Bakunin
|
8
|
+
survivors:
|
9
|
+
on_island:
|
10
|
+
jack: Jack Shepherd
|
11
|
+
locke: John Locke
|
12
|
+
deceased:
|
13
|
+
charlie: Charlie Pace
|
14
|
+
michael: Michael Dawson
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: runcoderun-configatron
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.2.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- markbates
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-14 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: "Configatron was developed by: markbates"
|
17
|
+
email: mark@mackframework.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- lib/configatron/configatron.rb
|
26
|
+
- lib/configatron/errors.rb
|
27
|
+
- lib/configatron/kernel.rb
|
28
|
+
- lib/configatron/store.rb
|
29
|
+
- lib/configatron.rb
|
30
|
+
- README
|
31
|
+
- spec/lib
|
32
|
+
- spec/lib/configatron_spec.rb
|
33
|
+
- spec/lib/futurama.yml
|
34
|
+
- spec/lib/lost.yml
|
35
|
+
- spec/lib/the_wire.yml
|
36
|
+
- spec/spec.opts
|
37
|
+
- spec/spec_helper.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://www.mackframework.com
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project: magrathea
|
61
|
+
rubygems_version: 1.2.0
|
62
|
+
signing_key:
|
63
|
+
specification_version: 2
|
64
|
+
summary: A powerful Ruby configuration system.
|
65
|
+
test_files:
|
66
|
+
- spec/lib
|
67
|
+
- spec/lib/configatron_spec.rb
|
68
|
+
- spec/lib/futurama.yml
|
69
|
+
- spec/lib/lost.yml
|
70
|
+
- spec/lib/the_wire.yml
|
71
|
+
- spec/spec.opts
|
72
|
+
- spec/spec_helper.rb
|