osullivan 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE +23 -0
  7. data/README.md +166 -0
  8. data/Rakefile +12 -0
  9. data/VERSION +1 -0
  10. data/lib/active_support/ordered_hash.rb +147 -0
  11. data/lib/iiif/hash_behaviours.rb +150 -0
  12. data/lib/iiif/presentation.rb +25 -0
  13. data/lib/iiif/presentation/abstract_resource.rb +75 -0
  14. data/lib/iiif/presentation/annotation.rb +25 -0
  15. data/lib/iiif/presentation/annotation_list.rb +28 -0
  16. data/lib/iiif/presentation/canvas.rb +45 -0
  17. data/lib/iiif/presentation/collection.rb +29 -0
  18. data/lib/iiif/presentation/image_resource.rb +115 -0
  19. data/lib/iiif/presentation/layer.rb +34 -0
  20. data/lib/iiif/presentation/manifest.rb +39 -0
  21. data/lib/iiif/presentation/range.rb +32 -0
  22. data/lib/iiif/presentation/resource.rb +21 -0
  23. data/lib/iiif/presentation/sequence.rb +35 -0
  24. data/lib/iiif/service.rb +418 -0
  25. data/osullivan.gemspec +27 -0
  26. data/spec/fixtures/manifests/complete_from_spec.json +171 -0
  27. data/spec/fixtures/manifests/minimal.json +40 -0
  28. data/spec/fixtures/manifests/service_only.json +11 -0
  29. data/spec/fixtures/vcr_cassettes/pul_loris_cassette.json +159 -0
  30. data/spec/integration/iiif/presentation/image_resource_spec.rb +123 -0
  31. data/spec/integration/iiif/service_spec.rb +211 -0
  32. data/spec/spec_helper.rb +104 -0
  33. data/spec/unit/active_support/ordered_hash_spec.rb +155 -0
  34. data/spec/unit/iiif/hash_behaviours_spec.rb +569 -0
  35. data/spec/unit/iiif/presentation/abstract_resource_spec.rb +133 -0
  36. data/spec/unit/iiif/presentation/annotation_list_spec.rb +7 -0
  37. data/spec/unit/iiif/presentation/annotation_spec.rb +7 -0
  38. data/spec/unit/iiif/presentation/canvas_spec.rb +40 -0
  39. data/spec/unit/iiif/presentation/collection_spec.rb +54 -0
  40. data/spec/unit/iiif/presentation/image_resource_spec.rb +13 -0
  41. data/spec/unit/iiif/presentation/layer_spec.rb +38 -0
  42. data/spec/unit/iiif/presentation/manifest_spec.rb +89 -0
  43. data/spec/unit/iiif/presentation/range_spec.rb +43 -0
  44. data/spec/unit/iiif/presentation/resource_spec.rb +16 -0
  45. data/spec/unit/iiif/presentation/sequence_spec.rb +110 -0
  46. data/spec/unit/iiif/presentation/shared_examples/abstract_resource_only_keys.rb +43 -0
  47. data/spec/unit/iiif/presentation/shared_examples/any_type_keys.rb +33 -0
  48. data/spec/unit/iiif/presentation/shared_examples/array_only_keys.rb +44 -0
  49. data/spec/unit/iiif/presentation/shared_examples/int_only_keys.rb +49 -0
  50. data/spec/unit/iiif/presentation/shared_examples/string_only_keys.rb +29 -0
  51. data/spec/unit/iiif/service_spec.rb +10 -0
  52. metadata +246 -0
