gorillib 0.0.8 → 0.1.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 (64) hide show
  1. data/CHANGELOG.textile +6 -0
  2. data/README.textile +34 -11
  3. data/VERSION +1 -1
  4. data/gorillib.gemspec +63 -5
  5. data/lib/gorillib/enumerable/sum.rb +2 -2
  6. data/lib/gorillib/hash/compact.rb +2 -29
  7. data/lib/gorillib/hash/deep_compact.rb +2 -12
  8. data/lib/gorillib/hash/deep_dup.rb +4 -0
  9. data/lib/gorillib/hash/deep_merge.rb +2 -14
  10. data/lib/gorillib/hash/indifferent_access.rb +207 -0
  11. data/lib/gorillib/hash/keys.rb +2 -40
  12. data/lib/gorillib/hash/reverse_merge.rb +2 -24
  13. data/lib/gorillib/hash/slice.rb +2 -51
  14. data/lib/gorillib/hash/tree_merge.rb +4 -0
  15. data/lib/gorillib/hashlike.rb +824 -0
  16. data/lib/gorillib/hashlike/compact.rb +60 -0
  17. data/lib/gorillib/hashlike/deep_compact.rb +18 -0
  18. data/lib/gorillib/hashlike/deep_dup.rb +15 -0
  19. data/lib/gorillib/hashlike/deep_merge.rb +20 -0
  20. data/lib/gorillib/hashlike/hashlike_via_accessors.rb +169 -0
  21. data/lib/gorillib/hashlike/keys.rb +59 -0
  22. data/lib/gorillib/hashlike/reverse_merge.rb +31 -0
  23. data/lib/gorillib/hashlike/slice.rb +67 -0
  24. data/lib/gorillib/hashlike/tree_merge.rb +76 -0
  25. data/lib/gorillib/metaprogramming/mattr_accessor.rb +1 -1
  26. data/lib/gorillib/receiver.rb +315 -0
  27. data/lib/gorillib/receiver/active_model_shim.rb +19 -0
  28. data/lib/gorillib/receiver/acts_as_hash.rb +191 -0
  29. data/lib/gorillib/receiver/acts_as_loadable.rb +42 -0
  30. data/lib/gorillib/receiver/tree_diff.rb +74 -0
  31. data/lib/gorillib/receiver/validations.rb +30 -0
  32. data/lib/gorillib/struct/acts_as_hash.rb +108 -0
  33. data/lib/gorillib/struct/hashlike_iteration.rb +0 -0
  34. data/notes/fancy_hashes_and_receivers.textile +120 -0
  35. data/notes/hash_rdocs.textile +97 -0
  36. data/spec/hash/deep_merge_spec.rb +0 -2
  37. data/spec/hash/indifferent_access_spec.rb +391 -0
  38. data/spec/hash/slice_spec.rb +35 -12
  39. data/spec/hashlike/behave_same_as_hash_spec.rb +105 -0
  40. data/spec/hashlike/hashlike_behavior_spec.rb +824 -0
  41. data/spec/hashlike/hashlike_via_accessors_fuzzing_spec.rb +37 -0
  42. data/spec/hashlike/hashlike_via_accessors_spec.rb +262 -0
  43. data/spec/hashlike_spec.rb +302 -0
  44. data/spec/metaprogramming/aliasing_spec.rb +3 -0
  45. data/spec/metaprogramming/cattr_accessor_spec.rb +2 -0
  46. data/spec/metaprogramming/class_attribute_spec.rb +2 -0
  47. data/spec/metaprogramming/delegation_spec.rb +2 -0
  48. data/spec/metaprogramming/mattr_accessor_spec.rb +2 -0
  49. data/spec/metaprogramming/singleton_class_spec.rb +3 -0
  50. data/spec/receiver/acts_as_hash_spec.rb +286 -0
  51. data/spec/receiver_spec.rb +478 -0
  52. data/spec/spec_helper.rb +11 -6
  53. data/spec/string/truncate_spec.rb +1 -0
  54. data/spec/struct/acts_as_hash_fuzz_spec.rb +67 -0
  55. data/spec/struct/acts_as_hash_spec.rb +426 -0
  56. data/spec/support/hashlike_fuzzing_helper.rb +127 -0
  57. data/spec/support/hashlike_helper.rb +75 -0
  58. data/spec/support/hashlike_struct_helper.rb +37 -0
  59. data/spec/support/hashlike_via_delegation.rb +30 -0
  60. data/spec/support/matchers/be_array_eql.rb +12 -0
  61. data/spec/support/matchers/be_hash_eql.rb +14 -0
  62. data/spec/support/matchers/enumerate_method.rb +10 -0
  63. data/spec/support/matchers/evaluate_to_true.rb +5 -0
  64. metadata +62 -4
