functional-ruby 0.7.7 → 1.0.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +92 -152
  3. data/doc/memo.txt +192 -0
  4. data/doc/pattern_matching.txt +485 -0
  5. data/doc/protocol.txt +221 -0
  6. data/doc/record.txt +144 -0
  7. data/doc/thread_safety.txt +8 -0
  8. data/lib/functional.rb +48 -18
  9. data/lib/functional/abstract_struct.rb +161 -0
  10. data/lib/functional/delay.rb +117 -0
  11. data/lib/functional/either.rb +222 -0
  12. data/lib/functional/memo.rb +93 -0
  13. data/lib/functional/method_signature.rb +72 -0
  14. data/lib/functional/option.rb +209 -0
  15. data/lib/functional/pattern_matching.rb +117 -100
  16. data/lib/functional/protocol.rb +157 -0
  17. data/lib/functional/protocol_info.rb +193 -0
  18. data/lib/functional/record.rb +155 -0
  19. data/lib/functional/type_check.rb +112 -0
  20. data/lib/functional/union.rb +152 -0
  21. data/lib/functional/version.rb +3 -1
  22. data/spec/functional/abstract_struct_shared.rb +154 -0
  23. data/spec/functional/complex_pattern_matching_spec.rb +205 -0
  24. data/spec/functional/configuration_spec.rb +17 -0
  25. data/spec/functional/delay_spec.rb +147 -0
  26. data/spec/functional/either_spec.rb +237 -0
  27. data/spec/functional/memo_spec.rb +207 -0
  28. data/spec/functional/option_spec.rb +292 -0
  29. data/spec/functional/pattern_matching_spec.rb +279 -276
  30. data/spec/functional/protocol_info_spec.rb +444 -0
  31. data/spec/functional/protocol_spec.rb +274 -0
  32. data/spec/functional/record_spec.rb +175 -0
  33. data/spec/functional/type_check_spec.rb +103 -0
  34. data/spec/functional/union_spec.rb +110 -0
  35. data/spec/spec_helper.rb +6 -4
  36. metadata +55 -45
  37. data/lib/functional/behavior.rb +0 -138
  38. data/lib/functional/behaviour.rb +0 -2
  39. data/lib/functional/catalog.rb +0 -487
  40. data/lib/functional/collection.rb +0 -403
  41. data/lib/functional/inflect.rb +0 -127
  42. data/lib/functional/platform.rb +0 -120
  43. data/lib/functional/search.rb +0 -132
  44. data/lib/functional/sort.rb +0 -41
  45. data/lib/functional/utilities.rb +0 -189
  46. data/md/behavior.md +0 -188
  47. data/md/catalog.md +0 -32
  48. data/md/collection.md +0 -32
  49. data/md/inflect.md +0 -32
  50. data/md/pattern_matching.md +0 -512
  51. data/md/platform.md +0 -32
  52. data/md/search.md +0 -32
  53. data/md/sort.md +0 -32
  54. data/md/utilities.md +0 -55
  55. data/spec/functional/behavior_spec.rb +0 -528
  56. data/spec/functional/catalog_spec.rb +0 -1206
  57. data/spec/functional/collection_spec.rb +0 -752
  58. data/spec/functional/inflect_spec.rb +0 -85
  59. data/spec/functional/integration_spec.rb +0 -205
  60. data/spec/functional/platform_spec.rb +0 -501
  61. data/spec/functional/search_spec.rb +0 -187
  62. data/spec/functional/sort_spec.rb +0 -61
  63. data/spec/functional/utilities_spec.rb +0 -277
