functional-ruby 0.7.4 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,752 @@
1
+ require 'spec_helper'
2
+
3
+ module Functional
4
+
5
+ describe Collection do
6
+
7
+ context '#random_sample' do
8
+
9
+ specify { Collection.random_sample(100).length == 100 }
10
+ specify { Collection.random_sample(100, :min => 10).min >= 10 }
11
+ specify { Collection.random_sample(100, :max => 10).max >= 10 }
12
+
13
+ end
14
+
15
+ context 'bisection' do
16
+
17
+ context '#bisect_left' do
18
+
19
+ it 'returns nil when the sample is nil' do
20
+ Collection.bisect_left(nil, 10).should be_nil
21
+ end
22
+
23
+ it 'returns zero when the sample is empty' do
24
+ Collection.bisect_left([], 10).should eq 0
25
+ end
26
+
27
+ it 'returns the index when the item is not in the sample' do
28
+ sample = [10, 20, 30]
29
+ Collection.bisect_left(sample, 15).should eq 1
30
+ Collection.bisect_left(sample, 25).should eq 2
31
+ end
32
+
33
+ it 'returns the index when the item is in the sample' do
34
+ sample = [10, 20, 30]
35
+ Collection.bisect_left(sample, 10).should eq 0
36
+ Collection.bisect_left(sample, 20).should eq 1
37
+ Collection.bisect_left(sample, 30).should eq 2
38
+ end
39
+
40
+ it 'returns the index when the item is not in the sample with a block' do
41
+ sample = [
42
+ {:count => 10},
43
+ {:count => 20},
44
+ {:count => 30}
45
+ ]
46
+ Collection.bisect_left(sample, 15){|x| x[:count]}.should eq 1
47
+ Collection.bisect_left(sample, 25){|x| x[:count]}.should eq 2
48
+ end
49
+
50
+ it 'returns the index when the item is in the sample with a block' do
51
+ sample = [
52
+ {:count => 10},
53
+ {:count => 20},
54
+ {:count => 30}
55
+ ]
56
+ Collection.bisect_left(sample, 10){|x| x[:count]}.should eq 0
57
+ Collection.bisect_left(sample, 20){|x| x[:count]}.should eq 1
58
+ Collection.bisect_left(sample, 30){|x| x[:count]}.should eq 2
59
+ end
60
+ end
61
+
62
+ context '#bisect_right' do
63
+
64
+ it 'returns nil when the sample is nil' do
65
+ Collection.bisect_right(nil, 10).should be_nil
66
+ end
67
+
68
+ it 'returns zero when the sample is empty' do
69
+ Collection.bisect_right([], 10).should eq 0
70
+ end
71
+
72
+ it 'returns the index when the item is not in the sample' do
73
+ sample = [10, 20, 30]
74
+ Collection.bisect_right(sample, 15).should eq 1
75
+ Collection.bisect_right(sample, 25).should eq 2
76
+ end
77
+
78
+ it 'returns the index when the item is in the sample' do
79
+ sample = [10, 20, 30]
80
+ Collection.bisect_right(sample, 10).should eq 1
81
+ Collection.bisect_right(sample, 20).should eq 2
82
+ Collection.bisect_right(sample, 30).should eq 3
83
+ end
84
+
85
+ it 'returns the index when the item is not in the sample with a block' do
86
+ sample = [
87
+ {:count => 10},
88
+ {:count => 20},
89
+ {:count => 30}
90
+ ]
91
+ Collection.bisect_right(sample, 15){|x| x[:count]}.should eq 1
92
+ Collection.bisect_right(sample, 25){|x| x[:count]}.should eq 2
93
+ end
94
+
95
+ it 'returns the index when the item is in the sample with a block' do
96
+ sample = [
97
+ {:count => 10},
98
+ {:count => 20},
99
+ {:count => 30}
100
+ ]
101
+ Collection.bisect_right(sample, 10){|x| x[:count]}.should eq 1
102
+ Collection.bisect_right(sample, 20){|x| x[:count]}.should eq 2
103
+ Collection.bisect_right(sample, 30){|x| x[:count]}.should eq 3
104
+ end
105
+ end
106
+
107
+ context '#insort_left!' do
108
+
109
+ it 'returns the item in a one-element array when the sample is nil' do
110
+ Collection.insort_left!(nil, 10).should eq [10]
111
+ end
112
+
113
+ it 'returns the item in a one-element array when the sample is empty' do
114
+ sample = []
115
+ insort = Collection.insort_left!(sample, 10)
116
+ insort.should eq [10]
117
+ sample.object_id.should eq insort.object_id
118
+ end
119
+
120
+ it 'inserts an element that is not in the sample' do
121
+ sample = [10, 20, 30]
122
+ insort = Collection.insort_left!(sample, 15)
123
+ insort.should eq [10, 15, 20, 30]
124
+ sample.object_id.should eq insort.object_id
125
+ end
126
+
127
+ it 'inserts an element that is in the sample' do
128
+ item = 'b'
129
+ sample = ['a', 'b', 'c']
130
+ insort = Collection.insort_left!(sample, item)
131
+ insort.should eq ['a', 'b', 'b', 'c']
132
+ sample.object_id.should eq insort.object_id
133
+ sample[1].object_id.should eq item.object_id
134
+ end
135
+
136
+ it 'inserts an element that is not in the sample using a block' do
137
+ sample = [
138
+ {:count => 10},
139
+ {:count => 20},
140
+ {:count => 30}
141
+ ]
142
+ insort = Collection.insort_left!(sample, {:count => 15}){|x| x[:count]}
143
+ insort.should eq [
144
+ {:count => 10},
145
+ {:count => 15},
146
+ {:count => 20},
147
+ {:count => 30}
148
+ ]
149
+ sample.object_id.should eq insort.object_id
150
+ end
151
+
152
+ it 'inserts an element that is in the sample using a block' do
153
+ item = {:letter => 'b'}
154
+ sample = [
155
+ {:letter => 'a'},
156
+ {:letter => 'b'},
157
+ {:letter => 'c'}
158
+ ]
159
+ insort = Collection.insort_left!(sample, item){|x| x[:letter]}
160
+ insort.should eq [
161
+ {:letter => 'a'},
162
+ {:letter => 'b'},
163
+ {:letter => 'b'},
164
+ {:letter => 'c'}
165
+ ]
166
+ sample.object_id.should eq insort.object_id
167
+ sample[1].object_id.should eq item.object_id
168
+ end
169
+ end
170
+
171
+ context '#insort_left' do
172
+
173
+ it 'returns the item in a one-element array when the sample is nil' do
174
+ Collection.insort_left(nil, 10).should eq [10]
175
+ end
176
+
177
+ it 'returns the item in a one-element array when the sample is empty' do
178
+ sample = []
179
+ insort = Collection.insort_left(sample, 10)
180
+ insort.should eq [10]
181
+ sample.object_id.should_not eq insort.object_id
182
+ end
183
+
184
+ it 'inserts an element that is not in the sample' do
185
+ sample = [10, 20, 30]
186
+ insort = Collection.insort_left(sample, 15)
187
+ insort.should eq [10, 15, 20, 30]
188
+ sample.object_id.should_not eq insort.object_id
189
+ end
190
+
191
+ it 'inserts an element that is in the sample' do
192
+ item = 'b'
193
+ sample = ['a', 'b', 'c']
194
+ insort = Collection.insort_left(sample, item)
195
+ insort.should eq ['a', 'b', 'b', 'c']
196
+ sample.object_id.should_not eq insort.object_id
197
+ insort[1].object_id.should eq item.object_id
198
+ end
199
+
200
+ it 'inserts an element when the sample class does not support the #dup method' do
201
+ sample = [10, 20, 30]
202
+ sample.should_receive(:respond_to?).with(:dup).and_return(false)
203
+ insort = Collection.insort_left(sample, 15)
204
+ insort.should eq [10, 15, 20, 30]
205
+ sample.object_id.should_not eq insort.object_id
206
+ end
207
+
208
+ it 'inserts an element that is not in the sample using a block' do
209
+ sample = [
210
+ {:count => 10},
211
+ {:count => 20},
212
+ {:count => 30}
213
+ ]
214
+ insort = Collection.insort_left(sample, {:count => 15}){|x| x[:count]}
215
+ insort.should eq [
216
+ {:count => 10},
217
+ {:count => 15},
218
+ {:count => 20},
219
+ {:count => 30}
220
+ ]
221
+ sample.object_id.should_not eq insort.object_id
222
+ end
223
+
224
+ it 'inserts an element that is in the sample using a block' do
225
+ item = {:letter => 'b'}
226
+ sample = [
227
+ {:letter => 'a'},
228
+ {:letter => 'b'},
229
+ {:letter => 'c'}
230
+ ]
231
+ insort = Collection.insort_left(sample, item){|x| x[:letter]}
232
+ insort.should eq [
233
+ {:letter => 'a'},
234
+ {:letter => 'b'},
235
+ {:letter => 'b'},
236
+ {:letter => 'c'}
237
+ ]
238
+ sample.object_id.should_not eq insort.object_id
239
+ insort[1].object_id.should eq item.object_id
240
+ end
241
+ end
242
+
243
+ context '#insort_right!' do
244
+
245
+ it 'returns the item in a one-element array when the sample is nil' do
246
+ Collection.insort_right!(nil, 10).should eq [10]
247
+ end
248
+
249
+ it 'returns the item in a one-element array when the sample is empty' do
250
+ sample = []
251
+ insort = Collection.insort_right!(sample, 10)
252
+ insort.should eq [10]
253
+ sample.object_id.should eq insort.object_id
254
+ end
255
+
256
+ it 'inserts an element that is not in the sample' do
257
+ sample = [10, 20, 30]
258
+ insort = Collection.insort_right!(sample, 15)
259
+ insort.should eq [10, 15, 20, 30]
260
+ sample.object_id.should eq insort.object_id
261
+ end
262
+
263
+ it 'inserts an element that is in the sample' do
264
+ item = 'b'
265
+ sample = ['a', 'b', 'c']
266
+ insort = Collection.insort_right!(sample, item)
267
+ insort.should eq ['a', 'b', 'b', 'c']
268
+ sample.object_id.should eq insort.object_id
269
+ insort[2].object_id.should eq item.object_id
270
+ end
271
+
272
+ it 'inserts an element that is not in the sample using a block' do
273
+ sample = [
274
+ {:count => 10},
275
+ {:count => 20},
276
+ {:count => 30}
277
+ ]
278
+ insort = Collection.insort_right!(sample, {:count => 15}){|x| x[:count]}
279
+ insort.should eq [
280
+ {:count => 10},
281
+ {:count => 15},
282
+ {:count => 20},
283
+ {:count => 30}
284
+ ]
285
+ sample.object_id.should eq insort.object_id
286
+ end
287
+
288
+ it 'inserts an element that is in the sample using a block' do
289
+ item = {:letter => 'b'}
290
+ sample = [
291
+ {:letter => 'a'},
292
+ {:letter => 'b'},
293
+ {:letter => 'c'}
294
+ ]
295
+ insort = Collection.insort_right!(sample, item){|x| x[:letter]}
296
+ insort.should eq [
297
+ {:letter => 'a'},
298
+ {:letter => 'b'},
299
+ {:letter => 'b'},
300
+ {:letter => 'c'}
301
+ ]
302
+ sample.object_id.should eq insort.object_id
303
+ insort[2].object_id.should eq item.object_id
304
+ end
305
+ end
306
+
307
+ context '#insort_right' do
308
+
309
+ it 'returns the item in a one-element array when the sample is nil' do
310
+ Collection.insort_right(nil, 10).should eq [10]
311
+ end
312
+
313
+ it 'returns the item in a one-element array when the sample is empty' do
314
+ sample = []
315
+ insort = Collection.insort_right(sample, 10)
316
+ insort.should eq [10]
317
+ sample.object_id.should_not eq insort.object_id
318
+ end
319
+
320
+ it 'inserts an element that is not in the sample' do
321
+ sample = [10, 20, 30]
322
+ insort = Collection.insort_right(sample, 15)
323
+ insort.should eq [10, 15, 20, 30]
324
+ sample.object_id.should_not eq insort.object_id
325
+ end
326
+
327
+ it 'inserts an element that is in the sample' do
328
+ item = 'b'
329
+ sample = ['a', 'b', 'c']
330
+ insort = Collection.insort_right(sample, item)
331
+ insort.should eq ['a', 'b', 'b', 'c']
332
+ sample.object_id.should_not eq insort.object_id
333
+ insort[2].object_id.should eq item.object_id
334
+ end
335
+
336
+ it 'inserts an element when the sample class does not support the #dup method' do
337
+ sample = [10, 20, 30]
338
+ sample.should_receive(:respond_to?).with(:dup).and_return(false)
339
+ insort = Collection.insort_right(sample, 15)
340
+ insort.should eq [10, 15, 20, 30]
341
+ sample.object_id.should_not eq insort.object_id
342
+ end
343
+
344
+ it 'inserts an element that is not in the sample using a block' do
345
+ sample = [
346
+ {:count => 10},
347
+ {:count => 20},
348
+ {:count => 30}
349
+ ]
350
+ insort = Collection.insort_right(sample, {:count => 15}){|x| x[:count]}
351
+ insort.should eq [
352
+ {:count => 10},
353
+ {:count => 15},
354
+ {:count => 20},
355
+ {:count => 30}
356
+ ]
357
+ sample.object_id.should_not eq insort.object_id
358
+ end
359
+
360
+ it 'inserts an element that is in the sample using a block' do
361
+ item = {:letter => 'b'}
362
+ sample = [
363
+ {:letter => 'a'},
364
+ {:letter => 'b'},
365
+ {:letter => 'c'}
366
+ ]
367
+ insort = Collection.insort_right(sample, item){|x| x[:letter]}
368
+ insort.should eq [
369
+ {:letter => 'a'},
370
+ {:letter => 'b'},
371
+ {:letter => 'b'},
372
+ {:letter => 'c'}
373
+ ]
374
+ sample.object_id.should_not eq insort.object_id
375
+ insort[2].object_id.should eq item.object_id
376
+ end
377
+ end
378
+ end
379
+
380
+ context '#collect' do
381
+
382
+ it 'returns an empty array when given a nil sample' do
383
+ Collection.collect(nil).should eq []
384
+ end
385
+
386
+ it 'returns an empty array when given an empty sample' do
387
+ Collection.collect([].freeze).should eq []
388
+ end
389
+
390
+ it 'returns an array when given a valid sample' do
391
+ sample = [1, 2, 3, 4, 5].freeze
392
+ collected = Collection.collect(sample)
393
+ collected.size.should eq sample.size
394
+ collected.each {|item| sample.should include(item)}
395
+ sample.each {|item| collected.should include(item)}
396
+ end
397
+
398
+ it 'returns an array when given a sample with a block' do
399
+ sample = [
400
+ {:count => 1},
401
+ {:count => 2},
402
+ {:count => 3}
403
+ ].freeze
404
+
405
+ collected = Collection.collect(sample){|item| item[:count]}
406
+ collected.size.should eq sample.size
407
+ sample.each {|item| collected.should include(item.values.first)}
408
+ end
409
+ end
410
+
411
+ context '#index_and_catalog' do
412
+
413
+ let(:sample) { [13, 18, 13, 14, 13, 16, 14, 21, 13].freeze }
414
+ let(:expected) { [ [0, 13], [1, 18], [2, 13], [3, 14], [4, 13], [5, 16], [6, 14], [7, 21], [8, 13] ].freeze }
415
+
416
+ it 'returns an empty catalog when given a nil sample' do
417
+ Collection.index_and_catalog(nil).should eq []
418
+ end
419
+
420
+ it 'returns an empty catalog when given an empty sample' do
421
+ Collection.index_and_catalog([].freeze).should eq []
422
+ end
423
+
424
+ it 'returns an catalog when given a valid sample' do
425
+ cataloged = Collection.index_and_catalog(sample)
426
+ cataloged.should eq expected
427
+ end
428
+
429
+ it 'returns an catalog when given a sample with a block' do
430
+ sample = [
431
+ {:count => 13}, {:count => 18}, {:count => 13},
432
+ {:count => 14}, {:count => 13}, {:count => 16},
433
+ {:count => 14}, {:count => 21}, {:count => 13}
434
+ ].freeze
435
+
436
+ cataloged = Collection.index_and_catalog(sample){|item| item[:count]}
437
+ cataloged.should eq expected
438
+ end
439
+ end
440
+
441
+ context '#catalog_hash' do
442
+
443
+ it 'returns an empty catalog when the hash is nil' do
444
+ Collection.catalog_hash(nil).should eq []
445
+ end
446
+
447
+ it 'returns an empty catalog when the hash is empty' do
448
+ Collection.catalog_hash({}.freeze).should eq []
449
+ end
450
+
451
+ it 'returns a catalog when given a populated hash' do
452
+ sample = {
453
+ 7 => 8,
454
+ 12 => 8,
455
+ 17 => 14,
456
+ 22 => 4,
457
+ 27 => 6,
458
+ 32 => 12,
459
+ 37 => 8,
460
+ 42 => 3,
461
+ 47 => 2
462
+ }.freeze
463
+
464
+ catalog = Collection.catalog_hash(sample)
465
+ catalog.size.should eq sample.size
466
+
467
+ catalog[0].should eq [7, 8]
468
+ catalog[1].should eq [12, 8]
469
+ catalog[2].should eq [17, 14]
470
+ catalog[3].should eq [22, 4]
471
+ catalog[4].should eq [27, 6]
472
+ catalog[5].should eq [32, 12]
473
+ catalog[6].should eq [37, 8]
474
+ catalog[7].should eq [42, 3]
475
+ catalog[8].should eq [47, 2]
476
+ end
477
+
478
+ it 'applies the supplied block to every value in the hash' do
479
+ sample = {
480
+ 7 => {:count => 8},
481
+ 12 => {:count => 8},
482
+ 17 => {:count => 14},
483
+ 22 => {:count => 4},
484
+ 27 => {:count => 6},
485
+ 32 => {:count => 12},
486
+ 37 => {:count => 8},
487
+ 42 => {:count => 3},
488
+ 47 => {:count => 2}
489
+ }.freeze
490
+
491
+ catalog = Collection.catalog_hash(sample){|item| item[:count]}
492
+ catalog.size.should eq sample.size
493
+
494
+ catalog[0].should eq [7, 8]
495
+ catalog[1].should eq [12, 8]
496
+ catalog[2].should eq [17, 14]
497
+ catalog[3].should eq [22, 4]
498
+ catalog[4].should eq [27, 6]
499
+ catalog[5].should eq [32, 12]
500
+ catalog[6].should eq [37, 8]
501
+ catalog[7].should eq [42, 3]
502
+ catalog[8].should eq [47, 2]
503
+ end
504
+ end
505
+
506
+ context '#hash_catalog' do
507
+
508
+ it 'returns an empty hash when the catalog is nil' do
509
+ Collection.hash_catalog(nil).should == {}
510
+ end
511
+
512
+ it 'returns an empty hash when the catalog is empty' do
513
+ Collection.hash_catalog({}.freeze).should == {}
514
+ end
515
+
516
+ it 'returns a hash when given a catalog hash' do
517
+ sample = [
518
+ [7, 8],
519
+ [12, 8],
520
+ [17, 14],
521
+ [22, 4],
522
+ [27, 6],
523
+ [32, 12],
524
+ [37, 8],
525
+ [42, 3],
526
+ [47, 2]
527
+ ].freeze
528
+
529
+ hash = Collection.hash_catalog(sample)
530
+ hash.size.should eq sample.size
531
+
532
+ hash[7].should eq 8
533
+ hash[12].should eq 8
534
+ hash[17].should eq 14
535
+ hash[22].should eq 4
536
+ hash[27].should eq 6
537
+ hash[32].should eq 12
538
+ hash[37].should eq 8
539
+ hash[42].should eq 3
540
+ hash[47].should eq 2
541
+ end
542
+
543
+ it 'keeps the last value when duplicate keys exist' do
544
+ sample = [
545
+ [7, 0],
546
+ [12, 1],
547
+ [12, 2],
548
+ [12, 3],
549
+ [12, 4],
550
+ [12, 5],
551
+ [12, 6],
552
+ [47, 7]
553
+ ].freeze
554
+
555
+ hash = Collection.hash_catalog(sample)
556
+ hash.size.should eq 3
557
+
558
+ hash[7].should eq 0
559
+ hash[12].should eq 6
560
+ hash[47].should eq 7
561
+ end
562
+
563
+ it 'applies the supplied block to every value in the hash' do
564
+ sample = [
565
+ [7, {:count => 8}],
566
+ [12, {:count => 8}],
567
+ [17, {:count => 14}],
568
+ [22, {:count => 4}],
569
+ [27, {:count => 6}],
570
+ [32, {:count => 12}],
571
+ [37, {:count => 8}],
572
+ [42, {:count => 3}],
573
+ [47, {:count => 2}]
574
+ ].freeze
575
+
576
+ hash = Collection.hash_catalog(sample){|item| item[:count]}
577
+ hash.size.should eq sample.size
578
+
579
+ hash[7].should eq 8
580
+ hash[12].should eq 8
581
+ hash[17].should eq 14
582
+ hash[22].should eq 4
583
+ hash[27].should eq 6
584
+ hash[32].should eq 12
585
+ hash[37].should eq 8
586
+ hash[42].should eq 3
587
+ hash[47].should eq 2
588
+ end
589
+ end
590
+
591
+ context 'predicates' do
592
+
593
+ context '#ascending?' do
594
+
595
+ it 'returns false for a nil sample' do
596
+ Collection.ascending?(nil).should be_false
597
+ end
598
+
599
+ it 'returns true for an empty sample' do
600
+ Collection.ascending?([].freeze).should be_true
601
+ end
602
+
603
+ it 'returns true for a one-element sample' do
604
+ Collection.ascending?([100].freeze).should be_true
605
+ end
606
+
607
+ it 'returns true for an ascending collection' do
608
+ Collection.ascending?([1, 2, 3, 4].freeze).should be_true
609
+ end
610
+
611
+ it 'returns false for a non-ascending collection' do
612
+ Collection.ascending?([1, 3, 2, 4].freeze).should be_false
613
+ end
614
+
615
+ it 'returns the correct value when given a block' do
616
+ sample = [
617
+ {:count => 11},
618
+ {:count => 12},
619
+ {:count => 13},
620
+ {:count => 14}
621
+ ].freeze
622
+
623
+ Collection.ascending?(sample){|item| item[:count]}.should be_true
624
+ end
625
+ end
626
+
627
+ context '#descending?' do
628
+
629
+ it 'returns false for a nil sample' do
630
+ Collection.descending?(nil).should be_false
631
+ end
632
+
633
+ it 'returns true for an empty sample' do
634
+ Collection.descending?([].freeze).should be_true
635
+ end
636
+
637
+ it 'returns true for a one-element sample' do
638
+ Collection.descending?([100].freeze).should be_true
639
+ end
640
+
641
+ it 'returns true for an descending collection' do
642
+ Collection.descending?([4, 3, 2, 1].freeze).should be_true
643
+ end
644
+
645
+ it 'returns false for a non-descending collection' do
646
+ Collection.descending?([1, 3, 2, 4].freeze).should be_false
647
+ end
648
+
649
+ it 'returns the correct value when given a block' do
650
+ sample = [
651
+ {:count => 21},
652
+ {:count => 20},
653
+ {:count => 19},
654
+ {:count => 18}
655
+ ].freeze
656
+
657
+ Collection.descending?(sample){|item| item[:count]}.should be_true
658
+ end
659
+ end
660
+ end
661
+
662
+ context 'partitioning' do
663
+
664
+ context '#slice' do
665
+
666
+ context 'function signature' do
667
+
668
+ it 'raises an exception with less than two arguments' do
669
+ lambda {
670
+ Functional.slice(1)
671
+ }.should raise_exception(ArgumentError)
672
+ end
673
+
674
+ it 'raises and exception with more than three arguments' do
675
+ lambda {
676
+ Functional.slice(1, 2, 3, 4)
677
+ }.should raise_exception(ArgumentError)
678
+ end
679
+ end
680
+
681
+ context 'with index' do
682
+
683
+ it 'returns nil if the positive index is out of range' do
684
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
685
+ Functional.slice(sample, 9).should be_nil
686
+ end
687
+
688
+ it 'returns nil if the negative index is out of range' do
689
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
690
+ Functional.slice(sample, -10).should be_nil
691
+ end
692
+
693
+ it 'returns the element at index for a non-negative index' do
694
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
695
+ Functional.slice(sample, 3).should eq 14
696
+ end
697
+
698
+ it 'returns the element counted backward from the end for a negative index' do
699
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
700
+ Functional.slice(sample, -4).should eq 16
701
+ end
702
+ end
703
+
704
+ context 'with range' do
705
+
706
+ it 'returns nil when the positive index is out of range' do
707
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
708
+ Functional.slice(sample, (9..5)).should be_nil
709
+ end
710
+
711
+ it 'returns nil when the index is negative' do
712
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
713
+ Functional.slice(sample, (-1..5)).should be_nil
714
+ end
715
+
716
+ it 'returns a subarray starting at start and continuing to end' do
717
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
718
+ Functional.slice(sample, (1..5)).should eq [13, 13, 14, 13, 16]
719
+ end
720
+
721
+ it 'returns a subarray to the end when the end is out of range' do
722
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
723
+ Functional.slice(sample, (1..100)).should eq [13, 13, 14, 13, 16, 14, 21, 13]
724
+ end
725
+ end
726
+
727
+ context 'with start index and length' do
728
+
729
+ it 'returns nil when the positive index is out of range' do
730
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
731
+ Functional.slice(sample, 9, 5).should be_nil
732
+ end
733
+
734
+ it 'returns nil when the index is negative' do
735
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
736
+ Functional.slice(sample, -1, 5).should be_nil
737
+ end
738
+
739
+ it 'returns a subarray specified by range' do
740
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
741
+ Functional.slice(sample, 2, 4).should eq [13, 14, 13, 16]
742
+ end
743
+
744
+ it 'returns a subarray to the end when length is out of range' do
745
+ sample = [18, 13, 13, 14, 13, 16, 14, 21, 13].freeze
746
+ Functional.slice(sample, 2, 100).should eq [13, 14, 13, 16, 14, 21, 13]
747
+ end
748
+ end
749
+ end
750
+ end
751
+ end
752
+ end