@@ -0,0 +1,569 @@
1
+ require File.join(File.dirname(__FILE__), '../../spec_helper')
2
+ require 'active_support/ordered_hash'
3
+ describe IIIF::HashBehaviours do
4
+
5
+ let(:hash_like_class) do
6
+ Class.new do
7
+ include IIIF::HashBehaviours
8
+ attr_accessor :data # Accessible for easier expects...not sure you'd do this in a real class
9
+ def initialize()
10
+ @data = ActiveSupport::OrderedHash.new
11
+ end
12
+ end
13
+ end
14
+
15
+ # TODO: let(:init_data)...rather than repeating so much below
16
+ subject { hash_like_class.new }
17
+
18
+ describe '#[]=' do
19
+ it 'assigns a new k and value to the node' do
20
+ subject['foo'] = 'bar'
21
+ expect(subject.data).to eq({'foo' => 'bar'})
22
+ end
23
+ it 'always puts new entries at the end' do
24
+ subject['baz'] = 'qux'
25
+ subject['quux'] = 'corge'
26
+ subject['grault'] = 'garply'
27
+ expect(subject.data[subject.data.keys.last]).to eq 'garply'
28
+ end
29
+ it 'replaces keys that already exist in the same place' do
30
+ subject['waldo'] = 'fred'
31
+ subject['plugh'] = 'xyzzy'
32
+ subject['thud'] = 'wibble'
33
+ subject['plugh'] = 'wobble'
34
+ expect(subject.data.select {|k,v| k == 'plugh'}).to eq({'plugh'=>'wobble'})
35
+ end
36
+ end
37
+
38
+ describe '#[]' do
39
+ it 'retrieves the expected value' do
40
+ subject['wibble'] = 'wobble'
41
+ subject['wubble'] = 'fred'
42
+ expect(subject['wibble']).to eq 'wobble'
43
+ end
44
+ it 'returns nil if the key is not found' do
45
+ subject['wibble'] = 'wobble'
46
+ subject['wubble'] = 'fred'
47
+ expect(subject['flob']).to be_nil
48
+ end
49
+ end
50
+
51
+ describe '#clear' do
52
+ it 'clears all properties' do
53
+ subject['wibble'] = 'wobble'
54
+ subject['wubble'] = 'fred'
55
+ subject.clear
56
+ expect(subject.keys).to eq []
57
+ end
58
+ it 'returns the instance on which it was called' do
59
+ subject['wibble'] = 'wobble'
60
+ subject['wubble'] = 'fred'
61
+ expect(subject.clear).to eq subject
62
+ end
63
+ end
64
+
65
+ describe '#delete' do
66
+ it 'removes an entry from the object' do
67
+ subject['waldo'] = 'fred'
68
+ subject['plugh'] = 'xyzzy'
69
+ subject.delete('waldo')
70
+ expect(subject.data).to eq({'plugh' => 'xyzzy'})
71
+ end
72
+ it 'returns the value of the entry that was removed' do
73
+ subject['waldo'] = 'fred'
74
+ subject['plugh'] = 'xyzzy'
75
+ expect(subject.delete('waldo')).to eq 'fred'
76
+ end
77
+ it 'can take a block as well' do
78
+ subject['waldo'] = 'fred'
79
+ subject['plugh'] = 'xyzzy'
80
+ expect { |b| subject.delete('wubble', &b) }.to yield_with_args
81
+ expect(subject.delete('foo') {|e| e.reverse }).to eq 'oof'
82
+ end
83
+ end
84
+
85
+ describe '#delete_if' do
86
+ it 'can take a block' do
87
+ subject['wibble'] = 'foo'
88
+ subject['waldo'] = 'fred'
89
+ subject['plugh'] = 'xyzzy'
90
+ expect { |b| subject.delete_if(&b) }.to yield_successive_args(['wibble', 'foo'], ['waldo', 'fred'], ['plugh', 'xyzzy'])
91
+ end
92
+ it 'returns the instance' do
93
+ subject['wibble'] = 'foo'
94
+ subject['waldo'] = 'fred'
95
+ subject['plugh'] = 'xyzzy'
96
+ expect( subject.delete_if { |k,v| k.start_with?('w') } ).to eq subject
97
+ end
98
+ it 'works' do
99
+ subject['wibble'] = 'foo'
100
+ subject['waldo'] = 'fred'
101
+ subject['plugh'] = 'xyzzy'
102
+ subject.delete_if { |k,v| k.start_with?('w') }
103
+ expect(subject.data).to eq({'plugh' => 'xyzzy'})
104
+ end
105
+ it 'returns an enumerator if no block is supplied' do
106
+ subject['wibble'] = 'foo'
107
+ subject['waldo'] = 'fred'
108
+ subject['plugh'] = 'xyzzy'
109
+ expect(subject.delete_if).to be_a Enumerator
110
+ end
111
+ end
112
+
113
+ describe '#each' do
114
+ it 'yields' do
115
+ subject['plugh'] = 'xyzzy'
116
+ expect { |b| subject.each(&b) }.to yield_with_args
117
+ end
118
+ it 'returns the instance' do
119
+ subject.data['waldo'] = 'fred'
120
+ subject.data['plugh'] = 'xyzzy'
121
+ expect(subject.each { |k,v| nil }).to eq subject
122
+ end
123
+ it 'loops as expected' do
124
+ subject.data['wibble'] = 'foo'
125
+ subject.data['waldo'] = 'fred'
126
+ subject.data['plugh'] = 'xyzzy'
127
+ capped_keys = []
128
+ subject.each { |k,v| capped_keys << k.capitalize }
129
+ expect(capped_keys).to eq ['Wibble', 'Waldo', 'Plugh']
130
+ end
131
+ it 'returns an enumerator if no block is supplied' do
132
+ subject['wibble'] = 'foo'
133
+ subject['waldo'] = 'fred'
134
+ subject['plugh'] = 'xyzzy'
135
+ expect(subject.delete_if).to be_a Enumerator
136
+ end
137
+ end
138
+
139
+ describe '#each_key' do
140
+ it 'yields' do
141
+ subject['plugh'] = 'xyzzy'
142
+ expect { |b| subject.each_key(&b) }.to yield_with_args
143
+ end
144
+ it 'returns the instance' do
145
+ subject.data['waldo'] = 'fred'
146
+ subject.data['plugh'] = 'xyzzy'
147
+ expect(subject.each_key { |k| nil }).to eq subject
148
+ end
149
+ it 'loops as expected' do
150
+ subject['wibble'] = 'foo'
151
+ subject['waldo'] = 'fred'
152
+ subject['plugh'] = 'xyzzy'
153
+ key_accumulator = []
154
+ subject.each_key { |k| key_accumulator << k }
155
+ expect(key_accumulator).to eq ['wibble', 'waldo', 'plugh']
156
+ end
157
+ it 'returns an enumerator if no block is supplied' do
158
+ subject['wibble'] = 'foo'
159
+ subject['waldo'] = 'fred'
160
+ subject['plugh'] = 'xyzzy'
161
+ expect(subject.each_key).to be_a Enumerator
162
+ end
163
+ end
164
+
165
+ describe '#each_value' do
166
+ it 'yields' do
167
+ subject['plugh'] = 'xyzzy'
168
+ expect { |b| subject.each_value(&b) }.to yield_with_args
169
+ end
170
+ it 'returns the instance' do
171
+ subject.data['waldo'] = 'fred'
172
+ subject.data['plugh'] = 'xyzzy'
173
+ expect(subject.each_value { |v| nil }).to eq subject
174
+ end
175
+ it 'loops as expected' do
176
+ subject['wibble'] = 'foo'
177
+ subject['waldo'] = 'fred'
178
+ subject['plugh'] = 'xyzzy'
179
+ value_accumulator = []
180
+ subject.each_value { |v| value_accumulator << v }
181
+ expect(value_accumulator).to eq ['foo', 'fred', 'xyzzy']
182
+ end
183
+ it 'returns an enumerator if no block is supplied' do
184
+ subject['wibble'] = 'foo'
185
+ subject['waldo'] = 'fred'
186
+ subject['plugh'] = 'xyzzy'
187
+ expect(subject.each_value).to be_a Enumerator
188
+ end
189
+
190
+ end
191
+
192
+ describe '#empty' do
193
+ it 'returns true when there are no entries' do
194
+ expect(subject.empty?).to be_truthy
195
+ end
196
+ it 'returns false when we have data' do
197
+ subject['waldo'] = 'fred'
198
+ expect(subject.empty?).to be_falsey
199
+ end
200
+ end
201
+
202
+ describe '#fetch' do
203
+ it 'retrieves the expected value' do
204
+ subject['wibble'] = 'wobble'
205
+ subject['wubble'] = 'fred'
206
+ expect(subject.fetch('wibble')).to eq 'wobble'
207
+ end
208
+ it 'returns the default if the key is not found and one is supplied' do
209
+ subject['wibble'] = 'wobble'
210
+ subject['wubble'] = 'fred'
211
+ expect(subject.fetch('flob', 'waldo')).to eq 'waldo'
212
+ end
213
+ it 'raises a KeyError if the key is not found and no default is supplied' do
214
+ expect { subject.fetch('flob') }.to raise_error KeyError
215
+ end
216
+ it 'can take a block as well' do
217
+ subject['wibble'] = 'wobble'
218
+ subject['wubble'] = 'fred'
219
+ expect(subject.fetch('wubble') {|e| e.capitalize }).to eq 'fred' # value takes precence
220
+ expect { |b| subject.fetch('foo', &b) }.to yield_with_args
221
+ expect(subject.fetch('foo') {|e| e.reverse }).to eq 'oof'
222
+ end
223
+ end
224
+
225
+ describe '#has_key? (and aliases)' do
226
+ it 'is true when the key exists' do
227
+ subject['wibble'] = 'wobble'
228
+ expect(subject.has_key? 'wibble').to be_truthy
229
+ end
230
+ it 'is false when the key does not exist' do
231
+ expect(subject.has_key? 'wibble').to be_falsey
232
+ end
233
+ end
234
+
235
+ describe '#has_value? (and aliases)' do
236
+ it 'is true when the value exists' do
237
+ subject['wibble'] = 'wobble'
238
+ expect(subject.has_value? 'wobble').to be_truthy
239
+ end
240
+ it 'is false when the value does not exist' do
241
+ expect(subject.has_value? 'wobble').to be_falsey
242
+ end
243
+ end
244
+
245
+ describe '#keep_if' do
246
+ it 'can take a block' do
247
+ subject['wibble'] = 'foo'
248
+ subject['waldo'] = 'fred'
249
+ subject['plugh'] = 'xyzzy'
250
+ expect { |b| subject.keep_if(&b) }.to yield_successive_args(['wibble', 'foo'], ['waldo', 'fred'], ['plugh', 'xyzzy'])
251
+ end
252
+ it 'returns the instance' do
253
+ subject['wibble'] = 'foo'
254
+ subject['waldo'] = 'fred'
255
+ subject['plugh'] = 'xyzzy'
256
+ expect( subject.keep_if { |k,v| k.start_with?('w') } ).to eq subject
257
+ end
258
+ it 'works' do
259
+ subject['wibble'] = 'foo'
260
+ subject['waldo'] = 'fred'
261
+ subject['plugh'] = 'xyzzy'
262
+ subject.keep_if { |k,v| k.start_with?('w') }
263
+ expect(subject.data).to eq({'wibble'=>'foo', 'waldo'=>'fred'})
264
+ end
265
+ end
266
+
267
+ describe '#key' do
268
+ it 'is the key associated with a value' do
269
+ subject['thud'] = 'wibble'
270
+ subject['plugh'] = 'wobble'
271
+ expect(subject.key 'wibble').to eq 'thud'
272
+ expect(subject.key 'wobble').to eq 'plugh'
273
+ end
274
+ it 'is nil if the value is not found' do
275
+ subject['thud'] = 'wibble'
276
+ subject['plugh'] = 'wobble'
277
+ expect(subject.key 'foo').to be_nil
278
+ end
279
+ end
280
+
281
+ describe '#keys' do
282
+ it 'is an array of all of the keys in the object' do
283
+ subject['foo'] = 'bar'
284
+ subject['waldo'] = 'fred'
285
+ subject['plugh'] = 'xyzzy'
286
+ expect(subject.keys).to eq ['foo', 'waldo', 'plugh']
287
+ end
288
+ end
289
+
290
+ describe '#length' do
291
+ it 'works' do
292
+ subject['wibble'] = 'foo'
293
+ subject['waldo'] = 'fred'
294
+ expect(subject.length).to eq 2
295
+ end
296
+ end
297
+
298
+ describe '#merge' do
299
+ it 'returns a new instance of the calling class' do
300
+ subject['wibble'] = 'foo'
301
+ another = hash_like_class.new
302
+ another['waldo'] = 'fred'
303
+ merged = subject.merge(another)
304
+ # clear them all to confirm we're not testing equality of anything other
305
+ # than that we have different instances
306
+ subject.data.clear
307
+ another.data.clear
308
+ merged.data.clear
309
+ expect(subject.merge(another).class).to eq subject.class # same class but'
310
+ expect(merged).to_not be subject # different instance
311
+ expect(merged).to_not be another # different instance
312
+ end
313
+ # it 'adds new entries to the end' do
314
+ # subject['wibble'] = 'foo'
315
+ # subject['plugh'] = 'xyzzy'
316
+ # another = hash_like_class.new
317
+ # another['waldo'] = 'fred'
318
+ # new_instance = subject.merge(another)
319
+ # expect(new_instance.data.last).to eq ['waldo', 'fred']
320
+ # end
321
+ it 'retains the index position for existing entries, replacing the value' do
322
+ subject['wibble'] = 'foo'
323
+ subject['plugh'] = 'xyzzy'
324
+ subject['foo'] = 'bar'
325
+ another = hash_like_class.new
326
+ another['plugh'] = 'fred'
327
+ new_instance = subject.merge(another)
328
+ expect(new_instance['plugh']).to eq 'fred'
329
+ expect(new_instance[new_instance.keys[1]]).to eq 'fred'
330
+ end
331
+ it 'takes a block' do
332
+ subject['wibble'] = 'foo'
333
+ subject['plugh'] = 'xyzzy'
334
+ subject['foo'] = 'bar'
335
+ another = hash_like_class.new
336
+ another['plugh'] = 'fred'
337
+ # e.g. give a block that turns common keys into an Array
338
+ new_instance = subject.merge(another) { |k, old_val,new_val| [old_val, new_val] }
339
+ expect(new_instance['wibble']).to eq 'foo'
340
+ expect(new_instance['plugh']).to eq ['xyzzy', 'fred']
341
+ expect(new_instance['foo']).to eq 'bar'
342
+ expect(new_instance.data).to eq({'wibble'=>'foo', 'plugh'=>['xyzzy', 'fred'], 'foo'=>'bar'})
343
+ end
344
+ describe 'takes anything that implements `#each { |k,v| block }` and #has_key?' do
345
+ it 'returns a new instance of the calling class' do
346
+ subject['wibble'] = 'foo'
347
+ another = {'waldo' => 'fred'}
348
+ merged = subject.merge(another)
349
+ # clear them all to confirm we're not testing equality of anything other
350
+ # than that we have different instances
351
+ subject.data.clear
352
+ another.clear
353
+ merged.data.clear
354
+ expect(subject.merge(another).class).to eq subject.class # same class but'
355
+ expect(merged).to_not be subject # different instance
356
+ expect(merged).to_not be another # different instance
357
+ end
358
+ # it 'adds new entries to the end' do
359
+ # subject['wibble'] = 'foo'
360
+ # subject['plugh'] = 'xyzzy'
361
+ # another = {'waldo' => 'fred'}
362
+ # new_instance = subject.merge(another)
363
+ # expect(new_instance.data.last).to eq ['waldo', 'fred']
364
+ # end
365
+ it 'retains the index position for existing entries, replacing the value' do
366
+ subject['wibble'] = 'foo'
367
+ subject['plugh'] = 'xyzzy'
368
+ subject['foo'] = 'bar'
369
+ another = {'plugh' => 'fred' }
370
+ another['plugh'] = 'fred'
371
+ new_instance = subject.merge(another)
372
+ expect(new_instance['plugh']).to eq 'fred'
373
+ expect(new_instance[new_instance.keys[1]]).to eq 'fred'
374
+ end
375
+ it 'takes a block' do
376
+ subject['wibble'] = 'foo'
377
+ subject['plugh'] = 'xyzzy'
378
+ subject['foo'] = 'bar'
379
+ another = {'plugh' => 'fred'}
380
+ # e.g. give a block that turns common keys into an Array
381
+ new_instance = subject.merge(another) { |k, old_val,new_val| [old_val, new_val] }
382
+ expect(new_instance['wibble']).to eq 'foo'
383
+ expect(new_instance['plugh']).to eq ['xyzzy', 'fred']
384
+ expect(new_instance['foo']).to eq 'bar'
385
+ expect(new_instance.data).to eq({'wibble'=>'foo', 'plugh'=>['xyzzy', 'fred'], 'foo'=>'bar'})
386
+ end
387
+ end
388
+ end
389
+
390
+ describe '#merge!' do
391
+ it 'returns the instance on which is was called' do
392
+ subject['wibble'] = 'foo'
393
+ another = hash_like_class.new
394
+ another['waldo'] = 'fred'
395
+ expect(subject.merge!(another)).to eq subject # same instance
396
+ end
397
+ it 'adds new entries to the end' do
398
+ subject['wibble'] = 'foo'
399
+ subject['plugh'] = 'xyzzy'
400
+ another = hash_like_class.new
401
+ another['waldo'] = 'fred'
402
+ subject.merge!(another)
403
+ expect(subject.data[subject.data.keys.last]).to eq 'fred'
404
+ end
405
+ it 'retains the index position for existing entries, replacing the value' do
406
+ subject['wibble'] = 'foo'
407
+ subject['plugh'] = 'xyzzy'
408
+ subject['foo'] = 'bar'
409
+ another = hash_like_class.new
410
+ another['plugh'] = 'fred'
411
+ subject.merge!(another)
412
+ expect(subject['plugh']).to eq 'fred'
413
+ expect(subject.data[subject.keys[1]]).to eq 'fred'
414
+ end
415
+ it 'takes a block' do
416
+ subject['wibble'] = 'foo'
417
+ subject['plugh'] = 'xyzzy'
418
+ subject['foo'] = 'bar'
419
+ another = hash_like_class.new
420
+ another['plugh'] = 'fred'
421
+ # e.g. give a block that turns common keys into an Array
422
+ subject.merge!(another) { |k, old_val,new_val| [old_val, new_val] }
423
+ expect(subject['wibble']).to eq 'foo'
424
+ expect(subject['plugh']).to eq ['xyzzy', 'fred']
425
+ expect(subject['foo']).to eq 'bar'
426
+ expect(subject.data).to eq({'wibble'=>'foo', 'plugh'=>['xyzzy', 'fred'], 'foo'=>'bar'})
427
+ end
428
+ describe 'takes anything that implements `#each { |k,v| block }` and #has_key?' do
429
+ it 'returns a new instance of the calling class' do
430
+ subject['wibble'] = 'foo'
431
+ another = {'waldo' => 'fred'}
432
+ expect(subject.merge!(another)).to eq subject # same instance
433
+ end
434
+ it 'adds new entries to the end' do
435
+ subject['wibble'] = 'foo'
436
+ subject['plugh'] = 'xyzzy'
437
+ another = {'waldo' => 'fred'}
438
+ subject.merge!(another)
439
+ expect(subject.data[subject.data.keys.last]).to eq 'fred'
440
+ end
441
+ it 'retains the index position for existing entries, replacing the value' do
442
+ subject['wibble'] = 'foo'
443
+ subject['plugh'] = 'xyzzy'
444
+ subject['foo'] = 'bar'
445
+ another = {'plugh' => 'fred' }
446
+ subject.merge!(another)
447
+ expect(subject['plugh']).to eq 'fred'
448
+ expect(subject.data[subject.keys[1]]).to eq 'fred'
449
+ end
450
+ it 'takes a block' do
451
+ subject['wibble'] = 'foo'
452
+ subject['plugh'] = 'xyzzy'
453
+ subject['foo'] = 'bar'
454
+ another = {'plugh' => 'fred'}
455
+ subject.merge!(another) { |k, old_val,new_val| "#{k}, #{old_val}, #{new_val}" }
456
+ expect(subject['wibble']).to eq 'foo'
457
+ expect(subject['plugh']).to eq 'plugh, xyzzy, fred'
458
+ expect(subject['foo']).to eq 'bar'
459
+ expect(subject.data).to eq({'wibble'=>'foo', 'plugh'=>'plugh, xyzzy, fred', 'foo'=>'bar'})
460
+ end
461
+ end
462
+ end
463
+
464
+ describe '#reject!' do
465
+ it 'can take a block' do
466
+ subject['wibble'] = 'foo'
467
+ subject['waldo'] = 'fred'
468
+ subject['plugh'] = 'xyzzy'
469
+ expect { |b| subject.reject!(&b) }.to yield_successive_args(['wibble', 'foo'], ['waldo', 'fred'], ['plugh', 'xyzzy'])
470
+ end
471
+ it 'returns the instance if there were changes' do
472
+ subject['wibble'] = 'foo'
473
+ subject['waldo'] = 'fred'
474
+ subject['plugh'] = 'xyzzy'
475
+ expect( subject.reject! { |k| k.start_with?('w') } ).to be subject
476
+ end
477
+ it 'returns nil if there were no changes' do
478
+ subject['wibble'] = 'foo'
479
+ subject['waldo'] = 'fred'
480
+ subject['plugh'] = 'xyzzy'
481
+ expect( subject.reject! { |k| k.start_with?('X') } ).to be_nil
482
+ end
483
+ it 'works' do
484
+ subject['wibble'] = 'foo'
485
+ subject['waldo'] = 'fred'
486
+ subject['plugh'] = 'xyzzy'
487
+ subject.reject! { |k| k.start_with?('w') }
488
+ expect(subject.data).to eq({'plugh' => 'xyzzy'})
489
+ end
490
+ end
491
+
492
+ describe '#select' do
493
+ it 'yields' do
494
+ subject['thud'] = 'wibble'
495
+ subject['plugh'] = 'wobble'
496
+ subject['waldo'] = 'fred'
497
+ expect { |b| subject.select(&b) }.to yield_successive_args(['thud', 'wibble'], ['plugh', 'wobble'], ['waldo', 'fred'])
498
+ end
499
+ it 'returns a new instance of the class' do
500
+ subject['thud'] = 'wibble'
501
+ subject['plugh'] = 'wobble'
502
+ subject['waldo'] = 'fred'
503
+ expect( subject.select{ |k,v| true }.class ).to eq subject.class
504
+ expect( subject.select{ |k,v| true } ).to_not eq subject
505
+ end
506
+ it 'selects but doesn\'t delete from the original instance' do
507
+ subject['thud'] = 'wibble'
508
+ subject['plugh'] = 'wobble'
509
+ subject['waldo'] = 'fred'
510
+ expect( subject.select{ |k,v| k.include?('u') }.data ).to eq({'thud'=>'wibble', 'plugh'=>'wobble'})
511
+ expect( subject.data ).to eq subject.data
512
+ end
513
+ end
514
+
515
+ describe '#select!' do
516
+ it 'can take a block' do
517
+ subject['wibble'] = 'foo'
518
+ subject['waldo'] = 'fred'
519
+ subject['plugh'] = 'xyzzy'
520
+ expect { |b| subject.select!(&b) }.to yield_successive_args(['wibble', 'foo'], ['waldo', 'fred'], ['plugh', 'xyzzy'])
521
+ end
522
+ it 'returns nil if there were no changes' do
523
+ subject['wibble'] = 'foo'
524
+ subject['waldo'] = 'fred'
525
+ subject['wobble'] = 'xyzzy'
526
+ expect( subject.select! { |k,v| k.start_with?('w') } ).to be_nil
527
+ end
528
+ it 'returns the instance if there were changes' do
529
+ subject['wibble'] = 'foo'
530
+ subject['waldo'] = 'fred'
531
+ subject['plugh'] = 'xyzzy'
532
+ expect( subject.select! { |k,v| k.start_with?('w') } ).to eq subject
533
+ end
534
+ it 'works' do
535
+ subject['wibble'] = 'foo'
536
+ subject['waldo'] = 'fred'
537
+ subject['plugh'] = 'xyzzy'
538
+ subject.select! { |k,v| k.start_with?('p') }
539
+ expect(subject.data).to eq({'plugh' => 'xyzzy'})
540
+ end
541
+ end
542
+
543
+ describe '#shift' do
544
+ it 'returns the first element in the hash without a param' do
545
+ subject['thud'] = 'wibble'
546
+ subject['plugh'] = 'wobble'
547
+ expect(subject.shift).to eq ['thud','wibble']
548
+ expect(subject.data).to eq({'plugh' => 'wobble'})
549
+ end
550
+ end
551
+
552
+ describe 'store' do
553
+ it 'works as an alias for []=' do
554
+ subject.store('foo', 'bar')
555
+ expect(subject.data).to eq({'foo' => 'bar'})
556
+ end
557
+ end
558
+
559
+ describe '#values' do
560
+ it 'is an array of all of the keys in the object' do
561
+ subject['foo'] = 'bar'
562
+ subject['waldo'] = 'fred'
563
+ subject['plugh'] = 'xyzzy'
564
+ expect(subject.values).to eq ['bar', 'fred', 'xyzzy']
565
+ end
566
+ end
567
+
568
+ end
569
+