functional-ruby 0.7.7 → 1.0.0

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