configatron 2.13.0 → 3.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +0 -0
- data/.rvmrc +0 -1
- data/.travis.yml +5 -2
- data/Gemfile +5 -1
- data/Gemfile.lock +30 -13
- data/Guardfile +24 -0
- data/LICENSE.txt +22 -0
- data/README.md +122 -112
- data/Rakefile +6 -4
- data/V2-README.md +243 -0
- data/configatron.gemspec +4 -31
- data/lib/configatron/core.rb +3 -94
- data/lib/configatron/deep_clone.rb +69 -0
- data/lib/configatron/errors.rb +5 -9
- data/lib/configatron/rails.rb +8 -8
- data/lib/configatron/store.rb +66 -339
- data/lib/configatron/version.rb +1 -1
- data/lib/configatron.rb +8 -16
- data/lib/generators/configatron/install/install_generator.rb +0 -0
- data/lib/generators/configatron/install/templates/configatron/defaults.rb +0 -0
- data/lib/generators/configatron/install/templates/configatron/development.rb +0 -0
- data/lib/generators/configatron/install/templates/configatron/production.rb +0 -0
- data/lib/generators/configatron/install/templates/configatron/test.rb +0 -0
- data/lib/generators/configatron/install/templates/initializers/configatron.rb +0 -0
- data/test/configatron/store_test.rb +191 -0
- data/test/configatron_test.rb +5 -0
- data/test/test_helper.rb +14 -0
- metadata +27 -54
- data/LICENSE +0 -21
- data/lib/configatron/core_ext/class.rb +0 -25
- data/lib/configatron/core_ext/kernel.rb +0 -8
- data/lib/configatron/core_ext/object.rb +0 -13
- data/lib/configatron/core_ext/string.rb +0 -90
- data/lib/configatron/proc.rb +0 -104
- data/spec/configatron/proc_spec.rb +0 -67
- data/spec/configatron/rails_spec.rb +0 -66
- data/spec/lib/class_spec.rb +0 -46
- data/spec/lib/complex.yml +0 -13
- data/spec/lib/configatron_spec.rb +0 -630
- data/spec/lib/futurama.yml +0 -6
- data/spec/lib/lost.yml +0 -14
- data/spec/lib/math.yml +0 -2
- data/spec/lib/merge.yml +0 -14
- data/spec/spec_helper.rb +0 -4
- data/spec/support/rails.rb +0 -7
data/lib/configatron/store.rb
CHANGED
@@ -1,373 +1,100 @@
|
|
1
|
-
|
2
|
-
class Store
|
3
|
-
if RUBY_VERSION.match(/^1\.9\.[^1]/)
|
4
|
-
require 'syck'
|
5
|
-
::YAML::ENGINE.yamler = 'syck' unless RUBY_PLATFORM == 'java'
|
6
|
-
end
|
7
|
-
|
8
|
-
alias_method :send!, :send
|
9
|
-
|
10
|
-
# Takes an optional Hash of parameters
|
11
|
-
def initialize(options = {}, name = nil, parent = nil)
|
12
|
-
@_name = name
|
13
|
-
@_parent = parent
|
14
|
-
@_store = {}
|
15
|
-
configure_from_hash(options)
|
16
|
-
@_protected = []
|
17
|
-
@_locked = false
|
18
|
-
end
|
19
|
-
|
20
|
-
def [](key)
|
21
|
-
method_missing(key.to_sym)
|
22
|
-
end
|
23
|
-
|
24
|
-
def []=(key, value)
|
25
|
-
method_missing(:"#{key}=", value)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns a Hash representing the configurations
|
29
|
-
def to_hash
|
30
|
-
h = Hash.new
|
31
|
-
@_store.each { |k,v|
|
32
|
-
# Descend the tree and hashify each node
|
33
|
-
h[k] = v.is_a?(Store) ? v.to_hash : v
|
34
|
-
}
|
35
|
-
h
|
36
|
-
end
|
1
|
+
require 'forwardable'
|
37
2
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
until parent.nil?
|
42
|
-
path << parent.instance_variable_get('@_name')
|
43
|
-
parent = parent.instance_variable_get('@_parent')
|
44
|
-
end
|
45
|
-
path.compact!
|
46
|
-
path.reverse!
|
47
|
-
path.join('.')
|
48
|
-
end
|
49
|
-
|
50
|
-
def configatron_keys
|
51
|
-
return @_store.keys.collect{|k| k.to_s}.sort
|
52
|
-
end
|
3
|
+
class Configatron
|
4
|
+
class Store# < BasicObject
|
5
|
+
extend ::Forwardable
|
53
6
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
# configatron.i.am.exists?(:alive) # => true
|
59
|
-
# configatron.i.am.exists?(:dead) # => false
|
60
|
-
def exists?(name)
|
61
|
-
@_store.has_key?(name.to_sym) || @_store.has_key?(name.to_s)
|
7
|
+
def initialize(attributes = {})
|
8
|
+
@__locked = false
|
9
|
+
@attributes = attributes || {}
|
10
|
+
@attributes.send(:extend, DeepClone)
|
62
11
|
end
|
63
12
|
|
64
|
-
|
65
|
-
|
66
|
-
exists?(name) || super
|
13
|
+
def lock!
|
14
|
+
@__locked = true
|
67
15
|
end
|
68
16
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
if v.is_a?(Configatron::Store)
|
74
|
-
v.inspect.each_line do |line|
|
75
|
-
if line.match(/\n/)
|
76
|
-
line.each_line do |l|
|
77
|
-
l.strip!
|
78
|
-
f_out << l
|
79
|
-
end
|
80
|
-
else
|
81
|
-
line.strip!
|
82
|
-
f_out << line
|
83
|
-
end
|
84
|
-
end
|
85
|
-
else
|
86
|
-
f_out << "#{name}.#{k} = #{v.inspect}"
|
17
|
+
def [](key)
|
18
|
+
fetch(key.to_sym) do
|
19
|
+
if @__locked
|
20
|
+
raise Configatron::UndefinedKeyError.new("Key Not Found: #{key}")
|
87
21
|
end
|
22
|
+
::Configatron::Store.new
|
88
23
|
end
|
89
|
-
f_out.compact.sort.join("\n")
|
90
24
|
end
|
91
25
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
# Allows for the configuration of the system from a YAML file.
|
98
|
-
# Takes the path to the YAML file. Also takes an optional parameter,
|
99
|
-
# <tt>:hash</tt>, that indicates a specific hash that should be
|
100
|
-
# loaded from the file.
|
101
|
-
def configure_from_yaml(path, opts = {})
|
102
|
-
Configatron.log.warn "DEPRECATED! (configure_from_yaml) Please stop using YAML and use Ruby instead. This method will be removed in 3.1."
|
103
|
-
begin
|
104
|
-
yml = ::Yamler.load(path)
|
105
|
-
yml = yml[opts[:hash]] unless opts[:hash].nil?
|
106
|
-
configure_from_hash(yml)
|
107
|
-
rescue Errno::ENOENT => e
|
108
|
-
puts e.message
|
26
|
+
def store(key, value)
|
27
|
+
if @__locked
|
28
|
+
raise Configatron::LockedError.new("Locked! Can not set key #{key}!")
|
109
29
|
end
|
30
|
+
@attributes[key.to_sym] = value
|
110
31
|
end
|
111
32
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
value.respond_to?(:empty?) ? value.empty? : !value
|
120
|
-
end
|
121
|
-
|
122
|
-
# Retrieves a certain parameter and if that parameter
|
123
|
-
# doesn't exist it will return the default_value specified.
|
124
|
-
def retrieve(name, default_value = nil)
|
125
|
-
val = method_missing(name.to_sym)
|
126
|
-
return val.is_a?(Configatron::Store) ? default_value : val
|
127
|
-
end
|
128
|
-
|
129
|
-
# Removes a parameter. In the case of a nested parameter
|
130
|
-
# it will remove all below it.
|
131
|
-
def remove(name)
|
132
|
-
@_store.delete(name.to_sym)
|
133
|
-
end
|
134
|
-
|
135
|
-
# Sets a 'default' value. If there is already a value specified
|
136
|
-
# it won't set the value.
|
137
|
-
def set_default(name, default_value)
|
138
|
-
unless @_store[name.to_sym]
|
139
|
-
# @_store[name.to_sym] = parse_options(default_value)
|
140
|
-
self.send("#{name}=", default_value)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
def method_missing(sym, *args) # :nodoc:
|
145
|
-
if sym.to_s.match(/(.+)=$/)
|
146
|
-
name = sym.to_s.gsub("=", '').to_sym
|
147
|
-
raise Configatron::ProtectedParameter.new(name) if @_protected.include?(name) || methods_include?(name)
|
148
|
-
raise Configatron::LockedNamespace.new(@_name) if @_locked && !@_store.has_key?(name)
|
149
|
-
@_store[name] = parse_options(*args)
|
150
|
-
elsif sym.to_s.match(/(.+)\?/)
|
151
|
-
object = _store_lookup($1.to_sym)
|
152
|
-
return !_object_blank?(object)
|
153
|
-
elsif block_given?
|
154
|
-
yield self.send(sym)
|
155
|
-
elsif @_store.has_key?(sym)
|
156
|
-
val = _store_lookup(sym)
|
157
|
-
if val.is_a?(Configatron::Proc)
|
158
|
-
res = val.execute
|
159
|
-
if val.finalize?
|
160
|
-
@_store[sym] = res
|
161
|
-
end
|
162
|
-
return res
|
33
|
+
def fetch(key, default_value = nil, &block)
|
34
|
+
val = @attributes[key.to_sym]
|
35
|
+
if val.nil?
|
36
|
+
if block_given?
|
37
|
+
val = block.call
|
38
|
+
elsif default_value
|
39
|
+
val = default_value
|
163
40
|
end
|
164
|
-
|
165
|
-
else
|
166
|
-
# This will error out if strict is enabled, and be a no-op
|
167
|
-
# otherwise. The nice thing is the error message will be the
|
168
|
-
# same as in the .method? case.
|
169
|
-
_store_lookup(sym)
|
170
|
-
store = Configatron::Store.new({}, sym, self)
|
171
|
-
@_store[sym] = store
|
172
|
-
return store
|
41
|
+
store(key, val)
|
173
42
|
end
|
43
|
+
return val
|
174
44
|
end
|
175
45
|
|
176
|
-
def
|
177
|
-
|
178
|
-
end
|
179
|
-
|
180
|
-
# Prevents a parameter from being reassigned. If called on a 'namespace' then
|
181
|
-
# all parameters below it will be protected as well.
|
182
|
-
def protect(name)
|
183
|
-
@_protected << name.to_sym
|
184
|
-
end
|
185
|
-
|
186
|
-
# Prevents all parameters from being reassigned.
|
187
|
-
def protect_all!
|
188
|
-
@_protected.clear
|
189
|
-
@_store.keys.each do |k|
|
190
|
-
val = self.send(k)
|
191
|
-
val.protect_all! if val.class == Configatron::Store
|
192
|
-
@_protected << k
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
# Removes the protection of a parameter.
|
197
|
-
def unprotect(name)
|
198
|
-
@_protected.reject! { |e| e == name.to_sym }
|
199
|
-
end
|
200
|
-
|
201
|
-
def unprotect_all!
|
202
|
-
@_protected.clear
|
203
|
-
@_store.keys.each do |k|
|
204
|
-
val = self.send(k)
|
205
|
-
val.unprotect_all! if val.class == Configatron::Store
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# Prevents a namespace from having new parameters set. The lock is applied
|
210
|
-
# recursively to any namespaces below it.
|
211
|
-
def lock(name)
|
212
|
-
namespace = @_store[name.to_sym]
|
213
|
-
raise ArgumentError, "Namespace #{name.inspect} does not exist" if namespace.nil?
|
214
|
-
namespace.lock!
|
46
|
+
def nil?
|
47
|
+
@attributes.empty?
|
215
48
|
end
|
216
49
|
|
217
|
-
def
|
218
|
-
|
219
|
-
|
220
|
-
namespace.unlock!
|
50
|
+
def has_key?(key)
|
51
|
+
val = self[key]
|
52
|
+
!val.is_a?(Configatron::Store)
|
221
53
|
end
|
222
54
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
#
|
228
|
-
# == Description
|
229
|
-
# Adds deep_clone method to an object which produces deep copy of it. It means
|
230
|
-
# if you clone a Hash, every nested items and their nested items will be cloned.
|
231
|
-
# Moreover deep_clone checks if the object is already cloned to prevent endless recursion.
|
232
|
-
#
|
233
|
-
# == Usage
|
234
|
-
#
|
235
|
-
# (see examples directory under the ruby gems root directory)
|
236
|
-
#
|
237
|
-
# require 'rubygems'
|
238
|
-
# require 'deep_clone'
|
239
|
-
#
|
240
|
-
# include DeepClone
|
241
|
-
#
|
242
|
-
# obj = []
|
243
|
-
# a = [ true, false, obj ]
|
244
|
-
# b = a.deep_clone
|
245
|
-
# obj.push( 'foo' )
|
246
|
-
# p obj # >> [ 'foo' ]
|
247
|
-
# p b[2] # >> []
|
248
|
-
#
|
249
|
-
# == Source
|
250
|
-
# http://simplypowerful.1984.cz/goodlibs/1.2006.05.23
|
251
|
-
#
|
252
|
-
# == Author
|
253
|
-
# jan molic (/mig/at_sign/1984/dot/cz/)
|
254
|
-
#
|
255
|
-
# == Licence
|
256
|
-
# You can redistribute it and/or modify it under the same terms of Ruby's license;
|
257
|
-
# either the dual license version in 2003, or any later version.
|
258
|
-
#
|
259
|
-
def deep_clone( obj=self, cloned={} )
|
260
|
-
if cloned.has_key?( obj.object_id )
|
261
|
-
return cloned[obj.object_id]
|
262
|
-
else
|
263
|
-
begin
|
264
|
-
cl = obj.clone
|
265
|
-
rescue Exception
|
266
|
-
# unclonnable (TrueClass, Fixnum, ...)
|
267
|
-
cloned[obj.object_id] = obj
|
268
|
-
return obj
|
55
|
+
def configure_from_hash(hash)
|
56
|
+
hash.each do |key, value|
|
57
|
+
if value.is_a?(Hash)
|
58
|
+
self[key].configure_from_hash(value)
|
269
59
|
else
|
270
|
-
|
271
|
-
cloned[cl.object_id] = cl
|
272
|
-
if cl.is_a?( Hash )
|
273
|
-
cl.clone.each { |k,v|
|
274
|
-
cl[k] = deep_clone( v, cloned )
|
275
|
-
}
|
276
|
-
elsif cl.is_a?( Array )
|
277
|
-
cl.collect! { |v|
|
278
|
-
deep_clone( v, cloned )
|
279
|
-
}
|
280
|
-
end
|
281
|
-
cl.instance_variables.each do |var|
|
282
|
-
v = cl.instance_eval( var.to_s )
|
283
|
-
v_cl = deep_clone( v, cloned )
|
284
|
-
cl.instance_eval( "#{var} = v_cl" )
|
285
|
-
end
|
286
|
-
return cl
|
60
|
+
store(key, value)
|
287
61
|
end
|
288
62
|
end
|
289
63
|
end
|
290
64
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
@
|
295
|
-
end
|
296
|
-
|
297
|
-
def unlock!
|
298
|
-
@_locked = false
|
299
|
-
@_store.values.each { |store| store.unlock! if store.is_a?(Configatron::Store) }
|
65
|
+
def temp(&block)
|
66
|
+
@__temp = @attributes.deep_clone
|
67
|
+
yield
|
68
|
+
@attributes = @__temp
|
300
69
|
end
|
301
70
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
end
|
306
|
-
|
307
|
-
def is_syck?(obj)
|
308
|
-
if defined?(SYCK_CONSTANT)
|
309
|
-
Configatron.log.warn "DEPRECATED! (SYCK) Syck support has been removed from Configatron in Ruby 2.x. This feature will be removed entirely in Configatron 3.0. Please be advised."
|
310
|
-
return obj.is_a?(SYCK_CONSTANT)
|
311
|
-
end
|
312
|
-
return false
|
313
|
-
end
|
314
|
-
|
315
|
-
def parse_options(options)
|
316
|
-
if options.is_a?(Hash)
|
317
|
-
options.each do |k,v|
|
318
|
-
if v.is_a?(Hash)
|
319
|
-
if v.keys.length == 1 && is_syck?(v.keys.first)
|
320
|
-
self.method_missing("#{k}=", v.values.first.flatten)
|
321
|
-
else
|
322
|
-
self.method_missing(k.to_sym).configure_from_hash(v)
|
323
|
-
end
|
324
|
-
else
|
325
|
-
self.method_missing("#{k}=", v)
|
326
|
-
end
|
327
|
-
end
|
71
|
+
def method_missing(name, *args, &block)
|
72
|
+
if block_given?
|
73
|
+
yield self[name]
|
328
74
|
else
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
parent = @_parent
|
336
|
-
until parent.nil?
|
337
|
-
path << parent.instance_variable_get('@_name')
|
338
|
-
parent = parent.instance_variable_get('@_parent')
|
339
|
-
end
|
340
|
-
path << 'configatron'
|
341
|
-
path.compact!
|
342
|
-
path.reverse!
|
343
|
-
path.join('.')
|
344
|
-
end
|
345
|
-
|
346
|
-
# Give it this awkward name to hopefully avoid config keys people
|
347
|
-
# are using.
|
348
|
-
def _store_lookup(sym)
|
349
|
-
begin
|
350
|
-
@_store.fetch(sym)
|
351
|
-
rescue IndexError => e
|
352
|
-
raise e.class.new("#{e.message} (for #{_store_name})") if Configatron.strict
|
353
|
-
nil
|
75
|
+
name = name.to_s
|
76
|
+
if /(.+)=$/.match(name)
|
77
|
+
return store($1, args[0])
|
78
|
+
else
|
79
|
+
return self[name]
|
80
|
+
end
|
354
81
|
end
|
355
82
|
end
|
356
83
|
|
357
|
-
|
358
|
-
|
359
|
-
end
|
360
|
-
|
361
|
-
begin
|
362
|
-
undef :test # :nodoc:
|
363
|
-
rescue Exception => e
|
364
|
-
end
|
84
|
+
alias :[]= :store
|
85
|
+
alias :blank? :nil?
|
365
86
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
87
|
+
def_delegator :@attributes, :values
|
88
|
+
def_delegator :@attributes, :keys
|
89
|
+
def_delegator :@attributes, :each
|
90
|
+
def_delegator :@attributes, :empty?
|
91
|
+
def_delegator :@attributes, :inspect
|
92
|
+
def_delegator :@attributes, :to_h
|
93
|
+
def_delegator :@attributes, :to_hash
|
94
|
+
def_delegator :@attributes, :delete
|
95
|
+
# def_delegator :@attributes, :fetch
|
96
|
+
# def_delegator :@attributes, :has_key?
|
97
|
+
# def_delegator :$stdout, :puts
|
371
98
|
|
372
|
-
end
|
373
|
-
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/configatron/version.rb
CHANGED
data/lib/configatron.rb
CHANGED
@@ -1,17 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
# do so, no `configatron` top-level method will be defined for
|
5
|
-
# you. You can access the configatron object by Configatron.instance.
|
1
|
+
require "configatron/version"
|
2
|
+
require "configatron/core"
|
3
|
+
require "configatron/rails"
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
require File.join(base, 'core_ext', 'kernel')
|
15
|
-
require File.join(base, 'core_ext', 'object')
|
16
|
-
require File.join(base, 'core_ext', 'string')
|
17
|
-
require File.join(base, 'core_ext', 'class')
|
5
|
+
module Kernel
|
6
|
+
def configatron
|
7
|
+
@__configatron ||= Configatron::Store.new
|
8
|
+
end
|
9
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Configatron::Store do
|
4
|
+
|
5
|
+
let(:store) { Configatron::Store.new }
|
6
|
+
|
7
|
+
context "[]" do
|
8
|
+
|
9
|
+
let(:store) { Configatron::Store.new(foo: "bar") }
|
10
|
+
|
11
|
+
it "returns the value if there is one" do
|
12
|
+
store[:foo].must_equal "bar"
|
13
|
+
store["foo"].must_equal "bar"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns a new Configatron::Store object if there is no value" do
|
17
|
+
store[:unknown].must_be_kind_of Configatron::Store
|
18
|
+
store["unknown"].must_be_kind_of Configatron::Store
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
context "[]=" do
|
24
|
+
|
25
|
+
it "sets the value" do
|
26
|
+
store[:foo] = "bar"
|
27
|
+
store[:foo].must_equal "bar"
|
28
|
+
store["foo"].must_equal "bar"
|
29
|
+
|
30
|
+
store[:baz] = "bazzy"
|
31
|
+
store[:baz].must_equal "bazzy"
|
32
|
+
store["baz"].must_equal "bazzy"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
context "fetch" do
|
38
|
+
|
39
|
+
let(:store) { Configatron::Store.new(foo: "bar") }
|
40
|
+
|
41
|
+
it "returns the value" do
|
42
|
+
store.fetch(:foo).must_equal "bar"
|
43
|
+
store.fetch("foo").must_equal "bar"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "sets and returns the value of the default_value if no value is found" do
|
47
|
+
store.fetch(:bar, "bar!!").must_equal "bar!!"
|
48
|
+
store.bar.must_equal "bar!!"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "sets and returns the value of the block if no value is found" do
|
52
|
+
store.fetch(:bar) do
|
53
|
+
"bar!"
|
54
|
+
end.must_equal "bar!"
|
55
|
+
store.bar.must_equal "bar!"
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
context "nil?" do
|
61
|
+
|
62
|
+
it "returns true if there is no value set" do
|
63
|
+
store.foo.must_be_nil
|
64
|
+
store.foo = "bar"
|
65
|
+
store.foo.wont_be_nil
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
context "empty?" do
|
71
|
+
|
72
|
+
it "returns true if there is no value set" do
|
73
|
+
store.foo.must_be_empty
|
74
|
+
store.foo = "bar"
|
75
|
+
store.foo.wont_be_empty
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
context "has_key?" do
|
81
|
+
|
82
|
+
it "returns true if there is a key" do
|
83
|
+
store.has_key?(:foo).must_equal false
|
84
|
+
store.foo = "bar"
|
85
|
+
store.has_key?(:foo).must_equal true
|
86
|
+
end
|
87
|
+
|
88
|
+
it "returns false if the key is a Configatron::Store" do
|
89
|
+
store.has_key?(:foo).must_equal false
|
90
|
+
store.foo = Configatron::Store.new
|
91
|
+
store.has_key?(:foo).must_equal false
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
context "method_missing" do
|
97
|
+
|
98
|
+
let(:store) { Configatron::Store.new(foo: "bar") }
|
99
|
+
|
100
|
+
it "returns the value if there is one" do
|
101
|
+
store.foo.must_equal "bar"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "returns a Configatron::Store if there is no value" do
|
105
|
+
store.bar.must_be_kind_of Configatron::Store
|
106
|
+
end
|
107
|
+
|
108
|
+
it "works with deeply nested values" do
|
109
|
+
store.a.b.c.d = "DD"
|
110
|
+
store.a.b.c.d.must_equal "DD"
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
context "lock!" do
|
116
|
+
|
117
|
+
before do
|
118
|
+
store.a.b.c.d = 'DD'
|
119
|
+
store.lock!
|
120
|
+
end
|
121
|
+
|
122
|
+
it "raises an error when accessing non-existing values" do
|
123
|
+
store.a.wont_be_nil
|
124
|
+
store.a.b.wont_be_nil
|
125
|
+
store.a.b.c.wont_be_nil
|
126
|
+
store.a.b.c.d.must_equal "DD"
|
127
|
+
proc {store.unknown}.must_raise(Configatron::UndefinedKeyError)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "raises an error when trying to set a non-existing key" do
|
131
|
+
proc {store.unknown = "known"}.must_raise(Configatron::LockedError)
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
context "temp" do
|
137
|
+
|
138
|
+
before do
|
139
|
+
store.a = 'A'
|
140
|
+
store.b = 'B'
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
it "allows for temporary setting of values" do
|
145
|
+
store.a.must_equal 'A'
|
146
|
+
store.b.must_equal 'B'
|
147
|
+
store.temp do
|
148
|
+
store.a = 'AA'
|
149
|
+
store.c = 'C'
|
150
|
+
store.a.must_equal 'AA'
|
151
|
+
store.b.must_equal 'B'
|
152
|
+
store.c.must_equal 'C'
|
153
|
+
end
|
154
|
+
store.a.must_equal 'A'
|
155
|
+
store.b.must_equal 'B'
|
156
|
+
store.c.must_be_nil
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
context "configuring" do
|
162
|
+
|
163
|
+
context "configure_from_hash" do
|
164
|
+
|
165
|
+
it "allows setup from a hash" do
|
166
|
+
store.configure_from_hash(one: 1, a: {b: {c: {d: "DD"}}})
|
167
|
+
store.one.must_equal 1
|
168
|
+
store.a.b.c.d.must_equal "DD"
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
context "with a block" do
|
174
|
+
|
175
|
+
before do
|
176
|
+
store.a.b = 'B'
|
177
|
+
end
|
178
|
+
|
179
|
+
it "yields up the store to configure with" do
|
180
|
+
store.a do |a|
|
181
|
+
a.c = 'CC'
|
182
|
+
end
|
183
|
+
store.a.b.must_equal 'B'
|
184
|
+
store.a.c.must_equal 'CC'
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
data/test/test_helper.rb
ADDED