configliere 0.4.5 → 0.4.6
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/FEATURES.txt +60 -16
- data/VERSION +1 -1
- data/configliere.gemspec +2 -2
- data/lib/configliere/config_file.rb +6 -2
- data/lib/configliere/deep_hash.rb +45 -30
- data/spec/configliere/config_file_spec.rb +24 -19
- data/spec/configliere/deep_hash_spec.rb +205 -62
- metadata +3 -3
data/FEATURES.txt
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
Configliere::Commandline
|
2
3
|
with long-format argvs
|
3
4
|
accepts --param=val pairs
|
@@ -26,6 +27,8 @@ Configliere::Commandline
|
|
26
27
|
exports dashed flags
|
27
28
|
#resolve!
|
28
29
|
calls super and returns self
|
30
|
+
#validate!
|
31
|
+
calls super and returns self
|
29
32
|
|
30
33
|
Configliere::Commands
|
31
34
|
when no commands are defined
|
@@ -45,13 +48,16 @@ Configliere::Commands
|
|
45
48
|
displays the commands and their descriptions
|
46
49
|
#resolve!
|
47
50
|
calls super and returns self
|
51
|
+
#validate!
|
52
|
+
calls super and returns self
|
48
53
|
|
49
54
|
Configliere::ConfigBlock
|
50
55
|
resolving
|
51
56
|
runs blocks
|
52
57
|
resolves blocks last
|
53
|
-
|
54
|
-
|
58
|
+
calls super and returns self
|
59
|
+
#validate!
|
60
|
+
calls super and returns self
|
55
61
|
|
56
62
|
Configliere::ConfigFile
|
57
63
|
is used by default
|
@@ -62,24 +68,29 @@ Configliere::ConfigFile
|
|
62
68
|
with an absolute pathname uses it directly
|
63
69
|
with a simple filename, references it to the default config dir
|
64
70
|
returns the config object for chaining
|
71
|
+
#read_yaml
|
72
|
+
loads yaml
|
65
73
|
with an environment scope
|
66
74
|
slices out a subhash given by :env
|
67
75
|
slices out a different subhash with a different :env
|
68
76
|
does no slicing without the :env option
|
69
77
|
has no effect if the key given by :env option is absent
|
70
|
-
|
78
|
+
lets you use a string if the loading hash has a string
|
71
79
|
saves to a config file
|
72
80
|
with an absolute pathname, as given
|
73
81
|
with a simple pathname, in the default config dir
|
74
82
|
and ensures the directory exists
|
75
83
|
#resolve!
|
76
84
|
calls super and returns self
|
85
|
+
#validate!
|
86
|
+
calls super and returns self
|
77
87
|
|
78
88
|
Crypter
|
79
89
|
encrypts
|
80
90
|
decrypts
|
81
91
|
|
82
92
|
DeepHash
|
93
|
+
responds to #symbolize_keys, #symbolize_keys! and #stringify_keys but not #stringify_keys!
|
83
94
|
#initialize
|
84
95
|
adopts a Hash when given
|
85
96
|
converts all pure Hash values into DeepHashes if param is a Hash
|
@@ -120,32 +131,58 @@ DeepHash
|
|
120
131
|
gets values for all given keys even if missing
|
121
132
|
is OK when empty
|
122
133
|
returns an instance of the same class
|
123
|
-
assert_valid_keys
|
124
|
-
is true and does not raise when valid
|
125
|
-
fails when invalid
|
126
134
|
#delete
|
127
135
|
converts Symbol key into String before deleting
|
128
136
|
works with String keys as well
|
129
|
-
#merge
|
130
|
-
returns instance of DeepHash
|
131
|
-
merges in give Hash
|
132
137
|
#fetch
|
133
138
|
converts key before fetching
|
134
139
|
returns alternative value if key lookup fails
|
135
140
|
#values_at
|
136
141
|
is indifferent to whether keys are strings or symbols
|
137
142
|
#symbolize_keys
|
138
|
-
with bang returns the deep_hash itself
|
139
143
|
returns a dup of itself
|
144
|
+
#symbolize_keys!
|
145
|
+
with bang returns the deep_hash itself
|
146
|
+
#stringify_keys
|
147
|
+
converts keys that are all symbols
|
148
|
+
returns a Hash, not a DeepHash
|
149
|
+
only stringifies and hashifies the top level
|
150
|
+
#assert_valid_keys
|
151
|
+
is true and does not raise when valid
|
152
|
+
fails when invalid
|
153
|
+
#merge
|
154
|
+
merges given Hash
|
155
|
+
returns a new instance
|
156
|
+
returns instance of DeepHash
|
157
|
+
converts all Hash values into DeepHashes
|
158
|
+
converts string keys to symbol keys even if they occur deep in the given hash
|
159
|
+
DOES merge values where given hash has nil value
|
160
|
+
replaces child hashes, and does not merge them
|
161
|
+
#merge!
|
162
|
+
merges given Hash
|
163
|
+
returns a new instance
|
164
|
+
returns instance of DeepHash
|
165
|
+
converts all Hash values into DeepHashes
|
166
|
+
converts string keys to symbol keys even if they occur deep in the given hash
|
167
|
+
DOES merge values where given hash has nil value
|
168
|
+
replaces child hashes, and does not merge them
|
140
169
|
#reverse_merge
|
141
|
-
merges
|
142
|
-
|
170
|
+
merges given Hash
|
171
|
+
returns a new instance
|
172
|
+
returns instance of DeepHash
|
173
|
+
converts all Hash values into DeepHashes
|
174
|
+
converts string keys to symbol keys even if they occur deep in the given hash
|
175
|
+
DOES merge values where given hash has nil value
|
176
|
+
replaces child hashes, and does not merge them
|
143
177
|
#deep_merge!
|
144
178
|
merges two subhashes when they share a key
|
145
179
|
merges two subhashes when they share a symbolized key
|
146
180
|
preserves values in the original
|
147
|
-
|
148
|
-
|
181
|
+
converts all Hash values into DeepHashes
|
182
|
+
converts string keys to symbol keys even if they occur deep in the given hash
|
183
|
+
replaces values from the given hash
|
184
|
+
replaces arrays and does not append to them
|
185
|
+
does not replaces values where given hash has nil value
|
149
186
|
#deep_set
|
150
187
|
should set a new value (single arg)
|
151
188
|
should set a new value (multiple args)
|
@@ -164,6 +201,7 @@ Configliere::Define
|
|
164
201
|
takes a description
|
165
202
|
defining any aspect of a param
|
166
203
|
adopts values
|
204
|
+
returns self
|
167
205
|
merges new definitions
|
168
206
|
lists params defined as the given aspect
|
169
207
|
definition_of
|
@@ -237,6 +275,8 @@ Configliere::Define
|
|
237
275
|
type converts
|
238
276
|
#resolve!
|
239
277
|
calls super and returns self
|
278
|
+
#validate!
|
279
|
+
calls super and returns self
|
240
280
|
|
241
281
|
Configliere::Encrypted
|
242
282
|
defines encrypted params
|
@@ -257,6 +297,8 @@ Configliere::Encrypted
|
|
257
297
|
#resolve!
|
258
298
|
calls super and returns self
|
259
299
|
removes the encrypt_pass from sight
|
300
|
+
#validate!
|
301
|
+
calls super and returns self
|
260
302
|
|
261
303
|
Configliere::EnvVar
|
262
304
|
environment variables can be defined
|
@@ -265,6 +307,8 @@ Configliere::EnvVar
|
|
265
307
|
with #define
|
266
308
|
#resolve!
|
267
309
|
calls super and returns self
|
310
|
+
#validate!
|
311
|
+
calls super and returns self
|
268
312
|
|
269
313
|
Configliere::Param
|
270
314
|
calling #defaults
|
@@ -294,5 +338,5 @@ Configliere
|
|
294
338
|
creates a global method Settings, so you can say Settings(:foo => :bar)
|
295
339
|
requires corresponding plugins when you call use
|
296
340
|
|
297
|
-
Finished in 0.
|
298
|
-
|
341
|
+
Finished in 0.61948 seconds
|
342
|
+
247 examples, 0 failures
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.6
|
data/configliere.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{configliere}
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["infochimps", "mrflip"]
|
12
|
-
s.date = %q{2011-05-
|
12
|
+
s.date = %q{2011-05-21}
|
13
13
|
s.description = %q{ You've got a script. It's got some settings. Some settings are for this module, some are for that module. Most of them don't change. Except on your laptop, where the paths are different. Or when you're in production mode. Or when you're testing from the command line.
|
14
14
|
|
15
15
|
"" So, Consigliere of mine, I think you should tell your Don what everyone knows. "" -- Don Corleone
|
@@ -30,11 +30,15 @@ module Configliere
|
|
30
30
|
if filename.is_a?(Symbol) then raise Configliere::DeprecatedError, "Loading from a default config file is no longer provided" ; end
|
31
31
|
filename = expand_filename(filename)
|
32
32
|
begin
|
33
|
-
|
33
|
+
read_yaml(File.open(filename), options)
|
34
34
|
rescue Errno::ENOENT => e
|
35
35
|
warn "Loading empty configliere settings file #{filename}"
|
36
|
-
new_data = {}
|
37
36
|
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def read_yaml yaml_str, options={}
|
41
|
+
new_data = YAML.load(yaml_str) || {}
|
38
42
|
# Extract the :env (production/development/etc)
|
39
43
|
if options[:env]
|
40
44
|
new_data = new_data[options[:env]] || {}
|
@@ -73,8 +73,6 @@ class DeepHash < Hash
|
|
73
73
|
self.dup.update(hash, &block)
|
74
74
|
end
|
75
75
|
|
76
|
-
alias_method :merge!, :update
|
77
|
-
|
78
76
|
# @param other_hash<Hash>
|
79
77
|
# A hash to update values in the deep_hash with. The keys and the values will be
|
80
78
|
# converted to DeepHash format.
|
@@ -89,17 +87,58 @@ class DeepHash < Hash
|
|
89
87
|
regular_update(deep_hash, &block)
|
90
88
|
end
|
91
89
|
|
92
|
-
|
93
|
-
|
90
|
+
alias_method :merge!, :update
|
91
|
+
|
92
|
+
# Allows for reverse merging two hashes where the keys in the calling hash take precedence over those
|
93
|
+
# in the <tt>other_hash</tt>. This is particularly useful for initializing an option hash with default values:
|
94
|
+
#
|
95
|
+
# def setup(options = {})
|
96
|
+
# options.reverse_merge! :size => 25, :velocity => 10
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# Using <tt>merge</tt>, the above example would look as follows:
|
100
|
+
#
|
101
|
+
# def setup(options = {})
|
102
|
+
# { :size => 25, :velocity => 10 }.merge(options)
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# The default <tt>:size</tt> and <tt>:velocity</tt> are only set if the +options+ hash passed in doesn't already
|
106
|
+
# have the respective key.
|
107
|
+
def reverse_merge(other_hash)
|
108
|
+
self.class.new(other_hash).merge!(self)
|
109
|
+
end unless method_defined?(:reverse_merge)
|
110
|
+
|
111
|
+
# Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
|
112
|
+
# Modifies the receiver in place.
|
113
|
+
def reverse_merge!(other_hash)
|
114
|
+
merge!( other_hash ){|k,o,n| convert_value(o) }
|
115
|
+
end unless method_defined?(:reverse_merge!)
|
116
|
+
|
117
|
+
# This DeepHash with all its keys converted to symbols, as long as they
|
118
|
+
# respond to +to_sym+. (this is always true for a deep_hash)
|
119
|
+
#
|
120
|
+
# @return [DeepHash] A copy of this deep_hash.
|
94
121
|
def symbolize_keys
|
95
122
|
dup.symbolize_keys!
|
96
123
|
end unless method_defined?(:symbolize_keys)
|
97
124
|
|
98
|
-
#
|
125
|
+
# This DeepHash with all its keys converted to symbols, as long as they
|
126
|
+
# respond to +to_sym+. (this is always true for a deep_hash)
|
99
127
|
#
|
100
128
|
# @return [DeepHash] This deep_hash unchanged.
|
101
129
|
def symbolize_keys!; self end
|
102
130
|
|
131
|
+
# Return a new hash with all top-level keys converted to strings.
|
132
|
+
#
|
133
|
+
# @return [Hash]
|
134
|
+
def stringify_keys
|
135
|
+
hsh = Hash.new(default)
|
136
|
+
self.each do |key, val|
|
137
|
+
hsh[key.to_s] = val
|
138
|
+
end
|
139
|
+
hsh
|
140
|
+
end
|
141
|
+
|
103
142
|
#
|
104
143
|
# remove all key-value pairs where the value is nil
|
105
144
|
#
|
@@ -112,6 +151,7 @@ class DeepHash < Hash
|
|
112
151
|
def compact!
|
113
152
|
replace(compact)
|
114
153
|
end
|
154
|
+
|
115
155
|
# Slice a hash to include only the given keys. This is useful for
|
116
156
|
# limiting an options hash to valid keys before passing to a method:
|
117
157
|
#
|
@@ -163,31 +203,6 @@ class DeepHash < Hash
|
|
163
203
|
result
|
164
204
|
end unless method_defined?(:extract!)
|
165
205
|
|
166
|
-
# Allows for reverse merging two hashes where the keys in the calling hash take precedence over those
|
167
|
-
# in the <tt>other_hash</tt>. This is particularly useful for initializing an option hash with default values:
|
168
|
-
#
|
169
|
-
# def setup(options = {})
|
170
|
-
# options.reverse_merge! :size => 25, :velocity => 10
|
171
|
-
# end
|
172
|
-
#
|
173
|
-
# Using <tt>merge</tt>, the above example would look as follows:
|
174
|
-
#
|
175
|
-
# def setup(options = {})
|
176
|
-
# { :size => 25, :velocity => 10 }.merge(options)
|
177
|
-
# end
|
178
|
-
#
|
179
|
-
# The default <tt>:size</tt> and <tt>:velocity</tt> are only set if the +options+ hash passed in doesn't already
|
180
|
-
# have the respective key.
|
181
|
-
def reverse_merge(other_hash)
|
182
|
-
other_hash.merge(self)
|
183
|
-
end unless method_defined?(:reverse_merge)
|
184
|
-
|
185
|
-
# Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
|
186
|
-
# Modifies the receiver in place.
|
187
|
-
def reverse_merge!(other_hash)
|
188
|
-
merge!( other_hash ){|k,o,n| o }
|
189
|
-
end unless method_defined?(:reverse_merge!)
|
190
|
-
|
191
206
|
# Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
|
192
207
|
# Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
|
193
208
|
# as keys, this will fail.
|
@@ -45,57 +45,62 @@ describe Configliere::ConfigFile do
|
|
45
45
|
@config.should_receive(:warn).with("Loading empty configliere settings file #{Configliere::DEFAULT_CONFIG_DIR}/nonexistent_file.yaml")
|
46
46
|
@config.read('nonexistent_file.yaml').should == {}
|
47
47
|
end
|
48
|
+
end
|
48
49
|
|
50
|
+
describe '#read_yaml' do
|
51
|
+
before do
|
52
|
+
@config.merge! :reload => :whatever
|
53
|
+
@simple_yaml = { :my_param => 'override_val', 'also_a_param' => true, 'strkey' => 'val', :falsekey => false, :nilkey => nil }.to_yaml
|
54
|
+
@yaml_with_subenvs = { :development => { :reload => true }, :production => { :reload => false }}.to_yaml
|
55
|
+
end
|
49
56
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
YAML.should_receive(:load).and_return(@hash_with_subenvs)
|
56
|
-
end
|
57
|
+
it 'loads yaml' do
|
58
|
+
@config.read_yaml(@simple_yaml)
|
59
|
+
@config.should == { :reload => :whatever, :my_param => 'override_val', :also_a_param => true, :strkey => 'val', :falsekey => false, :nilkey => nil }
|
60
|
+
@config.should_not == { :reload => :whatever, :my_param => 'override_val', 'also_a_param' => true, 'strkey' => 'val', :falsekey => false, :nilkey => nil }
|
61
|
+
end
|
57
62
|
|
63
|
+
describe 'with an environment scope' do
|
58
64
|
it 'slices out a subhash given by :env' do
|
59
|
-
@config.
|
65
|
+
@config.read_yaml(@yaml_with_subenvs, :env => :development)
|
60
66
|
@config.should == { :reload => true, :my_param => 'default_val', :also_a_param => true }
|
61
67
|
end
|
62
68
|
|
63
69
|
it 'slices out a different subhash with a different :env' do
|
64
|
-
@config.
|
70
|
+
@config.read_yaml(@yaml_with_subenvs, :env => :production)
|
65
71
|
@config.should == { :reload => false, :my_param => 'default_val', :also_a_param => true }
|
66
72
|
end
|
67
73
|
|
68
74
|
it 'does no slicing without the :env option' do
|
69
|
-
@config.
|
70
|
-
@config.should == { :development => { :reload => true }, :production => { :reload => false }, :reload => :
|
75
|
+
@config.read_yaml(@yaml_with_subenvs)
|
76
|
+
@config.should == { :development => { :reload => true }, :production => { :reload => false }, :reload => :whatever, :my_param => 'default_val', :also_a_param => true }
|
71
77
|
end
|
72
78
|
|
73
79
|
it 'has no effect if the key given by :env option is absent' do
|
74
|
-
@config.
|
75
|
-
@config.should == { :reload => :
|
80
|
+
@config.read_yaml(@yaml_with_subenvs, :env => :foobar)
|
81
|
+
@config.should == { :reload => :whatever, :my_param => 'default_val', :also_a_param => true }
|
76
82
|
end
|
77
83
|
|
78
|
-
it '
|
79
|
-
|
80
|
-
@config.
|
84
|
+
it 'lets you use a string if the loading hash has a string' do
|
85
|
+
yaml_with_string_subenv = { 'john_woo' => { :reload => :sideways }}.to_yaml
|
86
|
+
@config.read_yaml(yaml_with_string_subenv, :env => 'john_woo')
|
81
87
|
@config.should == { :reload => :sideways, :my_param => 'default_val', :also_a_param => true }
|
82
88
|
end
|
83
89
|
end
|
84
90
|
end
|
85
91
|
|
86
|
-
|
87
92
|
describe 'saves to a config file' do
|
88
93
|
it 'with an absolute pathname, as given' do
|
89
94
|
fake_file = StringIO.new('', 'w')
|
90
95
|
File.should_receive(:open).with(%r{/fake/path.yaml}, 'w').and_yield(fake_file)
|
91
|
-
fake_file.should_receive(:<<).with(
|
96
|
+
fake_file.should_receive(:<<).with({ :my_param => 'default_val', :also_a_param => true }.to_yaml)
|
92
97
|
@config.save! '/fake/path.yaml'
|
93
98
|
end
|
94
99
|
|
95
100
|
it 'with a simple pathname, in the default config dir' do
|
96
101
|
fake_file = StringIO.new('', 'w')
|
97
102
|
File.should_receive(:open).with(Configliere::DEFAULT_CONFIG_DIR + '/file.yaml', 'w').and_yield(fake_file)
|
98
|
-
fake_file.should_receive(:<<).with(
|
103
|
+
fake_file.should_receive(:<<).with({ :my_param => 'default_val', :also_a_param => true }.to_yaml)
|
99
104
|
@config.save! 'file.yaml'
|
100
105
|
end
|
101
106
|
|
@@ -4,7 +4,7 @@ class AwesomeHash < DeepHash ; end
|
|
4
4
|
|
5
5
|
describe DeepHash do
|
6
6
|
before(:each) do
|
7
|
-
@deep_hash = DeepHash.new
|
7
|
+
@deep_hash = DeepHash.new({ :nested_1 => { :nested_2 => { :leaf_3 => "val3" }, :leaf_2 => ['arr'] }, :leaf_at_top => 'val1b' })
|
8
8
|
@hash = { "str_key" => "strk_val", :sym_key => "symk_val"}
|
9
9
|
@sub = AwesomeHash.new("str_key" => "strk_val", :sym_key => "symk_val")
|
10
10
|
end
|
@@ -62,7 +62,7 @@ describe DeepHash do
|
|
62
62
|
it 'symbolizes keys' do
|
63
63
|
@deep_hash['leaf_at_top'] = :fedora
|
64
64
|
@deep_hash['new'] = :unseen
|
65
|
-
@deep_hash.should == {:nested_1 => {:nested_2 => {:leaf_3 => "val3"}, :leaf_2 =>
|
65
|
+
@deep_hash.should == {:nested_1 => {:nested_2 => {:leaf_3 => "val3"}, :leaf_2 => ['arr']}, :leaf_at_top => :fedora, :new => :unseen}
|
66
66
|
end
|
67
67
|
it 'deep-sets dotted vals, replacing values' do
|
68
68
|
@deep_hash['moon.man'] = :cheesy
|
@@ -211,23 +211,6 @@ describe DeepHash do
|
|
211
211
|
end
|
212
212
|
end
|
213
213
|
|
214
|
-
describe 'assert_valid_keys' do
|
215
|
-
before do
|
216
|
-
@deep_hash = DeepHash.new({ :failure => "stuff", :funny => "business" })
|
217
|
-
end
|
218
|
-
|
219
|
-
it 'is true and does not raise when valid' do
|
220
|
-
@deep_hash.assert_valid_keys([ :failure, :funny ]).should be_nil
|
221
|
-
@deep_hash.assert_valid_keys(:failure, :funny).should be_nil
|
222
|
-
end
|
223
|
-
|
224
|
-
it 'fails when invalid' do
|
225
|
-
@deep_hash[:failore] = @deep_hash.delete(:failure)
|
226
|
-
lambda{ @deep_hash.assert_valid_keys([ :failure, :funny ]) }.should raise_error(ArgumentError, "Unknown key(s): failore")
|
227
|
-
lambda{ @deep_hash.assert_valid_keys(:failure, :funny) }.should raise_error(ArgumentError, "Unknown key(s): failore")
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
214
|
describe "#delete" do
|
232
215
|
it 'converts Symbol key into String before deleting' do
|
233
216
|
deep_hash = DeepHash.new(@hash)
|
@@ -244,23 +227,9 @@ describe DeepHash do
|
|
244
227
|
end
|
245
228
|
end
|
246
229
|
|
247
|
-
describe "#merge" do
|
248
|
-
before(:each) do
|
249
|
-
@deep_hash = DeepHash.new(@hash).merge(:no => "in between")
|
250
|
-
end
|
251
|
-
|
252
|
-
it 'returns instance of DeepHash' do
|
253
|
-
@deep_hash.should be_an_instance_of(DeepHash)
|
254
|
-
end
|
255
|
-
|
256
|
-
it 'merges in give Hash' do
|
257
|
-
@deep_hash["no"].should == "in between"
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
230
|
describe "#fetch" do
|
262
231
|
before(:each) do
|
263
|
-
@deep_hash = DeepHash.new(
|
232
|
+
@deep_hash = DeepHash.new(:no => "in between")
|
264
233
|
end
|
265
234
|
|
266
235
|
it 'converts key before fetching' do
|
@@ -272,7 +241,6 @@ describe DeepHash do
|
|
272
241
|
end
|
273
242
|
end
|
274
243
|
|
275
|
-
|
276
244
|
describe "#values_at" do
|
277
245
|
before(:each) do
|
278
246
|
@deep_hash = DeepHash.new(@hash).merge(:no => "in between")
|
@@ -283,69 +251,244 @@ describe DeepHash do
|
|
283
251
|
end
|
284
252
|
end
|
285
253
|
|
286
|
-
|
254
|
+
it 'responds to #symbolize_keys, #symbolize_keys! and #stringify_keys but not #stringify_keys!' do
|
255
|
+
DeepHash.new.should respond_to(:symbolize_keys )
|
256
|
+
DeepHash.new.should respond_to(:symbolize_keys!)
|
257
|
+
DeepHash.new.should respond_to(:stringify_keys )
|
258
|
+
DeepHash.new.should_not respond_to(:stringify_keys!)
|
259
|
+
end
|
260
|
+
|
261
|
+
describe '#symbolize_keys' do
|
262
|
+
it 'returns a dup of itself' do
|
263
|
+
deep_hash = DeepHash.new(@hash)
|
264
|
+
deep_hash.symbolize_keys.should == deep_hash
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe '#symbolize_keys!' do
|
287
269
|
it 'with bang returns the deep_hash itself' do
|
288
270
|
deep_hash = DeepHash.new(@hash)
|
289
271
|
deep_hash.symbolize_keys!.object_id.should == deep_hash.object_id
|
290
272
|
end
|
273
|
+
end
|
291
274
|
|
292
|
-
|
293
|
-
|
294
|
-
deep_hash.
|
275
|
+
describe '#stringify_keys' do
|
276
|
+
it 'converts keys that are all symbols' do
|
277
|
+
@deep_hash.stringify_keys.should ==
|
278
|
+
{ 'nested_1' => { :nested_2 => { :leaf_3 => "val3" }, :leaf_2 => ['arr'] }, 'leaf_at_top' => 'val1b' }
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'returns a Hash, not a DeepHash' do
|
282
|
+
@deep_hash.stringify_keys.class.should == Hash
|
283
|
+
@deep_hash.stringify_keys.should_not be_a(DeepHash)
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'only stringifies and hashifies the top level' do
|
287
|
+
stringified = @deep_hash.stringify_keys
|
288
|
+
stringified.should == { 'nested_1' => { :nested_2 => { :leaf_3 => "val3" }, :leaf_2 => ['arr'] }, 'leaf_at_top' => 'val1b' }
|
289
|
+
stringified['nested_1'].should be_a(DeepHash)
|
295
290
|
end
|
296
291
|
end
|
297
292
|
|
298
|
-
describe
|
293
|
+
describe '#assert_valid_keys' do
|
299
294
|
before do
|
300
|
-
@
|
301
|
-
|
295
|
+
@deep_hash = DeepHash.new({ :failure => "stuff", :funny => "business" })
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'is true and does not raise when valid' do
|
299
|
+
@deep_hash.assert_valid_keys([ :failure, :funny ]).should be_nil
|
300
|
+
@deep_hash.assert_valid_keys(:failure, :funny).should be_nil
|
301
|
+
end
|
302
|
+
|
303
|
+
it 'fails when invalid' do
|
304
|
+
@deep_hash[:failore] = @deep_hash.delete(:failure)
|
305
|
+
lambda{ @deep_hash.assert_valid_keys([ :failure, :funny ]) }.should raise_error(ArgumentError, "Unknown key(s): failore")
|
306
|
+
lambda{ @deep_hash.assert_valid_keys(:failure, :funny) }.should raise_error(ArgumentError, "Unknown key(s): failore")
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
describe "#merge" do
|
311
|
+
it 'merges given Hash' do
|
312
|
+
merged = @deep_hash.merge(:no => "in between")
|
313
|
+
merged.should == { :nested_1 => { :nested_2 => { :leaf_3 => "val3" }, :leaf_2 => ['arr'] }, :leaf_at_top => 'val1b', :no => 'in between' }
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'returns a new instance' do
|
317
|
+
merged = @deep_hash.merge(:no => "in between")
|
318
|
+
merged.should_not equal(@deep_hash)
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'returns instance of DeepHash' do
|
322
|
+
merged = @deep_hash.merge(:no => "in between")
|
323
|
+
merged.should be_an_instance_of(DeepHash)
|
324
|
+
merged[:no].should == "in between"
|
325
|
+
merged["no"].should == "in between"
|
326
|
+
end
|
327
|
+
|
328
|
+
it "converts all Hash values into DeepHashes" do
|
329
|
+
merged = @deep_hash.merge({ :nested_1 => { 'nested_2' => { :leaf_3_also => "val3a" } }, :other1 => { "other2" => "other_val2" }})
|
330
|
+
merged[:nested_1].should be_an_instance_of(DeepHash)
|
331
|
+
merged[:nested_1][:nested_2].should be_an_instance_of(DeepHash)
|
332
|
+
merged[:other1].should be_an_instance_of(DeepHash)
|
333
|
+
end
|
334
|
+
|
335
|
+
it "converts string keys to symbol keys even if they occur deep in the given hash" do
|
336
|
+
merged = @deep_hash.merge({ 'a' => { 'b' => { 'c' => { :d => :e }}}})
|
337
|
+
merged[:a].should == { :b => { :c => { :d => :e }}}
|
338
|
+
merged[:a].should_not == { 'b' => { 'c' => { :d => :e }}}
|
339
|
+
end
|
340
|
+
|
341
|
+
it "DOES merge values where given hash has nil value" do
|
342
|
+
merged = @deep_hash.merge(:a => { :b => nil }, :c => nil, :leaf_3_also => nil)
|
343
|
+
merged[:a][:b].should be_nil
|
344
|
+
merged[:c].should be_nil
|
345
|
+
merged[:leaf_3_also].should be_nil
|
346
|
+
end
|
347
|
+
|
348
|
+
it "replaces child hashes, and does not merge them" do
|
349
|
+
merged = @deep_hash.merge({ :nested_1 => { 'nested_2' => { :leaf_3_also => "val3a" } }, :other1 => { "other2" => "other_val2" }})
|
350
|
+
merged.should == { :nested_1 => { :nested_2 => { :leaf_3_also => "val3a" } }, :other1 => { :other2 => "other_val2" }, :leaf_at_top => 'val1b' }
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
describe "#merge!" do
|
355
|
+
it 'merges given Hash' do
|
356
|
+
@deep_hash.merge!(:no => "in between")
|
357
|
+
@deep_hash.should == { :nested_1 => { :nested_2 => { :leaf_3 => "val3" }, :leaf_2 => ['arr'] }, :leaf_at_top => 'val1b', :no => 'in between' }
|
358
|
+
end
|
359
|
+
|
360
|
+
it 'returns a new instance' do
|
361
|
+
@deep_hash.merge!(:no => "in between")
|
362
|
+
@deep_hash.should equal(@deep_hash)
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'returns instance of DeepHash' do
|
366
|
+
@deep_hash.merge!(:no => "in between")
|
367
|
+
@deep_hash.should be_an_instance_of(DeepHash)
|
368
|
+
@deep_hash[:no].should == "in between"
|
369
|
+
@deep_hash["no"].should == "in between"
|
370
|
+
end
|
371
|
+
|
372
|
+
it "converts all Hash values into DeepHashes" do
|
373
|
+
@deep_hash.merge!({ :nested_1 => { 'nested_2' => { :leaf_3_also => "val3a" } }, :other1 => { "other2" => "other_val2" }})
|
374
|
+
@deep_hash[:nested_1].should be_an_instance_of(DeepHash)
|
375
|
+
@deep_hash[:nested_1][:nested_2].should be_an_instance_of(DeepHash)
|
376
|
+
@deep_hash[:other1].should be_an_instance_of(DeepHash)
|
377
|
+
end
|
378
|
+
|
379
|
+
it "converts string keys to symbol keys even if they occur deep in the given hash" do
|
380
|
+
@deep_hash.merge!({ 'a' => { 'b' => { 'c' => { :d => :e }}}})
|
381
|
+
@deep_hash[:a].should == { :b => { :c => { :d => :e }}}
|
382
|
+
@deep_hash[:a].should_not == { 'b' => { 'c' => { :d => :e }}}
|
383
|
+
end
|
384
|
+
|
385
|
+
it "DOES merge values where given hash has nil value" do
|
386
|
+
@deep_hash.merge!(:a => { :b => nil }, :c => nil, :leaf_3_also => nil)
|
387
|
+
@deep_hash[:a][:b].should be_nil
|
388
|
+
@deep_hash[:c].should be_nil
|
389
|
+
@deep_hash[:leaf_3_also].should be_nil
|
390
|
+
end
|
391
|
+
|
392
|
+
it "replaces child hashes, and does not merge them" do
|
393
|
+
@deep_hash = @deep_hash.merge!({ :nested_1 => { 'nested_2' => { :leaf_3_also => "val3a" } }, :other1 => { "other2" => "other_val2" }})
|
394
|
+
@deep_hash.should == { :nested_1 => { :nested_2 => { :leaf_3_also => "val3a" } }, :other1 => { :other2 => "other_val2" }, :leaf_at_top => 'val1b' }
|
395
|
+
@deep_hash.should_not == { :nested_1 => { 'nested_2' => { :leaf_3_also => "val3a" } }, :other1 => { "other2" => "other_val2" }, :leaf_at_top => 'val1b' }
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
describe "#reverse_merge" do
|
400
|
+
it 'merges given Hash' do
|
401
|
+
@deep_hash.reverse_merge!(:no => "in between", :leaf_at_top => 'NOT_USED')
|
402
|
+
@deep_hash.should == { :nested_1 => { :nested_2 => { :leaf_3 => "val3" }, :leaf_2 => ['arr'] }, :leaf_at_top => 'val1b', :no => 'in between' }
|
403
|
+
end
|
404
|
+
|
405
|
+
it 'returns a new instance' do
|
406
|
+
@deep_hash.reverse_merge!(:no => "in between")
|
407
|
+
@deep_hash.should equal(@deep_hash)
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'returns instance of DeepHash' do
|
411
|
+
@deep_hash.reverse_merge!(:no => "in between")
|
412
|
+
@deep_hash.should be_an_instance_of(DeepHash)
|
413
|
+
@deep_hash[:no].should == "in between"
|
414
|
+
@deep_hash["no"].should == "in between"
|
415
|
+
end
|
416
|
+
|
417
|
+
it "converts all Hash values into DeepHashes" do
|
418
|
+
@deep_hash.reverse_merge!({ :nested_1 => { 'nested_2' => { :leaf_3_also => "val3a" } }, :other1 => { "other2" => "other_val2" }})
|
419
|
+
@deep_hash[:nested_1].should be_an_instance_of(DeepHash)
|
420
|
+
@deep_hash[:nested_1][:nested_2].should be_an_instance_of(DeepHash)
|
421
|
+
@deep_hash[:other1].should be_an_instance_of(DeepHash)
|
422
|
+
end
|
423
|
+
|
424
|
+
it "converts string keys to symbol keys even if they occur deep in the given hash" do
|
425
|
+
merged = @deep_hash.reverse_merge({ 'a' => { 'b' => { 'c' => { :d => :e }}}})
|
426
|
+
merged[:a].should == { :b => { :c => { :d => :e }}}
|
427
|
+
merged[:a].should_not == { 'b' => { 'c' => { :d => :e }}}
|
302
428
|
end
|
303
429
|
|
304
|
-
it
|
305
|
-
@deep_hash.reverse_merge(
|
306
|
-
@deep_hash
|
430
|
+
it "DOES merge values where given hash has nil value" do
|
431
|
+
@deep_hash.reverse_merge!(:a => { :b => nil }, :c => nil)
|
432
|
+
@deep_hash[:a][:b].should be_nil
|
433
|
+
@deep_hash[:c].should be_nil
|
307
434
|
end
|
308
435
|
|
309
|
-
it
|
310
|
-
@deep_hash.reverse_merge!(
|
311
|
-
@deep_hash.should
|
436
|
+
it "replaces child hashes, and does not merge them" do
|
437
|
+
@deep_hash = @deep_hash.reverse_merge!({ :nested_1 => { 'nested_2' => { :leaf_3_also => "val3a" } }, :other1 => { "other2" => "other_val2" }})
|
438
|
+
@deep_hash.should == { :nested_1 => { :nested_2 => { :leaf_3 => "val3" }, :leaf_2 => ['arr'] }, :other1 => { :other2 => "other_val2" }, :leaf_at_top => 'val1b' }
|
312
439
|
end
|
313
440
|
end
|
314
441
|
|
315
442
|
describe "#deep_merge!" do
|
316
443
|
it "merges two subhashes when they share a key" do
|
317
444
|
@deep_hash.deep_merge!(:nested_1 => { :nested_2 => { :leaf_3_also => "val3a" } })
|
318
|
-
@deep_hash.should == { :nested_1 => { :nested_2 => { :leaf_3_also => "val3a", :leaf_3 => "val3" }, :leaf_2 =>
|
445
|
+
@deep_hash.should == { :nested_1 => { :nested_2 => { :leaf_3_also => "val3a", :leaf_3 => "val3" }, :leaf_2 => ['arr'] }, :leaf_at_top => 'val1b' }
|
319
446
|
end
|
447
|
+
|
320
448
|
it "merges two subhashes when they share a symbolized key" do
|
321
449
|
@deep_hash.deep_merge!(:nested_1 => { "nested_2" => { "leaf_3_also" => "val3a" } })
|
322
|
-
@deep_hash.should == { :nested_1 => { :nested_2 => { :leaf_3_also => "val3a", :leaf_3 => "val3" }, :leaf_2 =>
|
450
|
+
@deep_hash.should == { :nested_1 => { :nested_2 => { :leaf_3_also => "val3a", :leaf_3 => "val3" }, :leaf_2 => ['arr'] }, :leaf_at_top => "val1b" }
|
323
451
|
end
|
452
|
+
|
324
453
|
it "preserves values in the original" do
|
325
454
|
@deep_hash.deep_merge! :other_key => "other_val"
|
326
|
-
@deep_hash[:nested_1][:leaf_2].should ==
|
455
|
+
@deep_hash[:nested_1][:leaf_2].should == ['arr']
|
327
456
|
@deep_hash[:other_key].should == "other_val"
|
328
457
|
end
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
458
|
+
|
459
|
+
it "converts all Hash values into DeepHashes" do
|
460
|
+
@deep_hash.deep_merge!({:nested_1 => { :nested_2 => { :leaf_3_also => "val3a" } }, :other1 => { "other2" => "other_val2" }})
|
461
|
+
@deep_hash[:nested_1].should be_an_instance_of(DeepHash)
|
462
|
+
@deep_hash[:nested_1][:nested_2].should be_an_instance_of(DeepHash)
|
463
|
+
@deep_hash[:other1].should be_an_instance_of(DeepHash)
|
464
|
+
end
|
465
|
+
|
466
|
+
it "converts string keys to symbol keys even if they occur deep in the given hash" do
|
467
|
+
@deep_hash.deep_merge!({ 'a' => { 'b' => { 'c' => { :d => :e }}}})
|
468
|
+
@deep_hash[:a].should == { :b => { :c => { :d => :e }}}
|
469
|
+
@deep_hash[:a].should_not == { 'b' => { 'c' => { :d => :e }}}
|
470
|
+
end
|
471
|
+
|
472
|
+
it "replaces values from the given hash" do
|
336
473
|
@deep_hash.deep_merge!(:nested_1 => { :nested_2 => { :leaf_3 => "new_val3" }, :leaf_2 => { "other2" => "other_val2" }})
|
337
474
|
@deep_hash[:nested_1][:nested_2][:leaf_3].should == 'new_val3'
|
338
475
|
@deep_hash[:nested_1][:leaf_2].should == { :other2 => "other_val2" }
|
339
476
|
end
|
340
477
|
|
341
|
-
it "replaces
|
342
|
-
@deep_hash.deep_merge!(:nested_1 => { :nested_2 => { :leaf_3 => [] }, :leaf_2 =>
|
478
|
+
it "replaces arrays and does not append to them" do
|
479
|
+
@deep_hash.deep_merge!(:nested_1 => { :nested_2 => { :leaf_3 => [] }, :leaf_2 => ['val2'] })
|
343
480
|
@deep_hash[:nested_1][:nested_2][:leaf_3].should == []
|
344
|
-
@deep_hash[:nested_1][:leaf_2].should ==
|
481
|
+
@deep_hash[:nested_1][:leaf_2].should == ['val2']
|
482
|
+
end
|
483
|
+
|
484
|
+
it "does not replaces values where given hash has nil value" do
|
485
|
+
@deep_hash.deep_merge!(:nested_1 => { :leaf_2 => nil }, :leaf_at_top => '')
|
486
|
+
@deep_hash[:nested_1][:leaf_2].should == ['arr']
|
345
487
|
@deep_hash[:leaf_at_top].should == ""
|
346
488
|
end
|
347
489
|
end
|
348
490
|
|
491
|
+
|
349
492
|
describe "#deep_set" do
|
350
493
|
it 'should set a new value (single arg)' do
|
351
494
|
@deep_hash.deep_set :new_key, 'new_val'
|
@@ -378,7 +521,7 @@ describe DeepHash do
|
|
378
521
|
it 'should remove the key from the array (multiple args)' do
|
379
522
|
@deep_hash.deep_delete(:nested_1, :nested_2, :leaf_3)
|
380
523
|
@deep_hash[:nested_1][:nested_2][:leaf_3].should be_nil
|
381
|
-
@deep_hash.should == {:leaf_at_top => "val1b", :nested_1 => {:leaf_2 =>
|
524
|
+
@deep_hash.should == {:leaf_at_top => "val1b", :nested_1 => {:leaf_2 => ['arr'], :nested_2 => {}}}
|
382
525
|
end
|
383
526
|
it 'should return the value if present (single args)' do
|
384
527
|
returned_val = @deep_hash.deep_delete(:leaf_at_top)
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: configliere
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.4.
|
5
|
+
version: 0.4.6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- infochimps
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-05-
|
14
|
+
date: 2011-05-21 00:00:00 -05:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
@@ -174,7 +174,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
174
174
|
requirements:
|
175
175
|
- - ">="
|
176
176
|
- !ruby/object:Gem::Version
|
177
|
-
hash:
|
177
|
+
hash: 213250075244557737
|
178
178
|
segments:
|
179
179
|
- 0
|
180
180
|
version: "0"
|