configliere 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
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
- #resolve!
54
- calls super and returns self
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
- does not type convert the :env option
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 defaults into options, creating a new hash
142
- with bang merges! defaults into options, replacing options
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
- replaces values from the given DeepHash
148
- replaces values from the given DeepHash
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.26971 seconds
298
- 214 examples, 0 failures
341
+ Finished in 0.61948 seconds
342
+ 247 examples, 0 failures
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.5
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.5"
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-18}
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
- new_data = YAML.load(File.open(filename)) || {}
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
- # Return a new hash with all keys converted to symbols, as long as
93
- # they respond to +to_sym+.
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
- # Used to provide the same interface as Hash.
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
- describe 'with an environment scope' do
51
- before do
52
- @config.defaults :reload => :unset
53
- @hash_with_subenvs = { :development => { :reload => true }, :production => { :reload => false }}
54
- File.stub :open
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.read('f', :env => :development)
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.read('f', :env => :production)
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.read('f')
70
- @config.should == { :development => { :reload => true }, :production => { :reload => false }, :reload => :unset, :my_param => 'default_val', :also_a_param => true }
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.read('f', :env => :foobar)
75
- @config.should == { :reload => :unset, :my_param => 'default_val', :also_a_param => true }
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 'does not type convert the :env option' do
79
- @hash_with_subenvs['john_woo'] = { :reload => :sideways }
80
- @config.read('f', :env => 'john_woo')
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("--- \n:my_param: default_val\n:also_a_param: true\n")
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("--- \n:my_param: default_val\n:also_a_param: true\n")
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.merge!({ :nested_1 => { :nested_2 => { :leaf_3 => "val3" }, :leaf_2 => "val2" }, :leaf_at_top => 'val1b' })
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 => "val2"}, :leaf_at_top => :fedora, :new => :unseen}
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(@hash).merge(:no => "in between")
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
- describe "#symbolize_keys" do
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
- it 'returns a dup of itself' do
293
- deep_hash = DeepHash.new(@hash)
294
- deep_hash.symbolize_keys.should == 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 "#reverse_merge" do
293
+ describe '#assert_valid_keys' do
299
294
  before do
300
- @defaults = { :a => "x", :b => "y", :c => 10 }.freeze
301
- @deep_hash = DeepHash.new({ :a => 1, :b => 2 })
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 'merges defaults into options, creating a new hash' do
305
- @deep_hash.reverse_merge(@defaults).should == { :a => 1, :b => 2, :c => 10 }
306
- @deep_hash.should == { :a => 1, :b => 2 }
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 'with bang merges! defaults into options, replacing options' do
310
- @deep_hash.reverse_merge!(@defaults).should == { :a => 1, :b => 2, :c => 10 }
311
- @deep_hash.should == { :a => 1, :b => 2, :c => 10 }
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 => "val2" }, :leaf_at_top => 'val1b' }
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 => "val2" }, :leaf_at_top => "val1b" }
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 == "val2"
455
+ @deep_hash[:nested_1][:leaf_2].should == ['arr']
327
456
  @deep_hash[:other_key].should == "other_val"
328
457
  end
329
- # it "converts all Hash values into DeepHashes if param is a Hash" do
330
- # @deep_hash.deep_merge!({:nested_1 => { :nested_2 => { :leaf_3_also => "val3a" } }, :other1 => { "other2" => "other_val2" }})
331
- # @deep_hash[:nested_1].should be_an_instance_of(DeepHash)
332
- # @deep_hash[:nested_1][:nested_2].should be_an_instance_of(DeepHash)
333
- # @deep_hash[:other1].should be_an_instance_of(DeepHash)
334
- # end
335
- it "replaces values from the given DeepHash" do
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 values from the given DeepHash" do
342
- @deep_hash.deep_merge!(:nested_1 => { :nested_2 => { :leaf_3 => [] }, :leaf_2 => nil }, :leaf_at_top => '')
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 == "val2"
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 => "val2", :nested_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
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-18 00:00:00 -05:00
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: -3183115947293832895
177
+ hash: 213250075244557737
178
178
  segments:
179
179
  - 0
180
180
  version: "0"