functional-ruby 0.7.4 → 0.7.5
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.
- checksums.yaml +4 -4
- data/README.md +46 -12
- data/lib/functional.rb +19 -0
- data/lib/functional/catalog.rb +487 -0
- data/lib/functional/collection.rb +403 -0
- data/lib/functional/inflect.rb +127 -0
- data/lib/functional/search.rb +132 -0
- data/lib/functional/sort.rb +41 -0
- data/lib/functional/utilities.rb +0 -3
- data/lib/functional/version.rb +1 -1
- data/md/catalog.md +32 -0
- data/md/collection.md +32 -0
- data/md/inflect.md +32 -0
- data/md/pattern_matching.md +2 -2
- data/md/platform.md +32 -0
- data/md/search.md +32 -0
- data/md/sort.md +32 -0
- data/md/utilities.md +2 -2
- data/spec/functional/catalog_spec.rb +1206 -0
- data/spec/functional/collection_spec.rb +752 -0
- data/spec/functional/inflect_spec.rb +85 -0
- data/spec/functional/pattern_matching_spec.rb +0 -2
- data/spec/functional/search_spec.rb +187 -0
- data/spec/functional/sort_spec.rb +61 -0
- data/spec/spec_helper.rb +9 -0
- metadata +23 -2
@@ -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
|