@@ -96,8 +96,6 @@ describe Hash do
96
96
  end
97
97
  end
98
98
 
99
-
100
-
101
99
  describe '#deep_dup' do
102
100
  # def test_deep_dup
103
101
  # hash = { :a => { :b => 'b' } }
@@ -0,0 +1,391 @@
1
+ require 'gorillib/hash/indifferent_access'
2
+ require 'gorillib/hash/slice'
3
+ require 'gorillib/hash/reverse_merge'
4
+ require 'gorillib/hash/deep_merge'
5
+ require 'gorillib/hash/deep_dup'
6
+
7
+ describe Gorillib::HashWithIndifferentAccess do
8
+ class IndifferentHash < Gorillib::HashWithIndifferentAccess
9
+ end
10
+
11
+ class SubclassingArray < Array
12
+ end
13
+
14
+ class SubclassingHash < Hash
15
+ end
16
+
17
+ class NonIndifferentHash < Hash
18
+ def nested_under_indifferent_access
19
+ self
20
+ end
21
+ end
22
+
23
+ before do
24
+ @strings = { 'a' => 1, 'b' => 2 }
25
+ @symbols = { :a => 1, :b => 2 }
26
+ @mixed = { :a => 1, 'b' => 2 }
27
+ @fixnums = { 0 => 1, 1 => 2 }
28
+ if RUBY_VERSION < '1.9.0'
29
+ @illegal_symbols = { "\0" => 1, "" => 2, [] => 3 }
30
+ else
31
+ @illegal_symbols = { [] => 3 }
32
+ end
33
+ end
34
+
35
+ it 'symbolize_keys_for_hash_with_indifferent_access' do
36
+ @symbols.with_indifferent_access.symbolize_keys.should be_an_instance_of(Hash)
37
+ @symbols.with_indifferent_access.symbolize_keys.should == @symbols
38
+ @strings.with_indifferent_access.symbolize_keys.should == @symbols
39
+ @mixed.with_indifferent_access.symbolize_keys.should == @symbols
40
+ end
41
+
42
+ it 'symbolize_keys_bang_for_hash_with_indifferent_access' do
43
+ lambda{ @symbols.with_indifferent_access.dup.symbolize_keys! }.should raise_error(NoMethodError)
44
+ lambda{ @strings.with_indifferent_access.dup.symbolize_keys! }.should raise_error(NoMethodError)
45
+ lambda{ @mixed.with_indifferent_access.dup.symbolize_keys! }.should raise_error(NoMethodError)
46
+ end
47
+
48
+ it 'symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access' do
49
+ @illegal_symbols.with_indifferent_access.symbolize_keys.should == @illegal_symbols
50
+ lambda{ @illegal_symbols.with_indifferent_access.dup.symbolize_keys! }.should raise_error(NoMethodError)
51
+ end
52
+
53
+ it 'symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access' do
54
+ @fixnums.with_indifferent_access.symbolize_keys.should == @fixnums
55
+ lambda{ @fixnums.with_indifferent_access.dup.symbolize_keys! }.should raise_error(NoMethodError)
56
+ end
57
+
58
+ it 'stringify_keys_for_hash_with_indifferent_access' do
59
+ @symbols.with_indifferent_access.stringify_keys.should be_an_instance_of(Gorillib::HashWithIndifferentAccess)
60
+ @symbols.with_indifferent_access.stringify_keys.should == @strings
61
+ @strings.with_indifferent_access.stringify_keys.should == @strings
62
+ @mixed.with_indifferent_access.stringify_keys.should == @strings
63
+ end
64
+
65
+ it 'stringify_keys_bang_for_hash_with_indifferent_access' do
66
+ @symbols.with_indifferent_access.dup.stringify_keys!.should be_an_instance_of(Gorillib::HashWithIndifferentAccess)
67
+ @symbols.with_indifferent_access.dup.stringify_keys!.should == @strings
68
+ @strings.with_indifferent_access.dup.stringify_keys!.should == @strings
69
+ @mixed.with_indifferent_access.dup.stringify_keys!.should == @strings
70
+ end
71
+
72
+ it 'nested_under_indifferent_access' do
73
+ foo = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
74
+ foo["foo"].should be_a(Gorillib::HashWithIndifferentAccess)
75
+
76
+ foo = { "foo" => NonIndifferentHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
77
+ foo["foo"].should be_a(NonIndifferentHash)
78
+ end
79
+
80
+ it 'indifferent_assorted' do
81
+ @strings = @strings.with_indifferent_access
82
+ @symbols = @symbols.with_indifferent_access
83
+ @mixed = @mixed.with_indifferent_access
84
+
85
+ @strings.__send__(:convert_key, :a).should == 'a'
86
+
87
+ @strings.fetch('a').should == 1
88
+ @strings.fetch(:a.to_s).should == 1
89
+ @strings.fetch(:a).should == 1
90
+
91
+ hashes = { :@strings => @strings, :@symbols => @symbols, :@mixed => @mixed }
92
+ method_map = { :'[]' => 1, :fetch => 1, :values_at => [1],
93
+ :has_key? => true, :include? => true, :key? => true,
94
+ :member? => true }
95
+
96
+ hashes.each do |name, hash|
97
+ method_map.sort_by { |m| m.to_s }.each do |meth, expected|
98
+ hash.__send__(meth, 'a').should == expected
99
+ hash.__send__(meth, :a).should == expected
100
+ end
101
+ end
102
+
103
+ @strings.values_at('a', 'b').should == [1, 2]
104
+ @strings.values_at(:a, :b).should == [1, 2]
105
+ @symbols.values_at('a', 'b').should == [1, 2]
106
+ @symbols.values_at(:a, :b).should == [1, 2]
107
+ @mixed.values_at('a', 'b').should == [1, 2]
108
+ @mixed.values_at(:a, :b).should == [1, 2]
109
+ end
110
+
111
+ it 'indifferent_reading' do
112
+ hash = Gorillib::HashWithIndifferentAccess.new
113
+ hash["a"] = 1
114
+ hash["b"] = true
115
+ hash["c"] = false
116
+ hash["d"] = nil
117
+
118
+ hash[:a].should == 1
119
+ hash[:b].should == true
120
+ hash[:c].should == false
121
+ hash[:d].should == nil
122
+ hash[:e].should == nil
123
+ end
124
+
125
+ it 'indifferent_reading_with_nonnil_default' do
126
+ hash = Gorillib::HashWithIndifferentAccess.new(1)
127
+ hash["a"] = 1
128
+ hash["b"] = true
129
+ hash["c"] = false
130
+ hash["d"] = nil
131
+
132
+ hash[:a].should == 1
133
+ hash[:b].should == true
134
+ hash[:c].should == false
135
+ hash[:d].should == nil
136
+ hash[:e].should == 1
137
+ end
138
+
139
+ it 'indifferent_writing' do
140
+ hash = Gorillib::HashWithIndifferentAccess.new
141
+ hash[:a] = 1
142
+ hash['b'] = 2
143
+ hash[3] = 3
144
+
145
+ 1.should == hash['a']
146
+ 2.should == hash['b']
147
+ 1.should == hash[:a]
148
+ 2.should == hash[:b]
149
+ 3.should == hash[3]
150
+ end
151
+
152
+ it 'indifferent_update' do
153
+ hash = Gorillib::HashWithIndifferentAccess.new
154
+ hash[:a] = 'a'
155
+ hash['b'] = 'b'
156
+
157
+ updated_with_strings = hash.update(@strings)
158
+ updated_with_symbols = hash.update(@symbols)
159
+ updated_with_mixed = hash.update(@mixed)
160
+
161
+ 1.should == updated_with_strings[:a]
162
+ 1.should == updated_with_strings['a']
163
+ 2.should == updated_with_strings['b']
164
+
165
+ 1.should == updated_with_symbols[:a]
166
+ 2.should == updated_with_symbols['b']
167
+ 2.should == updated_with_symbols[:b]
168
+
169
+ 1.should == updated_with_mixed[:a]
170
+ 2.should == updated_with_mixed['b']
171
+
172
+ [updated_with_strings, updated_with_symbols, updated_with_mixed].all?{ |h| h.keys.size == 2 }.should be_true
173
+ end
174
+
175
+ it 'indifferent_merging' do
176
+ hash = Gorillib::HashWithIndifferentAccess.new
177
+ hash[:a] = 'failure'
178
+ hash['b'] = 'failure'
179
+
180
+ other = { 'a' => 1, :b => 2 }
181
+
182
+ merged = hash.merge(other)
183
+
184
+ merged.class.should == Gorillib::HashWithIndifferentAccess
185
+ merged[:a].should == 1
186
+ merged['b'].should == 2
187
+
188
+ hash.update(other)
189
+
190
+ hash[:a].should == 1
191
+ hash['b'].should == 2
192
+ end
193
+
194
+ it 'indifferent_reverse_merging' do
195
+ hash = Gorillib::HashWithIndifferentAccess.new('some' => 'value', 'other' => 'value')
196
+ hash.reverse_merge!(:some => 'noclobber', :another => 'clobber')
197
+ hash[:some].should == 'value'
198
+ hash[:another].should == 'clobber'
199
+ end
200
+
201
+ it 'indifferent_deleting' do
202
+ get_hash = proc{ { :a => 'foo' }.with_indifferent_access }
203
+ hash = get_hash.call
204
+ 'foo'.should == hash.delete(:a)
205
+ nil.should == hash.delete(:a)
206
+ hash = get_hash.call
207
+ 'foo'.should == hash.delete('a')
208
+ nil.should == hash.delete('a')
209
+ end
210
+
211
+ it 'indifferent_to_hash' do
212
+ # Should convert to a Hash with String keys.
213
+ @mixed.with_indifferent_access.to_hash.should == @strings
214
+
215
+ # Should preserve the default value.
216
+ mixed_with_default = @mixed.dup
217
+ mixed_with_default.default = '1234'
218
+ roundtrip = mixed_with_default.with_indifferent_access.to_hash
219
+ roundtrip.should == @strings
220
+ roundtrip.default.should == '1234'
221
+ end
222
+
223
+ it 'indifferent_hash_with_array_of_hashes' do
224
+ hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access
225
+ hash[:urls][:url].first[:address].should == "1"
226
+ end
227
+
228
+ it 'should_preserve_array_subclass_when_value_is_array' do
229
+ array = SubclassingArray.new
230
+ array << { "address" => "1" }
231
+ hash = { "urls" => { "url" => array }}.with_indifferent_access
232
+ hash[:urls][:url].class.should == SubclassingArray
233
+ end
234
+
235
+ it 'should_preserve_array_class_when_hash_value_is_frozen_array' do
236
+ array = SubclassingArray.new
237
+ array << { "address" => "1" }
238
+ hash = { "urls" => { "url" => array.freeze }}.with_indifferent_access
239
+ hash[:urls][:url].class.should == SubclassingArray
240
+ end
241
+
242
+ it 'stringify_and_symbolize_keys_on_indifferent_preserves_hash' do
243
+ h = Gorillib::HashWithIndifferentAccess.new
244
+ h[:first] = 1
245
+ h = h.stringify_keys
246
+ h['first'].should == 1
247
+ h = Gorillib::HashWithIndifferentAccess.new
248
+ h['first'] = 1
249
+ h = h.symbolize_keys
250
+ h[:first].should == 1
251
+ end
252
+
253
+ it 'to_options_on_indifferent_preserves_hash' do
254
+ h = Gorillib::HashWithIndifferentAccess.new
255
+ h['first'] = 1
256
+ h.to_options!
257
+ h['first'].should == 1
258
+ end
259
+
260
+ it 'indifferent_subhashes' do
261
+ h = {'user' => {'id' => 5}}.with_indifferent_access
262
+ ['user', :user].each{|user| [:id, 'id'].each{|id| h[user][id].should == 5 }}
263
+
264
+ h = {:user => {:id => 5}}.with_indifferent_access
265
+ ['user', :user].each{|user| [:id, 'id'].each{|id| h[user][id].should == 5 }}
266
+ end
267
+
268
+ it 'indifferent_duplication' do
269
+ # Should preserve default value
270
+ h = Gorillib::HashWithIndifferentAccess.new
271
+ h.default = '1234'
272
+ h.dup.default.should == h.default
273
+
274
+ # Should preserve class for subclasses
275
+ h = IndifferentHash.new
276
+ h.dup.class.should == h.class
277
+ end
278
+
279
+ it 'assorted_keys_not_stringified' do
280
+ original = {Object.new => 2, 1 => 2, [] => true}
281
+ indiff = original.with_indifferent_access
282
+ indiff.keys.any?{|k| k.kind_of? String }.should_not be_true
283
+ end
284
+
285
+ it 'deep_merge' do
286
+ hash_1 = { :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } }
287
+ hash_2 = { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } }
288
+ expected = { :a => 1, :b => "b", :c => { :c1 => 2, :c2 => "c2", :c3 => { :d1 => "d1", :d2 => "d2" } } }
289
+ hash_1.deep_merge(hash_2).should == expected
290
+
291
+ hash_1.deep_merge!(hash_2)
292
+ hash_1.should == expected
293
+ end
294
+
295
+ it 'deep_merge_on_indifferent_access' do
296
+ hash_1 = Gorillib::HashWithIndifferentAccess.new({ :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } })
297
+ hash_2 = Gorillib::HashWithIndifferentAccess.new({ :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } })
298
+ hash_3 = { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } }
299
+ expected = { "a" => 1, "b" => "b", "c" => { "c1" => 2, "c2" => "c2", "c3" => { "d1" => "d1", "d2" => "d2" } } }
300
+ hash_1.deep_merge(hash_2).should == expected
301
+ hash_1.deep_merge(hash_3).should == expected
302
+
303
+ hash_1.deep_merge!(hash_2)
304
+ hash_1.should == expected
305
+ end
306
+
307
+ it 'deep_dup' do
308
+ hash = { :a => { :b => 'b' } }
309
+ dup = hash.deep_dup
310
+ dup[:a][:c] = 'c'
311
+ hash[:a][:c].should == nil
312
+ dup[:a][:c].should == 'c'
313
+ end
314
+
315
+ it 'deep_dup_initialize' do
316
+ zero_hash = Hash.new 0
317
+ hash = { :a => zero_hash }
318
+ dup = hash.deep_dup
319
+ dup[:a][44].should == 0
320
+ end
321
+
322
+ it 'store_on_indifferent_access' do
323
+ hash = Gorillib::HashWithIndifferentAccess.new
324
+ hash.store(:test1, 1)
325
+ hash.store('test1', 11)
326
+ hash[:test2] = 2
327
+ hash['test2'] = 22
328
+ expected = { "test1" => 11, "test2" => 22 }
329
+ hash.should == expected
330
+ end
331
+
332
+ it 'indifferent_slice' do
333
+ original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access
334
+ expected = { :a => 'x', :b => 'y' }.with_indifferent_access
335
+
336
+ [['a', 'b'], [:a, :b]].each do |keys|
337
+ # Should return a new hash with only the given keys.
338
+ original.slice(*keys).should == expected
339
+ original.should_not == expected
340
+ end
341
+ end
342
+
343
+ it 'indifferent_slice_inplace' do
344
+ original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access
345
+ expected = { :c => 10 }.with_indifferent_access
346
+
347
+ [['a', 'b'], [:a, :b]].each do |keys|
348
+ # Should replace the hash with only the given keys.
349
+ copy = original.dup
350
+ copy.slice!(*keys).should == expected
351
+ end
352
+ end
353
+
354
+ it 'indifferent_slice_access_with_symbols' do
355
+ original = {'login' => 'bender', 'password' => 'shiny', 'stuff' => 'foo'}
356
+ original = original.with_indifferent_access
357
+
358
+ slice = original.slice(:login, :password)
359
+
360
+ slice[:login].should == 'bender'
361
+ slice['login'].should == 'bender'
362
+ end
363
+
364
+ it 'should_use_default_value_for_unknown_key' do
365
+ hash_wia = Gorillib::HashWithIndifferentAccess.new(3)
366
+ hash_wia[:new_key].should == 3
367
+ end
368
+
369
+ it 'should_use_default_value_if_no_key_is_supplied' do
370
+ hash_wia = Gorillib::HashWithIndifferentAccess.new(3)
371
+ hash_wia.default.should == 3
372
+ end
373
+
374
+ it 'should_nil_if_no_default_value_is_supplied' do
375
+ hash_wia = Gorillib::HashWithIndifferentAccess.new
376
+ hash_wia.default.should be_nil
377
+ end
378
+
379
+ it 'should_return_dup_for_with_indifferent_access' do
380
+ hash_wia = Gorillib::HashWithIndifferentAccess.new
381
+ hash_wia.with_indifferent_access.should == hash_wia
382
+ hash_wia.with_indifferent_access.should_not equal(hash_wia)
383
+ end
384
+
385
+ it 'should_copy_the_default_value_when_converting_to_hash_with_indifferent_access' do
386
+ hash = Hash.new(3)
387
+ hash_wia = hash.with_indifferent_access
388
+ hash_wia.default.should == 3
389
+ end
390
+
391
+ end
@@ -1,6 +1,8 @@
1
1
  require File.dirname(__FILE__)+'/../spec_helper'
