gorillib 0.0.8 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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