configatron 1.2.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. data/README +61 -34
  2. data/doc/classes/Configatron.html +241 -0
  3. data/doc/classes/Configatron/ProtectedParameter.html +146 -0
  4. data/doc/classes/Configatron/Store.html +241 -121
  5. data/doc/classes/Kernel.html +13 -20
  6. data/doc/created.rid +1 -1
  7. data/doc/files/README.html +85 -43
  8. data/doc/files/lib/configatron/{configuration_rb.html → configatron_rb.html} +11 -4
  9. data/doc/files/lib/configatron/{helpers_rb.html → errors_rb.html} +4 -4
  10. data/doc/files/lib/configatron/kernel_rb.html +1 -1
  11. data/doc/files/lib/configatron/store_rb.html +1 -1
  12. data/doc/files/lib/configatron_rb.html +1 -2
  13. data/doc/fr_class_index.html +2 -4
  14. data/doc/fr_file_index.html +2 -3
  15. data/doc/fr_method_index.html +15 -21
  16. data/lib/configatron.rb +5 -44
  17. data/lib/configatron/configatron.rb +44 -0
  18. data/lib/configatron/errors.rb +7 -0
  19. data/lib/configatron/kernel.rb +3 -9
  20. data/lib/configatron/store.rb +148 -56
  21. data/spec/lib/configatron_spec.rb +293 -0
  22. data/spec/lib/futurama.yml +6 -0
  23. data/spec/spec_helper.rb +3 -2
  24. metadata +11 -18
  25. data/doc/classes/Configatron/Configuration.html +0 -402
  26. data/doc/classes/Configatron/Helpers.html +0 -174
  27. data/doc/classes/Configatron/YamlStore.html +0 -203
  28. data/doc/classes/Hash.html +0 -193
  29. data/doc/files/lib/configatron/yaml_store_rb.html +0 -101
  30. data/lib/configatron/configuration.rb +0 -112
  31. data/lib/configatron/helpers.rb +0 -27
  32. data/lib/configatron/yaml_store.rb +0 -33
  33. data/spec/unit/configuration_spec.rb +0 -299
  34. data/spec/unit/family_guy.yml +0 -2
  35. data/spec/unit/helpers_spec.rb +0 -115
  36. data/spec/unit/kernel_spec.rb +0 -48
  37. data/spec/unit/store_spec.rb +0 -91
@@ -0,0 +1,44 @@
1
+ require 'singleton'
2
+
3
+ class Configatron
4
+ include Singleton
5
+
6
+ def initialize # :nodoc:
7
+ @_namespace = :default
8
+ reset!
9
+ end
10
+
11
+ # Forwards the method call onto the 'namespaced' Configatron::Store
12
+ def method_missing(sym, *args)
13
+ @_store[@_namespace].send(sym, *args)
14
+ end
15
+
16
+ # Removes ALL configuration parameters
17
+ def reset!
18
+ @_store = {:default => Configatron::Store.new}
19
+ end
20
+
21
+ # Allows for the temporary overriding of parameters in a block.
22
+ # Takes an optional Hash of parameters that will be applied before
23
+ # the block gets called. At the end of the block, the temporary
24
+ # settings are deleted and the original settings are reinstated.
25
+ def temp(options = nil)
26
+ @_namespace = rand
27
+ @_store[@_namespace] = @_store[:default].deep_clone
28
+ begin
29
+ if options
30
+ self.method_missing(:configure_from_hash, options)
31
+ end
32
+ yield
33
+ rescue Exception => e
34
+ raise e
35
+ ensure
36
+ @_store.delete(@_namespace)
37
+ @_namespace = :default
38
+ end
39
+ end
40
+
41
+ undef :inspect # :nodoc:
42
+ undef :nil? # :nodoc:
43
+
44
+ end
@@ -0,0 +1,7 @@
1
+ class Configatron
2
+ class ProtectedParameter < StandardError
3
+ def intialize(name)
4
+ super("Can not modify protected parameter: '#{name}'")
5
+ end
6
+ end
7
+ end
@@ -1,14 +1,8 @@
1
1
  module Kernel
