daru 0.1.3.1 → 0.1.4
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/.gitignore +2 -0
- data/.rspec +2 -1
- data/.rspec_formatter.rb +33 -0
- data/.rubocop.yml +26 -2
- data/History.md +38 -0
- data/README.md +22 -13
- data/Rakefile +50 -2
- data/benchmarks/csv_reading.rb +22 -0
- data/daru.gemspec +9 -2
- data/lib/daru.rb +36 -4
- data/lib/daru/accessors/array_wrapper.rb +6 -1
- data/lib/daru/accessors/dataframe_by_row.rb +10 -2
- data/lib/daru/accessors/gsl_wrapper.rb +1 -3
- data/lib/daru/accessors/nmatrix_wrapper.rb +9 -0
- data/lib/daru/category.rb +935 -0
- data/lib/daru/core/group_by.rb +29 -38
- data/lib/daru/core/merge.rb +186 -145
- data/lib/daru/core/query.rb +22 -11
- data/lib/daru/dataframe.rb +976 -885
- data/lib/daru/date_time/index.rb +166 -166
- data/lib/daru/date_time/offsets.rb +66 -77
- data/lib/daru/formatters/table.rb +54 -0
- data/lib/daru/helpers/array.rb +40 -0
- data/lib/daru/index.rb +476 -73
- data/lib/daru/io/io.rb +66 -45
- data/lib/daru/io/sql_data_source.rb +33 -62
- data/lib/daru/iruby/helpers.rb +38 -0
- data/lib/daru/iruby/templates/dataframe.html.erb +52 -0
- data/lib/daru/iruby/templates/dataframe_mi.html.erb +58 -0
- data/lib/daru/iruby/templates/multi_index.html.erb +12 -0
- data/lib/daru/iruby/templates/vector.html.erb +27 -0
- data/lib/daru/iruby/templates/vector_mi.html.erb +36 -0
- data/lib/daru/maths/arithmetic/dataframe.rb +16 -18
- data/lib/daru/maths/arithmetic/vector.rb +4 -6
- data/lib/daru/maths/statistics/dataframe.rb +8 -15
- data/lib/daru/maths/statistics/vector.rb +120 -98
- data/lib/daru/monkeys.rb +12 -40
- data/lib/daru/plotting/gruff.rb +3 -0
- data/lib/daru/plotting/gruff/category.rb +49 -0
- data/lib/daru/plotting/gruff/dataframe.rb +91 -0
- data/lib/daru/plotting/gruff/vector.rb +57 -0
- data/lib/daru/plotting/nyaplot.rb +3 -0
- data/lib/daru/plotting/nyaplot/category.rb +34 -0
- data/lib/daru/plotting/nyaplot/dataframe.rb +187 -0
- data/lib/daru/plotting/nyaplot/vector.rb +46 -0
- data/lib/daru/vector.rb +694 -421
- data/lib/daru/version.rb +1 -1
- data/profile/_base.rb +23 -0
- data/profile/df_to_a.rb +10 -0
- data/profile/filter.rb +13 -0
- data/profile/joining.rb +13 -0
- data/profile/sorting.rb +12 -0
- data/profile/vector_each_with_index.rb +9 -0
- data/spec/accessors/wrappers_spec.rb +2 -4
- data/spec/categorical_spec.rb +1734 -0
- data/spec/core/group_by_spec.rb +52 -2
- data/spec/core/merge_spec.rb +63 -2
- data/spec/core/query_spec.rb +236 -80
- data/spec/dataframe_spec.rb +1373 -79
- data/spec/date_time/data_spec.rb +3 -5
- data/spec/date_time/index_spec.rb +154 -17
- data/spec/date_time/offsets_spec.rb +3 -4
- data/spec/fixtures/empties.dat +2 -0
- data/spec/fixtures/strings.dat +2 -0
- data/spec/formatters/table_formatter_spec.rb +99 -0
- data/spec/helpers_spec.rb +8 -0
- data/spec/index/categorical_index_spec.rb +168 -0
- data/spec/index/index_spec.rb +283 -0
- data/spec/index/multi_index_spec.rb +570 -0
- data/spec/io/io_spec.rb +31 -4
- data/spec/io/sql_data_source_spec.rb +0 -1
- data/spec/iruby/dataframe_spec.rb +172 -0
- data/spec/iruby/helpers_spec.rb +49 -0
- data/spec/iruby/multi_index_spec.rb +37 -0
- data/spec/iruby/vector_spec.rb +107 -0
- data/spec/math/arithmetic/dataframe_spec.rb +71 -13
- data/spec/math/arithmetic/vector_spec.rb +8 -10
- data/spec/math/statistics/dataframe_spec.rb +3 -5
- data/spec/math/statistics/vector_spec.rb +45 -55
- data/spec/monkeys_spec.rb +32 -9
- data/spec/plotting/dataframe_spec.rb +386 -0
- data/spec/plotting/vector_spec.rb +230 -0
- data/spec/shared/vector_display_spec.rb +215 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/vector_spec.rb +905 -138
- metadata +143 -11
- data/.rubocop_todo.yml +0 -44
- data/lib/daru/plotting/dataframe.rb +0 -104
- data/lib/daru/plotting/vector.rb +0 -38
- data/spec/daru_spec.rb +0 -58
- data/spec/index_spec.rb +0 -375
@@ -0,0 +1,570 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Daru::MultiIndex do
|
4
|
+
before(:each) do
|
5
|
+
@index_tuples = [
|
6
|
+
[:a,:one,:bar],
|
7
|
+
[:a,:one,:baz],
|
8
|
+
[:a,:two,:bar],
|
9
|
+
[:a,:two,:baz],
|
10
|
+
[:b,:one,:bar],
|
11
|
+
[:b,:two,:bar],
|
12
|
+
[:b,:two,:baz],
|
13
|
+
[:b,:one,:foo],
|
14
|
+
[:c,:one,:bar],
|
15
|
+
[:c,:one,:baz],
|
16
|
+
[:c,:two,:foo],
|
17
|
+
[:c,:two,:bar]
|
18
|
+
]
|
19
|
+
@multi_mi = Daru::MultiIndex.from_tuples(@index_tuples)
|
20
|
+
end
|
21
|
+
|
22
|
+
context ".initialize" do
|
23
|
+
it "accepts labels and levels as arguments" do
|
24
|
+
mi = Daru::MultiIndex.new(
|
25
|
+
levels: [[:a,:b,:c], [:one, :two]],
|
26
|
+
labels: [[0,0,1,1,2,2], [0,1,0,1,0,1]])
|
27
|
+
|
28
|
+
expect(mi[:a, :two]).to eq(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "raises error for wrong number of labels or levels" do
|
32
|
+
expect {
|
33
|
+
Daru::MultiIndex.new(
|
34
|
+
levels: [[:a,:a,:b,:b,:c,:c], [:one, :two]],
|
35
|
+
labels: [[0,0,1,1,2,2]])
|
36
|
+
}.to raise_error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context ".from_tuples" do
|
41
|
+
it "creates 2 layer MultiIndex from tuples" do
|
42
|
+
tuples = [
|
43
|
+
[:a, :one],
|
44
|
+
[:a, :two],
|
45
|
+
[:b, :one],
|
46
|
+
[:b, :two],
|
47
|
+
[:c, :one],
|
48
|
+
[:c, :two]
|
49
|
+
]
|
50
|
+
mi = Daru::MultiIndex.from_tuples(tuples)
|
51
|
+
expect(mi.levels).to eq([[:a, :b, :c], [:one,:two]])
|
52
|
+
expect(mi.labels).to eq([[0,0,1,1,2,2], [0,1,0,1,0,1]])
|
53
|
+
end
|
54
|
+
|
55
|
+
it "creates a triple layer MultiIndex from tuples" do
|
56
|
+
expect(@multi_mi.levels).to eq([[:a,:b,:c], [:one, :two],[:bar,:baz,:foo]])
|
57
|
+
expect(@multi_mi.labels).to eq([
|
58
|
+
[0,0,0,0,1,1,1,1,2,2,2,2],
|
59
|
+
[0,0,1,1,0,1,1,0,0,0,1,1],
|
60
|
+
[0,1,0,1,0,0,1,2,0,1,2,0]
|
61
|
+
])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context '.try_from_tuples' do
|
66
|
+
it 'creates MultiIndex, if there are tuples' do
|
67
|
+
tuples = [
|
68
|
+
[:a, :one],
|
69
|
+
[:a, :two],
|
70
|
+
[:b, :one],
|
71
|
+
[:b, :two],
|
72
|
+
[:c, :one],
|
73
|
+
[:c, :two]
|
74
|
+
]
|
75
|
+
mi = Daru::MultiIndex.try_from_tuples(tuples)
|
76
|
+
expect(mi).to be_a Daru::MultiIndex
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'returns nil, if MultiIndex can not be created' do
|
80
|
+
mi = Daru::MultiIndex.try_from_tuples([:a, :b, :c])
|
81
|
+
expect(mi).to be_nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "#size" do
|
86
|
+
it "returns size of MultiIndex" do
|
87
|
+
expect(@multi_mi.size).to eq(12)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "#[]" do
|
92
|
+
it "returns the row number when specifying the complete tuple" do
|
93
|
+
expect(@multi_mi[:a, :one, :baz]).to eq(1)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "returns MultiIndex when specifying incomplete tuple" do
|
97
|
+
expect(@multi_mi[:b]).to eq(Daru::MultiIndex.from_tuples([
|
98
|
+
[:b,:one,:bar],
|
99
|
+
[:b,:two,:bar],
|
100
|
+
[:b,:two,:baz],
|
101
|
+
[:b,:one,:foo]
|
102
|
+
]))
|
103
|
+
expect(@multi_mi[:b, :one]).to eq(Daru::MultiIndex.from_tuples([
|
104
|
+
[:b,:one,:bar],
|
105
|
+
[:b,:one,:foo]
|
106
|
+
]))
|
107
|
+
# TODO: Return Daru::Index if a single layer of indexes is present.
|
108
|
+
end
|
109
|
+
|
110
|
+
it "returns MultiIndex when specifying wholly numeric ranges" do
|
111
|
+
expect(@multi_mi[3..6]).to eq(Daru::MultiIndex.from_tuples([
|
112
|
+
[:a,:two,:baz],
|
113
|
+
[:b,:one,:bar],
|
114
|
+
[:b,:two,:bar],
|
115
|
+
[:b,:two,:baz]
|
116
|
+
]))
|
117
|
+
end
|
118
|
+
|
119
|
+
it "raises error when specifying invalid index" do
|
120
|
+
expect { @multi_mi[:a, :three] }.to raise_error IndexError
|
121
|
+
expect { @multi_mi[:a, :one, :xyz] }.to raise_error IndexError
|
122
|
+
expect { @multi_mi[:x] }.to raise_error IndexError
|
123
|
+
expect { @multi_mi[:x, :one] }.to raise_error IndexError
|
124
|
+
expect { @multi_mi[:x, :one, :bar] }.to raise_error IndexError
|
125
|
+
end
|
126
|
+
|
127
|
+
it "works with numerical first levels" do
|
128
|
+
mi = Daru::MultiIndex.from_tuples([
|
129
|
+
[2000, 'M'],
|
130
|
+
[2000, 'F'],
|
131
|
+
[2001, 'M'],
|
132
|
+
[2001, 'F']
|
133
|
+
])
|
134
|
+
|
135
|
+
expect(mi[2000]).to eq(Daru::MultiIndex.from_tuples([
|
136
|
+
[2000, 'M'],
|
137
|
+
[2000, 'F']
|
138
|
+
]))
|
139
|
+
|
140
|
+
expect(mi[2000,'M']).to eq(0)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "#include?" do
|
145
|
+
it "checks if a completely specified tuple exists" do
|
146
|
+
expect(@multi_mi.include?([:a,:one,:bar])).to eq(true)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "checks if a top layer incomplete tuple exists" do
|
150
|
+
expect(@multi_mi.include?([:a])).to eq(true)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "checks if a middle layer incomplete tuple exists" do
|
154
|
+
expect(@multi_mi.include?([:a, :one])).to eq(true)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "checks for non-existence of a tuple" do
|
158
|
+
expect(@multi_mi.include?([:boo])).to eq(false)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "#key" do
|
163
|
+
it "returns the tuple of the specified number" do
|
164
|
+
expect(@multi_mi.key(3)).to eq([:a,:two,:baz])
|
165
|
+
end
|
166
|
+
|
167
|
+
it "returns nil for non-existent pointer number" do
|
168
|
+
expect {
|
169
|
+
@multi_mi.key(100)
|
170
|
+
}.to raise_error ArgumentError
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "#to_a" do
|
175
|
+
it "returns tuples as an Array" do
|
176
|
+
expect(@multi_mi.to_a).to eq(@index_tuples)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "#dup" do
|
181
|
+
it "completely duplicates the object" do
|
182
|
+
duplicate = @multi_mi.dup
|
183
|
+
expect(duplicate) .to eq(@multi_mi)
|
184
|
+
expect(duplicate.object_id).to_not eq(@multi_mi.object_id)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "#inspect" do
|
189
|
+
context 'small index' do
|
190
|
+
subject {
|
191
|
+
Daru::MultiIndex.from_tuples [
|
192
|
+
[:a,:one,:bar],
|
193
|
+
[:a,:one,:baz],
|
194
|
+
[:a,:two,:bar],
|
195
|
+
[:a,:two,:baz],
|
196
|
+
[:b,:one,:bar],
|
197
|
+
[:b,:two,:bar],
|
198
|
+
[:b,:two,:baz],
|
199
|
+
[:b,:one,:foo],
|
200
|
+
[:c,:one,:bar],
|
201
|
+
[:c,:one,:baz],
|
202
|
+
[:c,:two,:foo],
|
203
|
+
[:c,:two,:bar]
|
204
|
+
]
|
205
|
+
}
|
206
|
+
|
207
|
+
its(:inspect) { is_expected.to eq %Q{
|
208
|
+
|#<Daru::MultiIndex(12x3)>
|
209
|
+
| a one bar
|
210
|
+
| baz
|
211
|
+
| two bar
|
212
|
+
| baz
|
213
|
+
| b one bar
|
214
|
+
| two bar
|
215
|
+
| baz
|
216
|
+
| one foo
|
217
|
+
| c one bar
|
218
|
+
| baz
|
219
|
+
| two foo
|
220
|
+
| bar
|
221
|
+
}.unindent
|
222
|
+
}
|
223
|
+
end
|
224
|
+
|
225
|
+
context 'large index' do
|
226
|
+
subject {
|
227
|
+
Daru::MultiIndex.from_tuples(
|
228
|
+
(1..100).map { |i| %w[a b c].map { |c| [i, c] } }.flatten(1)
|
229
|
+
)
|
230
|
+
}
|
231
|
+
|
232
|
+
its(:inspect) { is_expected.to eq %Q{
|
233
|
+
|#<Daru::MultiIndex(300x2)>
|
234
|
+
| 1 a
|
235
|
+
| b
|
236
|
+
| c
|
237
|
+
| 2 a
|
238
|
+
| b
|
239
|
+
| c
|
240
|
+
| 3 a
|
241
|
+
| b
|
242
|
+
| c
|
243
|
+
| 4 a
|
244
|
+
| b
|
245
|
+
| c
|
246
|
+
| 5 a
|
247
|
+
| b
|
248
|
+
| c
|
249
|
+
| 6 a
|
250
|
+
| b
|
251
|
+
| c
|
252
|
+
| 7 a
|
253
|
+
| b
|
254
|
+
| ... ...
|
255
|
+
}.unindent
|
256
|
+
}
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context "#==" do
|
261
|
+
it "returns false for unequal MultiIndex comparisons" do
|
262
|
+
mi1 = Daru::MultiIndex.from_tuples([
|
263
|
+
[:a, :one, :bar],
|
264
|
+
[:a, :two, :baz],
|
265
|
+
[:b, :one, :foo],
|
266
|
+
[:b, :two, :bar]
|
267
|
+
])
|
268
|
+
mi2 = Daru::MultiIndex.from_tuples([
|
269
|
+
[:a, :two, :bar],
|
270
|
+
[:b, :one, :foo],
|
271
|
+
[:a, :one, :baz],
|
272
|
+
[:b, :two, :baz]
|
273
|
+
])
|
274
|
+
|
275
|
+
expect(mi1 == mi2).to eq(false)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
context "#values" do
|
280
|
+
it "returns an array of indices in order" do
|
281
|
+
mi = Daru::MultiIndex.from_tuples([
|
282
|
+
[:a, :one, :bar],
|
283
|
+
[:a, :two, :baz],
|
284
|
+
[:b, :one, :foo],
|
285
|
+
[:b, :two, :bar]
|
286
|
+
])
|
287
|
+
|
288
|
+
expect(mi.values).to eq([0,1,2,3])
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
context "#|" do
|
293
|
+
before do
|
294
|
+
@mi1 = Daru::MultiIndex.from_tuples([
|
295
|
+
[:a, :one, :bar],
|
296
|
+
[:a, :two, :baz],
|
297
|
+
[:b, :one, :foo],
|
298
|
+
[:b, :two, :bar]
|
299
|
+
])
|
300
|
+
@mi2 = Daru::MultiIndex.from_tuples([
|
301
|
+
[:a, :two, :bar],
|
302
|
+
[:b, :one, :foo],
|
303
|
+
[:a, :one, :baz],
|
304
|
+
[:b, :two, :baz]
|
305
|
+
])
|
306
|
+
end
|
307
|
+
|
308
|
+
it "returns a union of two MultiIndex objects" do
|
309
|
+
expect(@mi1 | @mi2).to eq(Daru::MultiIndex.new(
|
310
|
+
levels: [[:a, :b], [:one, :two], [:bar, :baz, :foo]],
|
311
|
+
labels: [
|
312
|
+
[0, 0, 1, 1, 0, 0, 1],
|
313
|
+
[0, 1, 0, 1, 1, 0, 1],
|
314
|
+
[0, 1, 2, 0, 0, 1, 1]
|
315
|
+
])
|
316
|
+
)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
context "#&" do
|
321
|
+
before do
|
322
|
+
@mi1 = Daru::MultiIndex.from_tuples([
|
323
|
+
[:a, :one],
|
324
|
+
[:a, :two],
|
325
|
+
[:b, :two]
|
326
|
+
])
|
327
|
+
@mi2 = Daru::MultiIndex.from_tuples([
|
328
|
+
[:a, :two],
|
329
|
+
[:b, :one],
|
330
|
+
[:b, :three]
|
331
|
+
])
|
332
|
+
end
|
333
|
+
|
334
|
+
it "returns the intersection of two MI objects" do
|
335
|
+
expect(@mi1 & @mi2).to eq(Daru::MultiIndex.from_tuples([
|
336
|
+
[:a, :two],
|
337
|
+
]))
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
context "#empty?" do
|
342
|
+
it "returns true if nothing present in MultiIndex" do
|
343
|
+
expect(Daru::MultiIndex.new(labels: [[]], levels: [[]]).empty?).to eq(true)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
context "#drop_left_level" do
|
348
|
+
it "drops the leftmost level" do
|
349
|
+
expect(
|
350
|
+
Daru::MultiIndex.from_tuples([
|
351
|
+
[:c,:one,:bar],
|
352
|
+
[:c,:one,:baz],
|
353
|
+
[:c,:two,:foo],
|
354
|
+
[:c,:two,:bar]
|
355
|
+
]).drop_left_level).to eq(
|
356
|
+
Daru::MultiIndex.from_tuples([
|
357
|
+
[:one,:bar],
|
358
|
+
[:one,:baz],
|
359
|
+
[:two,:foo],
|
360
|
+
[:two,:bar]
|
361
|
+
])
|
362
|
+
)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
context 'other forms of tuple list representation' do
|
367
|
+
let(:index) {
|
368
|
+
Daru::MultiIndex.from_tuples [
|
369
|
+
[:a,:one,:bar],
|
370
|
+
[:a,:one,:baz],
|
371
|
+
[:a,:two,:bar],
|
372
|
+
[:a,:two,:baz],
|
373
|
+
[:b,:one,:bar],
|
374
|
+
[:b,:two,:bar],
|
375
|
+
[:b,:two,:baz],
|
376
|
+
[:b,:one,:foo],
|
377
|
+
[:c,:one,:bar],
|
378
|
+
[:c,:one,:baz],
|
379
|
+
[:c,:two,:foo],
|
380
|
+
[:c,:two,:bar]
|
381
|
+
]
|
382
|
+
}
|
383
|
+
|
384
|
+
context '#sparse_tuples' do
|
385
|
+
subject { index.sparse_tuples }
|
386
|
+
|
387
|
+
it { is_expected.to eq [
|
388
|
+
[:a ,:one,:bar],
|
389
|
+
[nil, nil,:baz],
|
390
|
+
[nil,:two,:bar],
|
391
|
+
[nil, nil,:baz],
|
392
|
+
[:b ,:one,:bar],
|
393
|
+
[nil,:two,:bar],
|
394
|
+
[nil, nil,:baz],
|
395
|
+
[nil,:one,:foo],
|
396
|
+
[:c ,:one,:bar],
|
397
|
+
[nil, nil,:baz],
|
398
|
+
[nil,:two,:foo],
|
399
|
+
[nil, nil,:bar]
|
400
|
+
]}
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
context "#pos" do
|
405
|
+
let(:idx) do
|
406
|
+
described_class.from_tuples([
|
407
|
+
[:b,:one,:bar],
|
408
|
+
[:b,:two,:bar],
|
409
|
+
[:b,:two,:baz],
|
410
|
+
[:b,:one,:foo]
|
411
|
+
])
|
412
|
+
end
|
413
|
+
|
414
|
+
context "single index" do
|
415
|
+
it { expect(idx.pos :b, :one, :bar).to eq 0 }
|
416
|
+
end
|
417
|
+
|
418
|
+
context "multiple indexes" do
|
419
|
+
subject { idx.pos :b, :one }
|
420
|
+
|
421
|
+
it { is_expected.to be_a Array }
|
422
|
+
its(:size) { is_expected.to eq 2 }
|
423
|
+
it { is_expected.to eq [0, 3] }
|
424
|
+
end
|
425
|
+
|
426
|
+
context "single positional index" do
|
427
|
+
it { expect(idx.pos 0).to eq 0 }
|
428
|
+
end
|
429
|
+
|
430
|
+
context "multiple positional indexes" do
|
431
|
+
subject { idx.pos 0, 1 }
|
432
|
+
|
433
|
+
it { is_expected.to be_a Array }
|
434
|
+
its(:size) { is_expected.to eq 2 }
|
435
|
+
it { is_expected.to eq [0, 1] }
|
436
|
+
end
|
437
|
+
|
438
|
+
# TODO: Add specs for IndexError
|
439
|
+
end
|
440
|
+
|
441
|
+
context "#subset" do
|
442
|
+
let(:idx) do
|
443
|
+
described_class.from_tuples([
|
444
|
+
[:b, :one, :bar],
|
445
|
+
[:b, :two, :bar],
|
446
|
+
[:b, :two, :baz],
|
447
|
+
[:b, :one, :foo]
|
448
|
+
])
|
449
|
+
end
|
450
|
+
|
451
|
+
context "multiple indexes" do
|
452
|
+
subject { idx.subset :b, :one }
|
453
|
+
|
454
|
+
it { is_expected.to be_a described_class }
|
455
|
+
its(:size) { is_expected.to eq 2 }
|
456
|
+
its(:to_a) { is_expected.to eq [[:bar], [:foo]] }
|
457
|
+
end
|
458
|
+
|
459
|
+
context "multiple positional indexes" do
|
460
|
+
subject { idx.subset 0, 1 }
|
461
|
+
|
462
|
+
it { is_expected.to be_a described_class }
|
463
|
+
its(:size) { is_expected.to eq 2 }
|
464
|
+
its(:to_a) { is_expected.to eq [[:b, :one, :bar], [:b, :two, :bar]] }
|
465
|
+
end
|
466
|
+
|
467
|
+
# TODO: Checks for invalid indexes
|
468
|
+
end
|
469
|
+
|
470
|
+
context "at" do
|
471
|
+
let(:idx) do
|
472
|
+
described_class.from_tuples([
|
473
|
+
[:b, :one, :bar],
|
474
|
+
[:b, :two, :bar],
|
475
|
+
[:b, :two, :baz],
|
476
|
+
[:b, :one, :foo]
|
477
|
+
])
|
478
|
+
end
|
479
|
+
|
480
|
+
context "single position" do
|
481
|
+
it { expect(idx.at 2).to eq [:b, :two, :baz] }
|
482
|
+
end
|
483
|
+
|
484
|
+
context "multiple positions" do
|
485
|
+
subject { idx.at 1, 2 }
|
486
|
+
|
487
|
+
it { is_expected.to be_a described_class }
|
488
|
+
its(:size) { is_expected.to eq 2 }
|
489
|
+
its(:to_a) { is_expected.to eq [[:b, :two, :bar],
|
490
|
+
[:b, :two, :baz]] }
|
491
|
+
end
|
492
|
+
|
493
|
+
context "range" do
|
494
|
+
subject { idx.at 1..2 }
|
495
|
+
|
496
|
+
it { is_expected.to be_a described_class }
|
497
|
+
its(:size) { is_expected.to eq 2 }
|
498
|
+
its(:to_a) { is_expected.to eq [[:b, :two, :bar],
|
499
|
+
[:b, :two, :baz]] }
|
500
|
+
end
|
501
|
+
|
502
|
+
context "range with negative integers" do
|
503
|
+
subject { idx.at 1..-2 }
|
504
|
+
|
505
|
+
it { is_expected.to be_a described_class }
|
506
|
+
its(:size) { is_expected.to eq 2 }
|
507
|
+
its(:to_a) { is_expected.to eq [[:b, :two, :bar],
|
508
|
+
[:b, :two, :baz]] }
|
509
|
+
end
|
510
|
+
|
511
|
+
context "rangle with single element" do
|
512
|
+
subject { idx.at 1..1 }
|
513
|
+
|
514
|
+
it { is_expected.to be_a described_class }
|
515
|
+
its(:size) { is_expected.to eq 1 }
|
516
|
+
its(:to_a) { is_expected.to eq [[:b, :two, :bar]] }
|
517
|
+
end
|
518
|
+
|
519
|
+
context "invalid position" do
|
520
|
+
it { expect { idx.at 4 }.to raise_error IndexError }
|
521
|
+
end
|
522
|
+
|
523
|
+
context "invalid positions" do
|
524
|
+
it { expect { idx.at 2, 4 }.to raise_error IndexError }
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
context "#add" do
|
529
|
+
let(:idx) do
|
530
|
+
described_class.from_tuples [
|
531
|
+
[:a, :one, :bar],
|
532
|
+
[:a, :two, :bar],
|
533
|
+
[:b, :two, :baz],
|
534
|
+
[:b, :one, :foo]
|
535
|
+
]
|
536
|
+
end
|
537
|
+
|
538
|
+
context "single index" do
|
539
|
+
subject { idx.add :b, :two, :baz }
|
540
|
+
|
541
|
+
its(:to_a) { is_expected.to eq [
|
542
|
+
[:a, :one, :bar],
|
543
|
+
[:a, :two, :bar],
|
544
|
+
[:b, :two, :baz],
|
545
|
+
[:b, :one, :foo],
|
546
|
+
[:b, :two, :baz]] }
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
context "#valid?" do
|
551
|
+
let(:idx) do
|
552
|
+
described_class.from_tuples [
|
553
|
+
[:a, :one, :bar],
|
554
|
+
[:a, :two, :bar],
|
555
|
+
[:b, :two, :baz],
|
556
|
+
[:b, :one, :foo]
|
557
|
+
]
|
558
|
+
end
|
559
|
+
|
560
|
+
context "single index" do
|
561
|
+
it { expect(idx.valid? :a, :one, :bar).to eq true }
|
562
|
+
it { expect(idx.valid? :b, :two, :three).to eq false }
|
563
|
+
end
|
564
|
+
|
565
|
+
context "multiple indexes" do
|
566
|
+
it { expect(idx.valid? :a, :one).to eq true }
|
567
|
+
it { expect(idx.valid? :a, :three).to eq false }
|
568
|
+
end
|
569
|
+
end
|
570
|
+
end
|