@@ -1,1206 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Functional
4
-
5
- describe Catalog do
6
-
7
- let(:hash_sample) {
8
- {
9
- 7 => 8,
10
- 17 => 14,
11
- 27 => 6,
12
- 32 => 12,
13
- 37 => 8,
14
- 22 => 4,
15
- 42 => 3,
16
- 12 => 8,
17
- 47 => 2
18
- }.freeze
19
- }
20
-
21
- let(:hash_sample_for_block) {
22
- {
23
- 7 => {:count => 8},
24
- 17 => {:count => 14},
25
- 27 => {:count => 6},
26
- 32 => {:count => 12},
27
- 37 => {:count => 8},
28
- 22 => {:count => 4},
29
- 42 => {:count => 3},
30
- 12 => {:count => 8},
31
- 47 => {:count => 2}
32
- }.freeze
33
- }
34
-
35
- let(:catalog_sample) {
36
- [
37
- [7, 8],
38
- [17, 14],
39
- [27, 6],
40
- [32, 12],
41
- [37, 8],
42
- [22, 4],
43
- [42, 3],
44
- [12, 8],
45
- [47, 2]
46
- ].freeze
47
- }
48
-
49
- let(:catalog_sample_for_block) {
50
- [
51
- [7, {:count => 8}],
52
- [17, {:count => 14}],
53
- [27, {:count => 6}],
54
- [32, {:count => 12}],
55
- [37, {:count => 8}],
56
- [22, {:count => 4}],
57
- [42, {:count => 3}],
58
- [12, {:count => 8}],
59
- [47, {:count => 2}]
60
- ].freeze
61
- }
62
-
63
- context 'creation' do
64
-
65
- context '#initialize' do
66
-
67
- it 'creates an empty Catalog when no arguments are given' do
68
- catalog = Catalog.new
69
- catalog.should be_empty
70
- end
71
-
72
- it 'creates a Catalog from a hash' do
73
- catalog = Catalog.new(hash_sample, :from => :hash)
74
- catalog.size.should eq 9
75
- end
76
-
77
- it 'creates a Catalog from an array' do
78
- catalog = Catalog.new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], :from => :array)
79
- catalog.size.should eq 5
80
- catalog.first.should eq [1, 2]
81
- catalog.last.should eq [9, 10]
82
- end
83
-
84
- it 'creates a Catalog from a catalog' do
85
- catalog = Catalog.new(catalog_sample, :from => :catalog)
86
- catalog.size.should eq 9
87
- catalog.first.should eq catalog_sample.first
88
- catalog.last.should eq catalog_sample.last
89
-
90
- catalog = Catalog.new(catalog_sample, :from => :catalogue)
91
- catalog.size.should eq 9
92
- catalog.first.should eq catalog_sample.first
93
- catalog.last.should eq catalog_sample.last
94
- end
95
-
96
- it 'assumes the arguments are a catalog when no :from is given' do
97
- catalog = Catalog.new(catalog_sample)
98
- catalog.size.should eq 9
99
- catalog.first.should eq catalog_sample.first
100
- catalog.last.should eq catalog_sample.last
101
- end
102
-
103
- it 'creates an empty Catalog when :from is unrecognized' do
104
- catalog = Catalog.new(hash_sample, :from => :bogus)
105
- catalog.should be_empty
106
- end
107
-
108
- it 'uses the given block to create key/value pairs' do
109
- sample = [
110
- {:x => 1, :y => 2},
111
- {:x => 3, :y => 4},
112
- {:x => 5, :y => 6}
113
- ]
114
-
115
- expected = [ [1, 2], [3, 4], [5, 6] ]
116
-
117
- catalog = Catalog.new(sample){|item| [ item[:x], item[:y] ] }
118
- catalog.should eq expected
119
- end
120
- end
121
-
122
- context '#from_array' do
123
-
124
- it 'creates a Catalog from an Array' do
125
- catalog = Catalog.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
126
- catalog.size.should eq 5
127
- catalog.first.should eq [1, 2]
128
- catalog.last.should eq [9, 10]
129
-
130
- catalog = Catalog.from_array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
131
- catalog.size.should eq 5
132
- catalog.first.should eq [1, 2]
133
- catalog.last.should eq [9, 10]
134
- end
135
-
136
- it 'creates an empty Catalog from an empty Array' do
137
- catalog = Catalog.from_array([])
138
- catalog.should be_empty
139
- end
140
-
141
- it 'throws out the last element when given an odd-size array' do
142
- catalog = Catalog.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
143
- catalog.size.should eq 5
144
- catalog.first.should eq [1, 2]
145
- catalog.last.should eq [9, 10]
146
- end
147
-
148
- it 'creates a Catalog when given an array and a block' do
149
- sample = [
150
- {:count => 13},
151
- {:count => 18},
152
- {:count => 13},
153
- {:count => 14},
154
- {:count => 13},
155
- {:count => 16},
156
- {:count => 14},
157
- {:count => 13}
158
- ].freeze
159
-
160
- catalog = Catalog.from_array(sample){|item| item[:count]}
161
- catalog.size.should eq 4
162
- catalog.first.should eq [13, 18]
163
- catalog.last.should eq [14, 13]
164
- end
165
- end
166
-
167
- context '#from_hash' do
168
-
169
- it 'creates a Catalog from a hash' do
170
- catalog = Catalog.from_hash(hash_sample)
171
- catalog.size.should eq 9
172
-
173
- catalog = Catalog.from_hash(:one => 1, :two => 2, :three => 3)
174
- catalog.size.should eq 3
175
- end
176
-
177
- it 'creates an empty Catalog from an empty hash' do
178
- catalog = Catalog.from_hash({})
179
- catalog.should be_empty
180
- end
181
-
182
- it 'creates a Catalog when given a hash and a block' do
183
- catalog = Catalog.from_hash(hash_sample_for_block){|item| item[:count]}
184
- catalog.size.should eq 9
185
- end
186
- end
187
-
188
- context '#from_catalog' do
189
-
190
- context 'creates a Catalog from a catalog' do
191
-
192
- specify do
193
- catalog = Catalog.from_catalog(catalog_sample)
194
- catalog.size.should eq 9
195
- catalog.first.should eq catalog_sample.first
196
- catalog.last.should eq catalog_sample.last
197
- end
198
-
199
- specify do
200
- catalog = Catalog.from_catalog([:one, 1], [:two, 2], [:three, 3])
201
- catalog.size.should eq 3
202
- catalog.first.should eq [:one, 1]
203
- catalog.last.should eq [:three, 3]
204
- end
205
-
206
- specify do
207
- catalog = Catalog.from_catalog([[:one, 1], [:two, 2], [:three, 3]])
208
- catalog.size.should eq 3
209
- catalog.first.should eq [:one, 1]
210
- catalog.last.should eq [:three, 3]
211
- end
212
-
213
- specify do
214
- catalog = Catalog.from_catalog([:one, 1], [:two, 2])
215
- catalog.size.should eq 2
216
- catalog.first.should eq [:one, 1]
217
- catalog.last.should eq [:two, 2]
218
- end
219
-
220
- specify do
221
- catalog = Catalog.from_catalog([[:one, 1], [:two, 2]])
222
- catalog.size.should eq 2
223
- catalog.first.should eq [:one, 1]
224
- catalog.last.should eq [:two, 2]
225
- end
226
-
227
- specify do
228
- catalog = Catalog.from_catalog([:one, 1])
229
- catalog.size.should eq 1
230
- catalog.first.should eq [:one, 1]
231
- catalog.last.should eq [:one, 1]
232
- end
233
-
234
- specify do
235
- catalog = Catalog.from_catalog([[:one, 1]])
236
- catalog.size.should eq 1
237
- catalog.first.should eq [:one, 1]
238
- catalog.last.should eq [:one, 1]
239
- end
240
- end
241
-
242
- it 'creates an empty Catalog from an empty catalog' do
243
- catalog = Catalog.from_catalog({})
244
- catalog.should be_empty
245
- end
246
-
247
- it 'creates a Catalog when given a catalog and a block' do
248
- catalog = Catalog.from_catalog(catalog_sample_for_block){|item| item[:count]}
249
- catalog.size.should eq 9
250
- catalog.first.should eq [catalog_sample.first[0], catalog_sample.first[1]]
251
- catalog.last.should eq [catalog_sample.last[0], catalog_sample.last[1]]
252
- end
253
- end
254
- end
255
-
256
- context '#==' do
257
-
258
- it 'returns true for equal catalogs' do
259
- catalog_1 = Catalog.from_hash(hash_sample)
260
- catalog_2 = Catalog.from_hash(hash_sample)
261
- catalog_1.should eq catalog_2
262
- end
263
-
264
-
265
- it 'returns false for unequal catalogs' do
266
- catalog_1 = Catalog.new
267
- catalog_2 = Catalog.from_hash(hash_sample)
268
- catalog_1.should_not eq catalog_2
269
- end
270
-
271
- it 'compares with an equal Catalog object' do
272
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
273
- catalog_2 = Catalog.new([[1, 1], [2, 2], [3, 3]])
274
- catalog_1.should == catalog_2
275
- end
276
-
277
- it 'compares with an equal catalog array' do
278
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
279
- catalog_2 = [[1, 1], [2, 2], [3, 3]]
280
- catalog_1.should == catalog_2
281
- end
282
-
283
- it 'compares with a non-equal Catalog objects' do
284
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
285
- catalog_2 = Catalog.new([[1, 1], [2, 2], [3, 3], [4, 4]])
286
- catalog_1.should_not == catalog_2
287
- end
288
-
289
- it 'compares with a non-equal catalog array' do
290
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
291
- catalog_2 = [[1, 1], [2, 2], [3, 3], [4, 4]]
292
- catalog_1.should_not == catalog_2
293
- end
294
-
295
- it 'returns false when compared with any other object' do
296
- Catalog.new.should_not == :foo
297
- end
298
- end
299
-
300
- context '#!=' do
301
-
302
- it 'returns false for equal catalogs' do
303
- catalog_1 = Catalog.from_hash(hash_sample)
304
- catalog_2 = Catalog.from_hash(hash_sample)
305
- (catalog_1 != catalog_2).should be_false
306
- end
307
-
308
-
309
- it 'returns true for unequal catalogs' do
310
- catalog_1 = Catalog.from_hash(hash_sample)
311
- catalog_2 = Catalog.new
312
- (catalog_1 != catalog_2).should be_true
313
- end
314
-
315
- it 'compares with an equal Catalog object' do
316
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
317
- catalog_2 = Catalog.new([[1, 1], [2, 2], [3, 3]])
318
- (catalog_1 != catalog_2).should be_false
319
- end
320
-
321
- it 'compares with an equal catalog array' do
322
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
323
- catalog_2 = [[1, 1], [2, 2], [3, 3]]
324
- (catalog_1 != catalog_2).should be_false
325
- end
326
-
327
- it 'compares with a non-equal Catalog objects' do
328
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
329
- catalog_2 = Catalog.new([[1, 1], [2, 2], [3, 3], [4, 4]])
330
- (catalog_1 != catalog_2).should be_true
331
- end
332
-
333
- it 'compares with a non-equal catalog array' do
334
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
335
- catalog_2 = [[1, 1], [2, 2], [3, 3], [4, 4]]
336
- (catalog_1 != catalog_2).should be_true
337
- end
338
-
339
- it 'returns true when compared with any other object' do
340
- (Catalog.new != :foo).should be_true
341
- end
342
- end
343
-
344
- context '<=>' do
345
-
346
- let(:low) { [[1, 1], [2, 2]] }
347
- let(:high) { [[3, 3], [4, 4]] }
348
-
349
- it 'returns a negative number when less than another Catalog' do
350
- small = Catalog.new(low)
351
- big = Catalog.new(high)
352
- (small <=> big).should < 0
353
- end
354
-
355
- it 'returns a negative number when less than a catalog' do
356
- small = Catalog.new(low)
357
- (small <=> high).should < 0
358
- end
359
-
360
- it 'returns zero when equal to another Catalog' do
361
- small = Catalog.new(low)
362
- big = Catalog.new(low)
363
- (small <=> big).should eq 0
364
- end
365
-
366
- it 'returns zero when equal to a catalog' do
367
- small = Catalog.new(low)
368
- (small <=> low).should eq 0
369
- end
370
-
371
- it 'returns a positive number when greater than another Catalog' do
372
- small = Catalog.new(low)
373
- big = Catalog.new(high)
374
- (big <=> small).should > 0
375
- end
376
-
377
- it 'returns a positive number when greater than a catalog' do
378
- big = Catalog.new(high)
379
- (big <=> low).should > 0
380
- end
381
-
382
- it 'raises an error when compated to an invalid object' do
383
- lambda {
384
- Catalog.new <=> :foo
385
- }.should raise_error(TypeError)
386
- end
387
- end
388
-
389
- context '#[]' do
390
-
391
- it 'returns nil when empty' do
392
- catalog = Catalog.new
393
- catalog[0].should be_nil
394
- end
395
-
396
- it 'returns the element at a valid positive index' do
397
- catalog = Catalog.from_catalog(catalog_sample)
398
- catalog[0].should eq catalog_sample[0]
399
- end
400
-
401
- it 'returns the element at a valid negative index' do
402
- catalog = Catalog.from_catalog(catalog_sample)
403
- catalog[-1].should eq catalog_sample[-1]
404
- end
405
-
406
- it 'returns nil for an invalid positive index' do
407
- catalog = Catalog.from_catalog(catalog_sample)
408
- catalog[100].should be_nil
409
- end
410
-
411
- it 'returns nil for an invalid negative index' do
412
- catalog = Catalog.from_catalog(catalog_sample)
413
- catalog[-100].should be_nil
414
- end
415
- end
416
-
417
- context '#[]=' do
418
-
419
- let(:catalog) { Catalog.from_hash(:one => 1, :two => 2, :three => 3) }
420
-
421
- it 'accepts a one-element hash as a value' do
422
- catalog[0] = {:foo => :bar}
423
- catalog[0].should eq [:foo, :bar]
424
- end
425
-
426
- it 'accepts a two-element array as a value' do
427
- catalog[0] = [:foo, :bar]
428
- catalog[0].should eq [:foo, :bar]
429
- end
430
-
431
- it 'raises an exception when given in invalid value' do
432
- lambda {
433
- catalog[0] = :foo
434
- }.should raise_error(ArgumentError)
435
- end
436
-
437
- it 'updates the index when given a valid positive index' do
438
- catalog[1] = [:foo, :bar]
439
- catalog.should eq [[:one, 1], [:foo, :bar], [:three, 3]]
440
- end
441
-
442
- it 'updates the index when given an invalid negative index' do
443
- catalog[-2] = [:foo, :bar]
444
- catalog.should eq [[:one, 1], [:foo, :bar], [:three, 3]]
445
- end
446
-
447
- it 'raises an exception when given an invalid positive index' do
448
- lambda {
449
- catalog[100] = [:foo, :bar]
450
- }.should raise_error(ArgumentError)
451
- end
452
-
453
- it 'raises an exception when given an invalid negative index' do
454
- lambda {
455
- catalog[-100] = [:foo, :bar]
456
- }.should raise_error(ArgumentError)
457
- end
458
-
459
- end
460
-
461
- context '#&' do
462
-
463
- it 'returns a new Catalog object' do
464
- catalog_1 = Catalog.new
465
- catalog_2 = Catalog.new
466
- intersection = catalog_1 & catalog_2
467
- intersection.object_id.should_not eq catalog_1.object_id
468
- intersection.object_id.should_not eq catalog_2.object_id
469
- end
470
-
471
- it 'intersects two empty Catalogs' do
472
- catalog_1 = Catalog.new
473
- catalog_2 = Catalog.new
474
- intersection = catalog_1 & catalog_2
475
- intersection.should be_empty
476
- end
477
-
478
- it 'intersects an empty Catalog with a non-empty Catalog' do
479
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
480
- catalog_2 = Catalog.new
481
- intersection = catalog_1 & catalog_2
482
- intersection.should be_empty
483
- end
484
-
485
- it 'intersects two non-empty Catalogs' do
486
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
487
- catalog_2 = Catalog.new([[2, 2], [3, 3], [4, 4], [5, 5]])
488
- intersection = catalog_1 & catalog_2
489
- intersection.should eq [[2, 2], [3, 3]]
490
- end
491
-
492
- it 'intersects a Catalog object with a catalog' do
493
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
494
- catalog_2 = [[2, 2], [3, 3], [4, 4], [5, 5]]
495
- intersection = catalog_1 & catalog_2
496
- intersection.should eq [[2, 2], [3, 3]]
497
- end
498
-
499
- it 'removes duplicates when intersecting two non-empty Catalogs' do
500
- catalog_1 = Catalog.new([[1, 1], [1, 1], [1, 1], [2, 2], [3, 3]])
501
- catalog_2 = Catalog.new([[1, 1], [3, 3], [4, 4], [5, 5]])
502
- intersection = catalog_1 & catalog_2
503
- intersection.should eq [[1, 1], [3, 3]]
504
- end
505
-
506
- it 'raises an error when given a non-Catalog object' do
507
- lambda {
508
- catalog_1 = Catalog.new([[1, 1], [1, 1], [1, 1], [2, 2], [3, 3]])
509
- intersection = catalog_1 & :foo
510
- }.should raise_error(TypeError)
511
- end
512
- end
513
-
514
- context '#+' do
515
-
516
- it 'returns a new Catalog object' do
517
- catalog_1 = Catalog.new
518
- catalog_2 = Catalog.new
519
- sum = catalog_1 + catalog_2
520
- sum.object_id.should_not eq catalog_1.object_id
521
- sum.object_id.should_not eq catalog_2.object_id
522
- end
523
-
524
- it 'adds two empty Catalogs' do
525
- catalog_1 = Catalog.new
526
- catalog_2 = Catalog.new
527
- sum = catalog_1 + catalog_2
528
- sum.should be_empty
529
- end
530
-
531
- it 'adds an empty Catalog with a non-empty Catalog' do
532
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
533
- catalog_2 = Catalog.new
534
- sum = catalog_1 + catalog_2
535
- sum.should eq [[1, 1], [2, 2], [3, 3]]
536
- end
537
-
538
- it 'adds two non-empty Catalogs' do
539
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
540
- catalog_2 = Catalog.new([[2, 2], [3, 3], [4, 4], [5, 5]])
541
- sum = catalog_1 + catalog_2
542
- sum.should eq [[1, 1], [2, 2], [3, 3], [2, 2], [3, 3], [4, 4], [5, 5]]
543
- end
544
-
545
- it 'adds a Catalog object with a catalog' do
546
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
547
- catalog_2 = [[2, 2], [3, 3], [4, 4], [5, 5]]
548
- sum = catalog_1 + catalog_2
549
- sum.should eq [[1, 1], [2, 2], [3, 3],[2, 2], [3, 3], [4, 4], [5, 5] ]
550
- end
551
-
552
- it 'raises an error when given a non-Catalog object' do
553
- lambda {
554
- catalog_1 = Catalog.new([[1, 1], [1, 1], [1, 1], [2, 2], [3, 3]])
555
- sum = catalog_1 + :foo
556
- }.should raise_error(TypeError)
557
- end
558
- end
559
-
560
- context '#|' do
561
-
562
- it 'returns a new Catalog object' do
563
- catalog_1 = Catalog.new
564
- catalog_2 = Catalog.new
565
- union = catalog_1 | catalog_2
566
- union.object_id.should_not eq catalog_1.object_id
567
- union.object_id.should_not eq catalog_2.object_id
568
- end
569
-
570
- it 'unions two empty Catalogs' do
571
- catalog_1 = Catalog.new
572
- catalog_2 = Catalog.new
573
- union = catalog_1 | catalog_2
574
- union.should be_empty
575
- end
576
-
577
- it 'unions an empty Catalog with a non-empty Catalog' do
578
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
579
- catalog_2 = Catalog.new
580
- union = catalog_1 | catalog_2
581
- union.should eq [[1, 1], [2, 2], [3, 3]]
582
- end
583
-
584
- it 'unions two non-empty Catalogs' do
585
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
586
- catalog_2 = Catalog.new([[4, 4], [5, 5]])
587
- union = catalog_1 | catalog_2
588
- union.should eq [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]]
589
- end
590
-
591
- it 'unions a Catalog object with a catalog' do
592
- catalog_1 = Catalog.new([[1, 1], [2, 2], [3, 3]])
593
- catalog_2 = [[4, 4], [5, 5]]
594
- union = catalog_1 | catalog_2
595
- union.should eq [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]]
596
- end
597
-
598
- it 'removes duplicates when intersecting two non-empty Catalogs' do
599
- catalog_1 = Catalog.new([[1, 1], [1, 1], [1, 1], [2, 2], [3, 3]])
600
- catalog_2 = Catalog.new([[1, 1], [3, 3], [4, 4], [5, 5]])
601
- union = catalog_1 | catalog_2
602
- union.should eq [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]]
603
- end
604
-
605
- it 'raises an error when given a non-Catalog object' do
606
- lambda {
607
- catalog_1 = Catalog.new([[1, 1], [1, 1], [1, 1], [2, 2], [3, 3]])
608
- union = catalog_1 | :foo
609
- }.should raise_error(TypeError)
610
- end
611
- end
612
-
613
- context '#push' do
614
-
615
- it 'returns the Catalog' do
616
- catalog_1 = Catalog.new
617
- catalog_2 = catalog_1.push([1, 2])
618
- catalog_1.object_id.should eq catalog_2.object_id
619
- end
620
-
621
- it 'appends a two-element array onto the catalog' do
622
- catalog = Catalog.new([[1, 1], [2, 2]])
623
- catalog = catalog.push([3, 3])
624
- catalog.should eq [[1, 1], [2, 2], [3, 3]]
625
- end
626
-
627
- it 'appends a one-element hash onto the catalog' do
628
- catalog = Catalog.new([[1, 1], [2, 2]])
629
- catalog = catalog.push({3 => 3})
630
- catalog.should eq [[1, 1], [2, 2], [3, 3]]
631
- end
632
-
633
- it 'raises an error for an invalid datatype' do
634
- lambda {
635
- Catalog.new.push(:foo)
636
- }.should raise_error(TypeError)
637
- end
638
- end
639
-
640
- context '#pop' do
641
-
642
- it 'returns nil when empty' do
643
- Catalog.new.pop.should be_nil
644
- end
645
-
646
- it 'returns the last element' do
647
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
648
- pop = catalog.pop
649
- pop.should eq [3, 3]
650
- end
651
-
652
- it 'removes the last element' do
653
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
654
- catalog.pop
655
- catalog.should eq [[1, 1], [2, 2]]
656
- end
657
- end
658
-
659
- context '#peek' do
660
-
661
- it 'returns nil when empty' do
662
- Catalog.new.peek.should be_nil
663
- end
664
-
665
- it 'returns the last element' do
666
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
667
- peek = catalog.pop
668
- peek.should eq [3, 3]
669
- end
670
-
671
- it 'does not remove the last element' do
672
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
673
- catalog.peek
674
- catalog.should eq [[1, 1], [2, 2], [3, 3]]
675
- end
676
- end
677
-
678
- context '#keys' do
679
-
680
- it 'returns an empty array when empty' do
681
- Catalog.new.keys.should be_empty
682
- end
683
-
684
- it 'returns an array with all first elements in the catalog' do
685
- catalog = Catalog.new([[0, 0], [0, 1], [1, 0], [1, 1], [2, 2], [3, 3]])
686
- keys = catalog.keys
687
- keys.should eq [0, 0, 1, 1, 2, 3]
688
- end
689
- end
690
-
691
- context '#values' do
692
-
693
- it 'returns an empty array when empty' do
694
- Catalog.new.values.should be_empty
695
- end
696
-
697
- it 'returns an array with all last elements in the catalog' do
698
- catalog = Catalog.new([[0, 0], [0, 1], [1, 0], [1, 1], [2, 2], [3, 3]])
699
- values = catalog.values
700
- values.should eq [0, 1, 0, 1, 2, 3]
701
- end
702
- end
703
-
704
- context '#first' do
705
-
706
- it 'returns nil when empty' do
707
- Catalog.new.first.should be_nil
708
- end
709
-
710
- it 'returns the first element when not empty' do
711
- catalog = Catalog.from_catalog(catalog_sample)
712
- catalog.first.should == catalog_sample.first
713
- end
714
- end
715
-
716
- context '#last' do
717
-
718
- it 'returns nil when empty' do
719
- Catalog.new.last.should be_nil
720
- end
721
-
722
- it 'returns the last element when not empty' do
723
- catalog = Catalog.from_catalog(catalog_sample)
724
- catalog.last.should == catalog_sample.last
725
- end
726
- end
727
-
728
- context '#iterators' do
729
-
730
- let(:sample) {
731
- [
732
- [7, 8],
733
- [17, 14],
734
- [27, 6],
735
- [32, 12],
736
- [37, 8],
737
- [22, 4],
738
- [42, 3],
739
- [12, 8],
740
- [47, 2]
741
- ].freeze
742
- }
743
-
744
- let(:catalog) { Catalog.new(sample) }
745
-
746
- specify '#each' do
747
-
748
- index = 0
749
- catalog.each do |item|
750
- item.should eq sample[index]
751
- index = index + 1
752
- end
753
- end
754
-
755
- specify '#each_pair' do
756
-
757
- index = 0
758
- catalog.each_pair do |key, value|
759
- key.should eq sample[index].first
760
- value.should eq sample[index].last
761
- index = index + 1
762
- end
763
- end
764
-
765
- specify '#each_key' do
766
-
767
- index = 0
768
- catalog.each_key do |key|
769
- key.should eq sample[index].first
770
- index = index + 1
771
- end
772
- end
773
-
774
- specify '#each_value' do
775
-
776
- index = 0
777
- catalog.each_value do |value|
778
- value.should eq sample[index].last
779
- index = index + 1
780
- end
781
- end
782
- end
783
-
784
- context '#empty?' do
785
-
786
- it 'returns true when empty' do
787
- catalog = Catalog.new
788
- catalog.should be_empty
789
- end
790
-
791
- it 'returns false when not empty' do
792
- catalog = Catalog.from_hash(:one => 1, :two => 2, :three => 3)
793
- catalog.should_not be_empty
794
- end
795
- end
796
-
797
- context '#include?' do
798
-
799
- it 'returns false when empty' do
800
- Catalog.new.include?([1, 1]).should be_false
801
- end
802
-
803
- it 'returns true when the key/value array is found' do
804
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
805
- catalog.include?([2, 2]).should be_true
806
- end
807
-
808
- it 'returns true when the key/value pair is found' do
809
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
810
- catalog.include?(2, 2).should be_true
811
- end
812
-
813
- it 'returns true for given a one-element hash that matches' do
814
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
815
- catalog.include?({2 => 2}).should be_true
816
- end
817
-
818
- it 'returns true for an implicit one-element hash that matches' do
819
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
820
- catalog.include?(2 => 2).should be_true
821
- end
822
-
823
- it 'returns false when not found' do
824
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
825
- catalog.include?([4, 4]).should be_false
826
- end
827
-
828
- it 'returns false when given an invalid lookup item' do
829
- catalog = Catalog.new([[1, 1], [2, 2], [3, 3]])
830
- catalog.include?(:foo).should be_false
831
- end
832
- end
833
-
834
- context '#size' do
835
-
836
- it 'returns zero when is empty' do
837
- catalog = Catalog.new
838
- catalog.size.should eq 0
839
- end
840
-
841
- it 'returns the correct positive integer when not empty' do
842
- catalog = Catalog.from_hash(:one => 1, :two => 2, :three => 3)
843
- catalog.size.should eq 3
844
- end
845
- end
846
-
847
- context '#slice' do
848
-
849
- let(:catalog) {
850
- Catalog.new([[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]])
851
- }
852
-
853
- it 'returns the element at index' do
854
- slice = catalog.slice(2)
855
- slice.should eq [[3, 3]]
856
- slice.should be_a Catalog
857
- catalog.should eq [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]]
858
- end
859
-
860
- it 'returns the elements from index through length' do
861
- slice = catalog.slice(1, 2)
862
- slice.should eq [[2, 2], [3, 3]]
863
- slice.should be_a Catalog
864
- catalog.should eq [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]]
865
- end
866
-
867
- it 'returns a catalog specified by range' do
868
- slice = catalog.slice(1..2)
869
- slice.should eq [[2, 2], [3, 3]]
870
- slice.should be_a Catalog
871
- catalog.should eq [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]]
872
- end
873
-
874
- it 'returns the element at the negative index' do
875
- slice = catalog.slice(-3)
876
- slice.should eq [[3, 3]]
877
- slice.should be_a Catalog
878
- catalog.should eq [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]]
879
- end
880
-
881
- it 'returns an empty Catalog if the index is out of range' do
882
- slice = catalog.slice(10, 2)
883
- slice.should be_empty
884
- slice.should be_a Catalog
885
- catalog.should eq [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]]
886
- end
887
- end
888
-
889
- context '#slice!' do
890
-
891
- let(:catalog) {
892
- Catalog.new([[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]])
893
- }
894
-
895
- it 'returns the element at index' do
896
- slice = catalog.slice!(2)
897
- slice.should eq [[3, 3]]
898
- slice.should be_a Catalog
899
- catalog.should eq [[1, 1], [2, 2], [4, 4], [5, 5]]
900
- end
901
-
902
- it 'returns the elements from index through length' do
903
- slice = catalog.slice!(1, 2)
904
- slice.should eq [[2, 2], [3, 3]]
905
- slice.should be_a Catalog
906
- catalog.should eq [[1, 1], [4, 4], [5, 5]]
907
- end
908
-
909
- it 'returns a catalog specified by range' do
910
- slice = catalog.slice!(1..2)
911
- slice.should eq [[2, 2], [3, 3]]
912
- slice.should be_a Catalog
913
- catalog.should eq [[1, 1], [4, 4], [5, 5]]
914
- end
915
-
916
- it 'returns the element at the negative index' do
917
- slice = catalog.slice!(-3)
918
- slice.should eq [[3, 3]]
919
- slice.should be_a Catalog
920
- catalog.should eq [[1, 1], [2, 2], [4, 4], [5, 5]]
921
- end
922
-
923
- it 'returns an empty Catalog if the index is out of range' do
924
- slice = catalog.slice!(10, 2)
925
- slice.should be_empty
926
- slice.should be_a Catalog
927
- catalog.should eq [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5]]
928
- end
929
- end
930
-
931
- context 'sorting' do
932
-
933
- let(:unsorted_catalog) {
934
- [
935
- [7, 8],
936
- [17, 14],
937
- [27, 6],
938
- [32, 12],
939
- [37, 9],
940
- [22, 4],
941
- [42, 3],
942
- [12, 10],
943
- [47, 2]
944
- ].freeze
945
- }
946
-
947
- let(:catalog_sorted_by_key) {
948
- [
949
- [7, 8],
950
- [12, 10],
951
- [17, 14],
952
- [22, 4],
953
- [27, 6],
954
- [32, 12],
955
- [37, 9],
956
- [42, 3],
957
- [47, 2]
958
- ].freeze
959
- }
960
-
961
- let(:catalog_sorted_by_value) {
962
- [
963
- [47, 2],
964
- [42, 3],
965
- [22, 4],
966
- [27, 6],
967
- [7, 8],
968
- [37, 9],
969
- [12, 10],
970
- [32, 12],
971
- [17, 14]
972
- ].freeze
973
- }
974
-
975
- let(:catalog_reversed) {
976
- [
977
- [47, 2],
978
- [42, 3],
979
- [37, 9],
980
- [32, 12],
981
- [27, 6],
982
- [22, 4],
983
- [17, 14],
984
- [12, 10],
985
- [7, 8]
986
- ].freeze
987
- }
988
-
989
- let(:catalog) { Catalog.new(unsorted_catalog) }
990
-
991
- specify '#sort_by_key' do
992
- sorted = catalog.sort_by_key
993
- sorted.should eq catalog_sorted_by_key
994
- catalog.should eq unsorted_catalog
995
- sorted.should be_a Catalog
996
- end
997
-
998
- specify '#sort_by_key!' do
999
- sorted = catalog.sort_by_key!
1000
- sorted.should eq catalog_sorted_by_key
1001
- catalog.should eq catalog_sorted_by_key
1002
- sorted.object_id.should eq catalog.object_id
1003
- end
1004
-
1005
- specify '#sort_by_value' do
1006
- sorted = catalog.sort_by_value
1007
- sorted.should eq catalog_sorted_by_value
1008
- catalog.should eq unsorted_catalog
1009
- sorted.should be_a Catalog
1010
- end
1011
-
1012
- specify '#sort_by_value!' do
1013
- sorted = catalog.sort_by_value!
1014
- sorted.should eq catalog_sorted_by_value
1015
- catalog.should eq catalog_sorted_by_value
1016
- sorted.object_id.should eq catalog.object_id
1017
- end
1018
-
1019
- specify '#sort' do
1020
- sorted = catalog.sort
1021
- sorted.should eq catalog_sorted_by_key
1022
- catalog.should eq unsorted_catalog
1023
- sorted.should be_a Catalog
1024
- end
1025
-
1026
- specify '#sort!' do
1027
- sorted = catalog.sort!
1028
- sorted.should eq catalog_sorted_by_key
1029
- catalog.should eq catalog_sorted_by_key
1030
- sorted.object_id.should eq catalog.object_id
1031
- end
1032
-
1033
- specify '#sort with block' do
1034
- sorted = catalog.sort{|a, b| b <=> a}
1035
- sorted.should eq catalog_reversed
1036
- catalog.should eq unsorted_catalog
1037
- sorted.should be_a Catalog
1038
- end
1039
-
1040
- specify '#sort! with block' do
1041
- sorted = catalog.sort!{|a, b| b <=> a}
1042
- sorted.should eq catalog_reversed
1043
- catalog.should eq catalog_reversed
1044
- sorted.should be_a Catalog
1045
- end
1046
- end
1047
-
1048
- context 'conversion' do
1049
-
1050
- let(:sample) {
1051
- [
1052
- [7, 8],
1053
- [17, 14],
1054
- [47, 2]
1055
- ].freeze
1056
- }
1057
-
1058
- let(:sample_as_hash) {
1059
- {
1060
- 7 => 8,
1061
- 17 => 14,
1062
- 47 => 2
1063
- }.freeze
1064
- }
1065
-
1066
- let(:sample_as_array) {
1067
- [7, 8, 17, 14, 47, 2]
1068
- }
1069
-
1070
- let(:catalog) { Catalog.new(sample) }
1071
-
1072
- context '#to_a' do
1073
-
1074
- specify { Catalog.new.to_a.should eq [] }
1075
-
1076
- specify { catalog.to_a.should eq sample_as_array }
1077
- end
1078
-
1079
- context '#to_hash' do
1080
-
1081
- specify { Catalog.new.to_hash.should == {} }
1082
-
1083
- specify { catalog.to_hash.should eq sample_as_hash }
1084
- end
1085
-
1086
- context '#to_catalog' do
1087
- specify { Catalog.new.to_catalog.should eq [] }
1088
-
1089
- specify do
1090
- cat = catalog.to_catalog
1091
- cat.should eq sample
1092
- cat.should be_a Array
1093
- end
1094
- end
1095
-
1096
- context '#to_s' do
1097
-
1098
- specify { Catalog.new.to_s.should eq '[]' }
1099
- specify { Catalog.from_hash(:one => 1, :two => 2).to_s.should eq '[[:one, 1], [:two, 2]]' }
1100
- end
1101
- end
1102
-
1103
- context 'deletion' do
1104
-
1105
- let(:sample) {
1106
- [
1107
- [7, 8],
1108
- [17, 14],
1109
- [47, 2]
1110
- ].freeze
1111
- }
1112
-
1113
- let(:catalog) { Catalog.new(sample) }
1114
-
1115
- context 'delete' do
1116
-
1117
- it 'deletes the specified item' do
1118
- item = catalog.delete([17, 14])
1119
- item.should eq [17, 14]
1120
- catalog.should eq [[7, 8], [47, 2]]
1121
- end
1122
-
1123
- it 'deletes the item matching the given key/value pair' do
1124
- item = catalog.delete(17, 14)
1125
- item.should eq [17, 14]
1126
- catalog.should eq [[7, 8], [47, 2]]
1127
- end
1128
-
1129
- it 'deletes the item matching the given one-item hash' do
1130
- item = catalog.delete({17 => 14})
1131
- item.should eq [17, 14]
1132
- catalog.should eq [[7, 8], [47, 2]]
1133
- end
1134
-
1135
- it 'deletes the item matching the implied one-item hash' do
1136
- item = catalog.delete(17 => 14)
1137
- item.should eq [17, 14]
1138
- catalog.should eq [[7, 8], [47, 2]]
1139
- end
1140
-
1141
- it 'returns nil if the item is not found' do
1142
- item = catalog.delete([1, 2])
1143
- item.should be_nil
1144
- end
1145
-
1146
- it 'returns the result of the given block if the item is not found' do
1147
- item = catalog.delete([1, 2]){ 'not found' }
1148
- item.should eq 'not found'
1149
- end
1150
- end
1151
-
1152
- context 'delete_at' do
1153
-
1154
- it 'deletes the item at the specified index' do
1155
- item = catalog.delete_at(1)
1156
- item.should eq [17, 14]
1157
- catalog.should eq [[7, 8], [47, 2]]
1158
- end
1159
-
1160
- it 'returns nil if the index is out of range' do
1161
- item = catalog.delete_at(100)
1162
- item.should be_nil
1163
- end
1164
-
1165
- it 'returns the result of the given block if the index is out of range' do
1166
- item = catalog.delete_at(100){ 'not found' }
1167
- item.should eq 'not found'
1168
- end
1169
- end
1170
-
1171
- context 'delete_if' do
1172
-
1173
- it 'can yield the key/value pair on iteration' do
1174
- catalog.delete_if {|item| item.last > 5}
1175
- catalog.should eq [[47, 2]]
1176
- end
1177
-
1178
- it 'can yield the key and value separately on iteration' do
1179
- catalog.delete_if {|key, value| value > 5}
1180
- catalog.should eq [[47, 2]]
1181
- end
1182
-
1183
- it 'removes the matched items' do
1184
- catalog.delete_if {|key, value| value > 5}
1185
- catalog.should eq [[47, 2]]
1186
- end
1187
-
1188
- it 'does nothing on no matches' do
1189
- result = catalog.delete_if {|item| false }
1190
- result.should eq catalog
1191
- end
1192
-
1193
- it 'returns self' do
1194
- result = catalog.delete_if {|key, value| value > 5}
1195
- result.object_id.should eq catalog.object_id
1196
- end
1197
-
1198
- it 'raises an exception if a block is not given' do
1199
- lambda {
1200
- catalog.delete_if
1201
- }.should raise_error(ArgumentError)
1202
- end
1203
- end
1204
- end
1205
- end
1206
- end