2
2
 
3
- # If called without a block it will return the Configatron::Configuration instance.
4
- # If called with a block then it will call the Configatron::Configatron configure method
5
- # and yield up a Configatron::Store object.
6
- def configatron(&block)
7
- if block_given?
8
- Configatron::Configuration.instance.configure(&block)
9
- else
10
- Configatron::Configuration.instance
11
- end
3
+ # Provides access to the Configatron storage system.
4
+ def configatron
5
+ Configatron.instance
12
6
  end
13
7
 
14
8
  end
@@ -1,74 +1,166 @@
1
- module Configatron
2
- # Used to store each of the 'sets' of configuration parameters.
1
+ class Configatron
3
2
  class Store
4
- include Configatron::Helpers
5
3
 
6
- # The actual key/pair parameter values.
7
- attr_reader :parameters
8
-
9
- # Takes an optional Hash to configure parameters.
10
- def initialize(parameters = {})
11
- @parameters = parameters.inject({}) do |m,pair|
12
- sym = pair.first.is_a?(Symbol) ? pair.first : pair.first.intern
13
- m[sym] = pair.last
14
- m
15
- end
4
+ # Takes an optional Hash of parameters
5
+ def initialize(options = {})
6
+ @_store = {}
7
+ configure_from_hash(options)
8
+ @_protected = []
16
9
  end
17
-
18
- # If a method is called with an = at the end, then that method name, minus
19
- # the equal sign is added to the parameter list as a key, and it's *args
20
- # become the value for that key. Eventually the keys become method names.
21
- # If a method is called without an = sign at the end then the value from
22
- # the parameters hash is returned, if it exists.
23
- def method_missing(sym, *args)
24
- if sym.to_s.match(/(.+)=$/)
25
- @parameters[sym.to_s.gsub("=", '').to_sym] = *args
26
- else
27
- val = @parameters[sym]
28
- if val.is_a? Hash
29
- val = (@parameters[sym] = Configatron::Store.new(val))
30
- end
31
- return val unless val.nil?
32
- return handle_missing_parameter(sym)
10
+
11
+ # Returns a Hash representing the configurations
12
+ def to_hash
13
+ @_store
14
+ end
15
+
16
+ def inspect # :nodoc:
17
+ to_hash.inspect
18
+ end
19
+
20
+ # Allows for the configuration of the system via a Hash
21
+ def configure_from_hash(options)
22
+ parse_options(options)
23
+ end
24
+
25
+ # Allows for the configuration of the system from a YAML file.
26
+ # Takes the path to the YAML file.
27
+ def configure_from_yaml(path)
28
+ begin
29
+ configure_from_hash(YAML.load(File.read(path)))
30
+ rescue Errno::ENOENT => e
31
+ puts e.message
33
32
  end
34
33
  end
34
+
35
+ # Returns true if there are no configuration parameters
36
+ def nil?
37
+ return @_store.empty?
38
+ end
39
+
40
+ # Retrieves a certain parameter and if that parameter
41
+ # doesn't exist it will return the default_value specified.
42
+ def retrieve(name, default_value = nil)
43
+ @_store[name.to_sym] || default_value
44
+ end
35
45
 
36
- # Checks whether or not configuration parameter exists.
37
- def exists?(name)
38
- return true unless @parameters[name.to_sym].nil?
39
- super(name)
46
+ # Removes a parameter. In the case of a nested parameter
47
+ # it will remove all below it.
48
+ def remove(name)
49
+ @_store.delete(name.to_sym)
50
+ end
51
+
52
+ # Sets a 'default' value. If there is already a value specified
53
+ # it won't set the value.
54
+ def set_default(name, default_value)
55
+ unless @_store[name.to_sym]
56
+ @_store[name.to_sym] = parse_options(default_value)
57
+ end
40
58
  end