2
2
  require 'gorillib/hash/slice'
3
3
 
4
+ class HashSubclass < Hash ; end
5
+
4
6
  describe Hash do
5
7
  describe '#slice' do
6
8
  it 'should return a new hash with only the given keys' do
@@ -8,14 +10,7 @@ describe Hash do
8
10
  expected = { :a => 'x', :b => 'y' }
9
11
 
10
12
  original.slice(:a, :b).should == expected
11
- original.should_not == expected
12
- end
13
-
14
- it 'Should replace the hash with only the given keys' do
15
- original = { :a => 'x', :b => 'y', :c => 10 }
16
- expected = { :c => 10 }
17
-
18
- original.slice!(:a, :b).should == expected
13
+ original.should == { :a => 'x', :b => 'y', :c => 10 }
19
14
  end
20
15
 
21
16
  it 'should return a new hash with only the given keys when given an array key' do
@@ -26,18 +21,46 @@ describe Hash do
26
21
  original.should_not == expected
27
22
  end
28
23
 
24
+ it 'Should grab each of the splatted keys' do
25
+ original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" }
26
+ expected = { :a => 'x', :b => "y" }
27
+
28
+ original.slice(*[:a, :b]).should == expected
29
+ end
30
+
31
+ it 'should have the same type as the original' do
32
+ hsh = HashSubclass.new.merge({ :a => 'x', :b => 'y', :c => 10 })
33
+ hsh.slice(:a, :b).should be_a(HashSubclass)
34
+ end
35
+ end
36
+
37
+ describe '#slice!' do
38
+ it 'Should replace the hash with only the given keys' do
39
+ original = { :a => 'x', :b => 'y', :c => 10 }
40
+ expected = { :c => 10 }
41
+ remaining = { :a => 'x', :b => 'y' }
42
+
43
+ original.slice!(:a, :b).should == expected
44
+ original.should == remaining
45
+ end
46
+
29
47
  it 'should replace the hash with only the given keys when given an array key' do
30
48
  original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" }
31
49
  expected = { :a => 'x', :b => 'y' }
32
50
 
33
51
  original.slice!([:a, :b], :c).should == expected
34
52
  end
53
+ end
35
54
 
36
- it 'Should grab each of the splatted keys' do
37
- original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" }
38
- expected = { :a => 'x', :b => "y" }
55
+ describe '#extract!' do
56
+ it 'Should replace the hash with only the omitted keys' do
57
+ original = { :a => 'x', :b => 'y', :c => 10 }
58
+ expected = { :a => 'x', :b => 'y' }
59
+ remaining = { :c => 10 }
39
60
 
40
- original.slice(*[:a, :b]).should == expected
61
+ original.extract!(:a, :b).should == expected
62
+ original.should == remaining
41
63
  end
42
64
  end
65
+
43
66
  end