sevenwire-configatron 2.2.2

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 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,9 @@
1
+ base = File.join(File.dirname(__FILE__), 'configatron')
2
+ require 'yaml'
3
+ require File.join(base, 'configatron')
4
+ require File.join(base, 'store')
5
+ require File.join(base, 'errors')
6
+ require File.join(base, 'core_ext', 'kernel')
7
+ require File.join(base, 'core_ext', 'object')
8
+ require File.join(base, 'core_ext', 'string')
9
+ require File.join(base, 'core_ext', 'class')
@@ -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,26 @@
1
+ class Class
2
+
3
+ # Returns access to configuration parameters named after the class.
4
+ #
5
+ # Examples:
6
+ # configatron.foo.bar = :bar
7
+ # configatron.a.b.c.d = 'D'
8
+ #
9
+ # class Foo
10
+ # end
11
+ #
12
+ # module A
13
+ # module B
14
+ # class C
15
+ # end
16
+ # end
17
+ # end
18
+ #
19
+ # Foo.to_configatron.bar # => :bar
20
+ # A::B::C.to_configatron.d # => 'D'
21
+ def to_configatron
22
+ name_spaces = self.name.split("::").collect{|s| s.methodize}
23
+ configatron.send_with_chain(name_spaces)
24
+ end
25
+
26
+ end
@@ -0,0 +1,8 @@
1
+ module Kernel
2
+
3
+ # Provides access to the Configatron storage system.
4
+ def configatron
5
+ Configatron.instance
6
+ end
7
+
8
+ end
@@ -0,0 +1,9 @@
1
+ class Object # :nodoc:
2
+
3
+ def send_with_chain(methods, *args) # :nodoc:
4
+ obj = self
5
+ [methods].flatten.each {|m| obj = obj.send(m, *args)}
6
+ obj
7
+ end
8
+
9
+ end
@@ -0,0 +1,84 @@
1
+ class String # :nodoc:
2
+
3
+ def underscore # :nodoc:
4
+ self.to_s.gsub(/::/, '/').
5
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
6
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
7
+ tr("-", "_").
8
+ downcase
9
+ end
10
+
11
+ def methodize # :nodoc:
12
+ x = self
13
+
14
+ # if we get down to a nil or an empty string raise an exception!
15
+ raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
16
+
17
+ # get rid of the big stuff in the front/back
18
+ x.strip!
19
+
20
+ # if we get down to a nil or an empty string raise an exception!
21
+ raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
22
+
23
+ x = x.underscore
24
+
25
+ # get rid of spaces and make the _
26
+ x.gsub!(' ', '_')
27
+ # get rid of everything that isn't 'safe' a-z, 0-9, ?, !, =, _
28
+ x.gsub!(/([^ a-zA-Z0-9\_\?\!\=]+)/n, '_')
29
+
30
+ # if we get down to a nil or an empty string raise an exception!
31
+ raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
32
+
33
+ # condense multiple 'safe' non a-z chars to just one.
34
+ # ie. ___ becomes _ !!!! becomes ! etc...
35
+ [' ', '_', '?', '!', "="].each do |c|
36
+ x.squeeze!(c)
37
+ end
38
+
39
+ # if we get down to a nil or an empty string raise an exception!
40
+ raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
41
+
42
+ #down case the whole thing
43
+ x.downcase!
44
+
45
+ # get rid of any characters at the beginning that aren't a-z
46
+ while !x.match(/^[a-z]/)
47
+ x.slice!(0)
48
+
49
+ # if we get down to a nil or an empty string raise an exception!
50
+ raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
51
+ end
52
+
53
+ # let's trim this bad boy down a bit now that we've cleaned it up, somewhat.
54
+ # we should do this before cleaning up the end character, because it's possible to end up with a
55
+ # bad char at the end if you trim too late.
56
+ x = x[0..100] if x.length > 100
57
+
58
+ # get rid of any characters at the end that aren't safe
59
+ while !x.match(/[a-z0-9\?\!\=]$/)
60
+ x.slice!(x.length - 1)
61
+ # if we get down to a nil or an empty string raise an exception!
62
+ raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
63
+ end
64
+
65
+ # if we get down to a nil or an empty string raise an exception!
66
+ raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
67
+
68
+ # let's get rid of characters that don't belong in the 'middle' of the method.
69
+ orig_middle = x[1..(x.length - 2)]
70
+ n_middle = orig_middle.dup
71
+
72
+ ['?', '!', "="].each do |c|
73
+ n_middle.gsub!(c, "_")
74
+ end
75
+
76
+ # the previous gsub can leave us with multiple underscores that need cleaning up.
77
+ n_middle.squeeze!("_")
78
+
79
+ x.gsub!(orig_middle, n_middle)
80
+ x.gsub!("_=", "=")
81
+ x
82
+ end
83
+
84
+ 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,258 @@
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(File.read(path))
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 sym.to_s.match(/(.+)\!$/)
101
+ name = sym.to_s.gsub("!", '').to_sym
102
+ @_store.has_key?(name) && !@_store[name].nil? ? @_store[name] : nil
103
+ elsif @_store.has_key?(sym)
104
+ return @_store[sym]
105
+ else
106
+ store = Configatron::Store.new({}, sym, self)
107
+ @_store[sym] = store
108
+ return store
109
+ end
110
+ end
111
+
112
+ def ==(other) # :nodoc:
113
+ self.to_hash == other
114
+ end
115
+
116
+ # Prevents a parameter from being reassigned. If called on a 'namespace' then
117
+ # all parameters below it will be protected as well.
118
+ def protect(name)
119
+ @_protected << name.to_sym
120
+ end
121
+
122
+ # Prevents all parameters from being reassigned.
123
+ def protect_all!
124
+ @_protected.clear
125
+ @_store.keys.each do |k|
126
+ val = self.send(k)
127
+ val.protect_all! if val.class == Configatron::Store
128
+ @_protected << k
129
+ end
130
+ end
131
+
132
+ # Removes the protection of a parameter.
133
+ def unprotect(name)
134
+ @_protected.reject! { |e| e == name.to_sym }
135
+ end
136
+
137
+ def unprotect_all!
138
+ @_protected.clear
139
+ @_store.keys.each do |k|
140
+ val = self.send(k)
141
+ val.unprotect_all! if val.class == Configatron::Store
142
+ end
143
+ end
144
+
145
+ # Prevents a namespace from having new parameters set. The lock is applied
146
+ # recursively to any namespaces below it.
147
+ def lock(name)
148
+ namespace = @_store[name.to_sym]
149
+ raise ArgumentError, "Namespace #{name.inspect} does not exist" if namespace.nil?
150
+ namespace.lock!
151
+ end
152
+
153
+ def unlock(name)
154
+ namespace = @_store[name.to_sym]
155
+ raise ArgumentError, "Namespace #{name.inspect} does not exist" if namespace.nil?
156
+ namespace.unlock!
157
+ end
158
+
159
+ # = DeepClone
160
+ #
161
+ # == Version
162
+ # 1.2006.05.23 (change of the first number means Big Change)
163
+ #
164
+ # == Description
165
+ # Adds deep_clone method to an object which produces deep copy of it. It means
166
+ # if you clone a Hash, every nested items and their nested items will be cloned.
167
+ # Moreover deep_clone checks if the object is already cloned to prevent endless recursion.
168
+ #
169
+ # == Usage
170
+ #
171
+ # (see examples directory under the ruby gems root directory)
172
+ #
173
+ # require 'rubygems'
174
+ # require 'deep_clone'
175
+ #
176
+ # include DeepClone
177
+ #
178
+ # obj = []
179
+ # a = [ true, false, obj ]
180
+ # b = a.deep_clone
181
+ # obj.push( 'foo' )
182
+ # p obj # >> [ 'foo' ]
183
+ # p b[2] # >> []
184
+ #
185
+ # == Source
186
+ # http://simplypowerful.1984.cz/goodlibs/1.2006.05.23
187
+ #
188
+ # == Author
189
+ # jan molic (/mig/at_sign/1984/dot/cz/)
190
+ #
191
+ # == Licence
192
+ # You can redistribute it and/or modify it under the same terms of Ruby's license;
193
+ # either the dual license version in 2003, or any later version.
194
+ #
195
+ def deep_clone( obj=self, cloned={} )
196
+ if cloned.has_key?( obj.object_id )
197
+ return cloned[obj.object_id]
198
+ else
199
+ begin
200
+ cl = obj.clone
201
+ rescue Exception
202
+ # unclonnable (TrueClass, Fixnum, ...)
203
+ cloned[obj.object_id] = obj
204
+ return obj
205
+ else
206
+ cloned[obj.object_id] = cl
207
+ cloned[cl.object_id] = cl
208
+ if cl.is_a?( Hash )
209
+ cl.clone.each { |k,v|
210
+ cl[k] = deep_clone( v, cloned )
211
+ }
212
+ elsif cl.is_a?( Array )
213
+ cl.collect! { |v|
214
+ deep_clone( v, cloned )
215
+ }
216
+ end
217
+ cl.instance_variables.each do |var|
218
+ v = cl.instance_eval( var.to_s )
219
+ v_cl = deep_clone( v, cloned )
220
+ cl.instance_eval( "#{var} = v_cl" )
221
+ end
222
+ return cl
223
+ end
224
+ end
225
+ end
226
+
227
+ protected
228
+ def lock!
229
+ @_locked = true
230
+ @_store.values.each { |store| store.lock! if store.is_a?(Configatron::Store) }
231
+ end
232
+
233
+ def unlock!
234
+ @_locked = false
235
+ @_store.values.each { |store| store.unlock! if store.is_a?(Configatron::Store) }
236
+ end
237
+
238
+ private
239
+ def methods_include?(name)
240
+ self.methods.include?(RUBY_VERSION > '1.9.0' ? name.to_sym : name.to_s)
241
+ end
242
+
243
+ def parse_options(options)
244
+ if options.is_a?(Hash)
245
+ options.each do |k,v|
246
+ if v.is_a?(Hash)
247
+ self.method_missing(k.to_sym).configure_from_hash(v)
248
+ else
249
+ self.method_missing("#{k.to_sym}=", v)
250
+ end
251
+ end
252
+ else
253
+ return options
254
+ end
255
+ end
256
+
257
+ end
258
+ end
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+
3
+ configatron.foo.bar = :bar
4
+ configatron.a.b.c.d = 'D'
5
+
6
+ class Foo
7
+ end
8
+
9
+ module A
10
+ module B
11
+ class C
12
+ end
13
+ end
14
+ end
15
+
16
+ describe Class do
17
+
18
+ describe 'to_configatron' do
19
+
20
+ it 'should return a Configatron::Store object based on the name of the class' do
21
+ Foo.to_configatron.should be_kind_of(Configatron::Store)
22
+ Foo.to_configatron.bar.should == :bar
23
+ A::B::C.to_configatron.d.should == 'D'
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,434 @@
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
+ end
257
+
258
+ it 'should return a parameter' do
259
+ configatron.foo = :bar
260
+ configatron.foo.should == :bar
261
+ end
262
+
263
+ it 'should return a nested parameter' do
264
+ configatron.children.dylan = 'Dylan Bates'
265
+ configatron.children.dylan.should == 'Dylan Bates'
266
+ end
267
+
268
+ it 'should set a nested parameter and not remove previously defined params' do
269
+ configatron.friends.rachel = 'Rachel Green'
270
+ configatron.friends.rachel.should == 'Rachel Green'
271
+ configatron.friends.ross = 'Ross Gellar'
272
+ configatron.friends.ross.should == 'Ross Gellar'
273
+ configatron.friends.monica = 'Monica Gellar'
274
+ configatron.friends.monica.should == 'Monica Gellar'
275
+ configatron.friends.rachel = 'R. Green'
276
+ configatron.friends.monica = 'Monica Bing'
277
+ configatron.friends.rachel.should == 'R. Green'
278
+ configatron.friends.ross.should == 'Ross Gellar'
279
+ configatron.friends.monica.should == 'Monica Bing'
280
+ end
281
+
282
+ it 'should return the Configatron instance' do
283
+ configatron.should be_is_a(Configatron)
284
+ end
285
+
286
+ describe 'to_hash' do
287
+
288
+ it 'should return a hash of all the params' do
289
+ configatron.one = 1
290
+ configatron.letters.a = 'A'
291
+ configatron.letters.b = 'B'
292
+ configatron.to_hash.should == {:one => 1, :letters => {:a => 'A', :b => 'B'}}
293
+ end
294
+
295
+ end
296
+
297
+ describe 'inspect' do
298
+
299
+ it 'should call return the inspect method of the to_hash method' do
300
+ configatron.one = 1
301
+ configatron.letters.a = 'A'
302
+ configatron.letters.b = 'B'
303
+ configatron.numbers.small.one = 1
304
+ configatron.numbers.small.others = [2,3]
305
+ configatron.numbers.big.one.hundred = '100'
306
+
307
+ configatron.inspect.should == %{
308
+ configatron.letters.a = "A"
309
+ configatron.letters.b = "B"
310
+ configatron.numbers.big.one.hundred = "100"
311
+ configatron.numbers.small.one = 1
312
+ configatron.numbers.small.others = [2, 3]
313
+ configatron.one = 1
314
+ }.strip
315
+
316
+ end
317
+
318
+ end
319
+
320
+ describe 'nil?' do
321
+
322
+ it 'should return true if there are no parameters' do
323
+ configatron.should be_nil
324
+ configatron.friends.should be_nil
325
+ end
326
+
327
+ it 'should return true if there are no parameters on a nested parameter' do
328
+ configatron.friends.monica.should be_nil
329
+ end
330
+
331
+ end
332
+
333
+ describe 'retrieve' do
334
+
335
+ it 'should retrieve a parameter' do
336
+ configatron.office = 'Michael'
337
+ configatron.retrieve(:office).should == 'Michael'
338
+ end
339
+
340
+ it 'should return the optional second parameter if the config setting is nil' do
341
+ configatron.retrieve(:office, 'Stanley').should == 'Stanley'
342
+ end
343
+
344
+ it 'should work with a symbol or a string' do
345
+ configatron.office = 'Michael'
346
+ configatron.retrieve(:office).should == 'Michael'
347
+ configatron.retrieve('office').should == 'Michael'
348
+ end
349
+
350
+ it 'should work on nested parameters' do
351
+ configatron.the.office = 'Michael'
352
+ configatron.the.retrieve(:office).should == 'Michael'
353
+ configatron.the.retrieve('office').should == 'Michael'
354
+ end
355
+
356
+ end
357
+
358
+ describe 'remove' do
359
+
360
+ it 'should remove a parameter' do
361
+ configatron.movies = 'Pulp Fiction'
362
+ configatron.movies.should == 'Pulp Fiction'
363
+ configatron.remove(:movies)
364
+ configatron.movies.should be_nil
365
+ end
366
+
367
+ it 'should remove a nested parameter' do
368
+ configatron.the.movies = 'Pulp Fiction'
369
+ configatron.the.movies.should == 'Pulp Fiction'
370
+ configatron.the.remove(:movies)
371
+ configatron.the.movies.should be_nil
372
+ end
373
+
374
+ it 'should work with a symbol or a string' do
375
+ configatron.the.movies = 'Pulp Fiction'
376
+ configatron.the.office = 'Michael'
377
+ configatron.the.remove(:movies)
378
+ configatron.the.movies.should be_nil
379
+ configatron.the.remove('office')
380
+ configatron.the.office.should be_nil
381
+ end
382
+
383
+ it 'should remove all sub-parameters' do
384
+ configatron.the.movies = 'Pulp Fiction'
385
+ configatron.the.office = 'Michael'
386
+ configatron.remove(:the)
387
+ configatron.the.should be_nil
388
+ configatron.the.movies.should be_nil
389
+ end
390
+
391
+ end
392
+
393
+ describe 'set_default' do
394
+
395
+ it 'should set a default parameter value' do
396
+ configatron.set_default(:movies, 'Pulp Fiction')
397
+ configatron.movies.should == 'Pulp Fiction'
398
+ end
399
+
400
+ it 'should set a default parameter value for a nested parameter' do
401
+ configatron.the.set_default(:movies, 'Pulp Fiction')
402
+ configatron.the.movies.should == 'Pulp Fiction'
403
+ end
404
+
405
+ it 'should not set the parameter if it is already set' do
406
+ configatron.movies = 'Transformers'
407
+ configatron.set_default(:movies, 'Pulp Fiction')
408
+ configatron.movies.should == 'Transformers'
409
+ end
410
+
411
+ it 'should not set the nested parameter if it is already set' do
412
+ configatron.the.movies = 'Transformers'
413
+ configatron.the.set_default(:movies, 'Pulp Fiction')
414
+ configatron.the.movies.should == 'Transformers'
415
+ end
416
+
417
+ end
418
+
419
+ describe 'reset!' do
420
+
421
+ it 'should clear out all parameter' do
422
+ configatron.one = 1
423
+ configatron.letters.a = 'A'
424
+ configatron.letters.b = 'B'
425
+ configatron.one.should == 1
426
+ configatron.letters.a.should == 'A'
427
+ configatron.reset!
428
+ configatron.one.should be_nil
429
+ configatron.letters.a.should be_nil
430
+ end
431
+
432
+ end
433
+
434
+ end
@@ -0,0 +1,6 @@
1
+ futurama:
2
+ robots:
3
+ bender: Bender The Robot
4
+ humans:
5
+ fry: Philip J. Fry
6
+ amy: Amy Wong
@@ -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
@@ -0,0 +1,2 @@
1
+ --format specdoc
2
+ --colour
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'configatron')
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sevenwire-configatron
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.2.2
5
+ platform: ruby
6
+ authors:
7
+ - markbates
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-29 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/core_ext/class.rb
27
+ - lib/configatron/core_ext/kernel.rb
28
+ - lib/configatron/core_ext/object.rb
29
+ - lib/configatron/core_ext/string.rb
30
+ - lib/configatron/errors.rb
31
+ - lib/configatron/store.rb
32
+ - lib/configatron.rb
33
+ - README
34
+ - spec/lib
35
+ - spec/lib/class_spec.rb
36
+ - spec/lib/configatron_spec.rb
37
+ - spec/lib/futurama.yml
38
+ - spec/lib/lost.yml
39
+ - spec/spec.opts
40
+ - spec/spec_helper.rb
41
+ has_rdoc: true
42
+ homepage: http://www.mackframework.com
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project: magrathea
64
+ rubygems_version: 1.2.0
65
+ signing_key:
66
+ specification_version: 2
67
+ summary: A powerful Ruby configuration system.
68
+ test_files:
69
+ - spec/lib
70
+ - spec/lib/class_spec.rb
71
+ - spec/lib/configatron_spec.rb
72
+ - spec/lib/futurama.yml
73
+ - spec/lib/lost.yml
74
+ - spec/spec.opts
75
+ - spec/spec_helper.rb