41
59
 
42
- # Used to create 'namespaces' around a set of configuration parameters.
43
- def namespace(name)
44
- if exists?(name)
45
- yield self.send(name.to_sym)
46
- elsif configatron.exists?(name)
47
- yield configatron.send(name.to_sym)
60
+ def method_missing(sym, *args) # :nodoc:
61
+ if sym.to_s.match(/(.+)=$/)
62
+ name = sym.to_s.gsub("=", '').to_sym
63
+ raise Configatron::ProtectedParameter.new(name) if @_protected.include?(name)
64
+ @_store[name] = parse_options(*args)
65
+ elsif @_store.has_key?(sym)
66
+ return @_store[sym]
48
67
  else
49
- ns = Configatron::Store.new
50
- yield ns
51
- @parameters[name.to_sym] = ns
68
+ store = Configatron::Store.new
69
+ @_store[sym] = store
70
+ return store
52
71
  end
53
72
  end
54
73
 
55
- # Called when a reload is called on configatron. Useful for subclasses that
56
- # may need to read a file in, etc...
57
- def reload
74
+ def ==(other) # :nodoc:
75
+ self.to_hash == other
58
76
  end
59
77
 
60
- def to_hash
61
- @parameters.inject({}) do |acc, (k,v)|
62
- case v
63
- when Configatron::Store
64
- acc[k] = v.to_hash
78
+ def protect(name)
79
+ @_protected << name.to_sym
80
+ end
81
+
82
+ # = DeepClone
83
+ #
84
+ # == Version
85
+ # 1.2006.05.23 (change of the first number means Big Change)
86
+ #
87
+ # == Description
88
+ # Adds deep_clone method to an object which produces deep copy of it. It means
89
+ # if you clone a Hash, every nested items and their nested items will be cloned.
90
+ # Moreover deep_clone checks if the object is already cloned to prevent endless recursion.
91
+ #
92
+ # == Usage
93
+ #
94
+ # (see examples directory under the ruby gems root directory)
95
+ #
96
+ # require 'rubygems'
97
+ # require 'deep_clone'
98
+ #
99
+ # include DeepClone
100
+ #
101
+ # obj = []
102
+ # a = [ true, false, obj ]
103
+ # b = a.deep_clone
104
+ # obj.push( 'foo' )
105
+ # p obj # >> [ 'foo' ]
106
+ # p b[2] # >> []
107
+ #
108
+ # == Source
109
+ # http://simplypowerful.1984.cz/goodlibs/1.2006.05.23
110
+ #
111
+ # == Author
112
+ # jan molic (/mig/at_sign/1984/dot/cz/)
113
+ #
114
+ # == Licence
115
+ # You can redistribute it and/or modify it under the same terms of Ruby's license;
116
+ # either the dual license version in 2003, or any later version.
117
+ #
118
+ def deep_clone( obj=self, cloned={} )
119
+ if cloned.has_key?( obj.object_id )
120
+ return cloned[obj.object_id]
121
+ else
122
+ begin
123
+ cl = obj.clone
124
+ rescue Exception
125
+ # unclonnable (TrueClass, Fixnum, ...)
126
+ cloned[obj.object_id] = obj
127
+ return obj
65
128
  else
66
- acc[k] = v
129
+ cloned[obj.object_id] = cl
130
+ cloned[cl.object_id] = cl
131
+ if cl.is_a?( Hash )
132
+ cl.clone.each { |k,v|
133
+ cl[k] = deep_clone( v, cloned )
134
+ }
135
+ elsif cl.is_a?( Array )
136
+ cl.collect! { |v|
137
+ deep_clone( v, cloned )
138
+ }
139
+ end
140
+ cl.instance_variables.each do |var|
141
+ v = cl.instance_eval( var )
142
+ v_cl = deep_clone( v, cloned )
143
+ cl.instance_eval( "#{var} = v_cl" )
144
+ end
145
+ return cl
67
146
  end
68
-
69
- acc
70
147
  end
71
148
  end
72
-
73
- end # Store
74
- end # Configatron
149
+
150
+ private
151
+ def parse_options(options)
152
+ if options.is_a?(Hash)
153
+ options.each do |k,v|
154
+ if v.is_a?(Hash)
155
+ self.method_missing(k.to_sym).configure_from_hash(v)
156
+ else
157
+ self.method_missing("#{k.to_sym}=", v)
158
+ end
159
+ end
160
+ else
161
+ return options
162
+ end
163
+ end
164
+
165
+ end
166
+ end
@@ -0,0 +1,293 @@
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 work with nested parameters' do
19
+ configatron.one = 1
20
+ configatron.letters.a = 'A'
21
+ configatron.letters.b = 'B'
22
+ configatron.letters.protect(:a)
23
+ lambda{configatron.letters.a = 'a'}.should raise_error(Configatron::ProtectedParameter)
24
+ configatron.letters.a.should == 'A'
25
+ configatron.protect(:letters)
26
+ lambda{configatron.letters.a = 'a'}.should raise_error(Configatron::ProtectedParameter)
27
+ lambda{configatron.letters = 'letter'}.should raise_error(Configatron::ProtectedParameter)
28
+ end
29
+
30
+ it 'should work with configure_from_hash' do
31
+ configatron.one = 1
32
+ configatron.letters.a = 'A'
33
+ configatron.letters.b = 'B'
34
+ configatron.letters.protect(:a)
35
+ lambda{configatron.configure_from_hash(:letters => {:a => 'a'})}.should raise_error(Configatron::ProtectedParameter)
36
+ configatron.letters.a.should == 'A'
37
+ configatron.protect(:letters)
38
+ lambda{configatron.letters.configure_from_hash(:a => 'a')}.should raise_error(Configatron::ProtectedParameter)
39
+ lambda{configatron.configure_from_hash(:letters => 'letters')}.should raise_error(Configatron::ProtectedParameter)
40
+ end
41
+
42
+ end
43
+
44
+ describe 'temp' do
45
+
46
+ it 'should revert back to the original parameters when the block ends' do
47
+ configatron.one = 1
48
+ configatron.letters.a = 'A'
49
+ configatron.letters.b = 'B'
50
+ configatron.temp do
51
+ configatron.letters.b = 'bb'
52
+ configatron.letters.c = 'c'
53
+ configatron.one.should == 1
54
+ configatron.letters.a.should == 'A'
55
+ configatron.letters.b.should == 'bb'
56
+ configatron.letters.c.should == 'c'
57
+ end
58
+ configatron.one.should == 1
59
+ configatron.letters.a.should == 'A'
60
+ configatron.letters.b.should == 'B'
61
+ configatron.letters.c.should be_nil
62
+ end
63
+
64
+ it 'should take an optional hash of parameters' do
65
+ configatron.one = 1
66
+ configatron.letters.a = 'A'
67
+ configatron.letters.b = 'B'
68
+ configatron.temp(:letters => {:b => 'bb', :c => 'c'}) do
69
+ configatron.one.should == 1
70
+ configatron.letters.a.should == 'A'
71
+ configatron.letters.b.should == 'bb'
72
+ configatron.letters.c.should == 'c'
73
+ end
74
+ configatron.one.should == 1
75
+ configatron.letters.a.should == 'A'
76
+ configatron.letters.b.should == 'B'
77
+ configatron.letters.c.should be_nil
78
+ end
79
+
80
+ end
81
+
82
+ describe 'configure_from_hash' do
83
+
84
+ it 'should configure itself from a hash' do
85
+ configatron.foo.should be_nil
86
+ configatron.configure_from_hash(:foo => :bar)
87
+ configatron.foo.should == :bar
88
+ end
89
+
90
+ it 'should handled deeply nested params' do
91
+ configatron.friends.rachel.should be_nil
92
+ configatron.configure_from_hash(:friends => {:rachel => 'Rachel Green'})
93
+ configatron.friends.rachel.should == 'Rachel Green'
94
+ end
95
+
96
+ it 'should not remove previously defined params' do
97
+ configatron.friends.rachel = 'Rachel Green'
98
+ configatron.friends.ross = 'Ross Gellar'
99
+ configatron.friends.monica = 'Monica Gellar'
100
+ configatron.configure_from_hash(:friends => {:rachel => 'R. Green', :monica => 'Monica Bing'})
101
+ configatron.friends.ross.should == 'Ross Gellar'
102
+ configatron.friends.rachel.should == 'R. Green'
103
+ configatron.friends.monica.should == 'Monica Bing'
104
+ end
105
+
106
+ end
107
+
108
+ describe 'configure_from_yaml' do
109
+
110
+ it 'should configure itself from a yaml file' do
111
+ configatron.futurama.should be_nil
112
+ configatron.configure_from_yaml(File.join(File.dirname(__FILE__), 'futurama.yml'))
113
+ configatron.futurama.robots.bender.should == 'Bender The Robot'
114
+ end
115
+
116
+ it 'should not remove previously defined params' do
117
+ configatron.futurama.mutants.leela = 'Leela'
118
+ configatron.configure_from_yaml(File.join(File.dirname(__FILE__), 'futurama.yml'))
119
+ configatron.futurama.robots.bender.should == 'Bender The Robot'
120
+ configatron.futurama.mutants.leela = 'Leela'
121
+ end
122
+
123
+ it "should fail silently if the file doesn't exist" do
124
+ lambda{configatron.configure_from_yaml('i_dont_exist.yml')}.should_not raise_error
125
+ end
126
+
127
+ end
128
+
129
+ it 'should return a parameter' do
130
+ configatron.foo = :bar
131
+ configatron.foo.should == :bar
132
+ end
133
+
134
+ it 'should return a nested parameter' do
135
+ configatron.children.dylan = 'Dylan Bates'
136
+ configatron.children.dylan.should == 'Dylan Bates'
137
+ end
138
+
139
+ it 'should set a nested parameter and not remove previously defined params' do
140
+ configatron.friends.rachel = 'Rachel Green'
141
+ configatron.friends.rachel.should == 'Rachel Green'
142
+ configatron.friends.ross = 'Ross Gellar'
143
+ configatron.friends.ross.should == 'Ross Gellar'
144
+ configatron.friends.monica = 'Monica Gellar'
145
+ configatron.friends.monica.should == 'Monica Gellar'
146
+ configatron.friends.rachel = 'R. Green'
147
+ configatron.friends.monica = 'Monica Bing'
148
+ configatron.friends.rachel.should == 'R. Green'
149
+ configatron.friends.ross.should == 'Ross Gellar'
150
+ configatron.friends.monica.should == 'Monica Bing'
151
+ end
152
+
153
+ it 'should return the Configatron instance' do
154
+ configatron.should be_is_a(Configatron)
155
+ end
156
+
157
+ describe 'to_hash' do
158
+
159
+ it 'should return a hash of all the params' do
160
+ configatron.one = 1
161
+ configatron.letters.a = 'A'
162
+ configatron.letters.b = 'B'
163
+ configatron.to_hash.should == {:one => 1, :letters => {:a => 'A', :b => 'B'}}
164
+ end
165
+
166
+ end
167
+
168
+ describe 'inspect' do
169
+
170
+ it 'should call return the inspect method of the to_hash method' do
171
+ configatron.one = 1
172
+ configatron.letters.a = 'A'
173
+ configatron.letters.b = 'B'
174
+ configatron.inspect.should == {:one => 1, :letters => {:a => 'A', :b => 'B'}}.inspect
175
+ end
176
+
177
+ end
178
+
179
+ describe 'nil?' do
180
+
181
+ it 'should return true if there are no parameters' do
182
+ configatron.should be_nil
183
+ configatron.friends.should be_nil
184
+ end
185
+
186
+ it 'should return true if there are no parameters on a nested parameter' do
187
+ configatron.friends.monica.should be_nil
188
+ end
189
+
190
+ end
191
+
192
+ describe 'retrieve' do
193
+
194
+ it 'should retrieve a parameter' do
195
+ configatron.office = 'Michael'
196
+ configatron.retrieve(:office).should == 'Michael'
197
+ end
198
+
199
+ it 'should return the optional second parameter if the config setting is nil' do
200
+ configatron.retrieve(:office, 'Stanley').should == 'Stanley'
201
+ end
202
+
203
+ it 'should work with a symbol or a string' do
204
+ configatron.office = 'Michael'
205
+ configatron.retrieve(:office).should == 'Michael'
206
+ configatron.retrieve('office').should == 'Michael'
207
+ end
208
+
209
+ it 'should work on nested parameters' do
210
+ configatron.the.office = 'Michael'
211
+ configatron.the.retrieve(:office).should == 'Michael'
212
+ configatron.the.retrieve('office').should == 'Michael'
213
+ end
214
+
215
+ end
216
+
217
+ describe 'remove' do
218
+
219
+ it 'should remove a parameter' do
220
+ configatron.movies = 'Pulp Fiction'
221
+ configatron.movies.should == 'Pulp Fiction'
222
+ configatron.remove(:movies)
223
+ configatron.movies.should be_nil
224
+ end
225
+
226
+ it 'should remove a nested parameter' do
227
+ configatron.the.movies = 'Pulp Fiction'
228
+ configatron.the.movies.should == 'Pulp Fiction'
229
+ configatron.the.remove(:movies)
230
+ configatron.the.movies.should be_nil
231
+ end
232
+
233
+ it 'should work with a symbol or a string' do
234
+ configatron.the.movies = 'Pulp Fiction'
235
+ configatron.the.office = 'Michael'
236
+ configatron.the.remove(:movies)
237
+ configatron.the.movies.should be_nil
238
+ configatron.the.remove('office')
239
+ configatron.the.office.should be_nil
240
+ end
241
+
242
+ it 'should remove all sub-parameters' do
243
+ configatron.the.movies = 'Pulp Fiction'
244
+ configatron.the.office = 'Michael'
245
+ configatron.remove(:the)
246
+ configatron.the.should be_nil
247
+ configatron.the.movies.should be_nil
248
+ end
249
+
250
+ end
251
+
252
+ describe 'set_default' do
253
+
254
+ it 'should set a default parameter value' do
255
+ configatron.set_default(:movies, 'Pulp Fiction')
256
+ configatron.movies.should == 'Pulp Fiction'
257
+ end
258
+
259
+ it 'should set a default parameter value for a nested parameter' do
260
+ configatron.the.set_default(:movies, 'Pulp Fiction')
261
+ configatron.the.movies.should == 'Pulp Fiction'
262
+ end
263
+
264
+ it 'should not set the parameter if it is already set' do
265
+ configatron.movies = 'Transformers'
266
+ configatron.set_default(:movies, 'Pulp Fiction')
267
+ configatron.movies.should == 'Transformers'
268
+ end
269
+
270
+ it 'should not set the nested parameter if it is already set' do
271
+ configatron.the.movies = 'Transformers'
272
+ configatron.the.set_default(:movies, 'Pulp Fiction')
273
+ configatron.the.movies.should == 'Transformers'
274
+ end
275
+
276
+ end
277
+
278
+ describe 'reset!' do
279
+
280
+ it 'should clear out all parameter' do
281
+ configatron.one = 1
282
+ configatron.letters.a = 'A'
283
+ configatron.letters.b = 'B'
284
+ configatron.one.should == 1
285
+ configatron.letters.a.should == 'A'
286
+ configatron.reset!
287
+ configatron.one.should be_nil
288
+ configatron.letters.a.should be_nil
289
+ end
290
+
291
+ end
292
+
293
+ end