object_table 0.2.0 → 0.2.2
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 +6 -4
- data/lib/object_table/column.rb +36 -6
- data/lib/object_table/grouped.rb +51 -16
- data/lib/object_table/masked_column.rb +8 -10
- data/lib/object_table/printable.rb +72 -0
- data/lib/object_table/table_child.rb +19 -0
- data/lib/object_table/table_methods.rb +7 -52
- data/lib/object_table/version.rb +1 -1
- data/lib/object_table/view.rb +2 -3
- data/lib/object_table/view_methods.rb +2 -0
- data/lib/object_table.rb +91 -5
- data/spec/object_table/column_spec.rb +139 -9
- data/spec/object_table/grouped_spec.rb +134 -5
- data/spec/object_table/masked_column_spec.rb +65 -57
- data/spec/object_table_spec.rb +116 -0
- data/spec/subclassing_spec.rb +0 -2
- data/spec/support/object_table_example.rb +36 -1
- data/spec/support/view_example.rb +24 -0
- metadata +4 -5
- data/lib/object_table/temp_grouped.rb +0 -43
- data/spec/object_table/temp_grouped_spec.rb +0 -143
@@ -26,11 +26,39 @@ shared_examples 'a NArray' do |operator, options={}|
|
|
26
26
|
let(:expected_result){ x_na.send(operator, y_na) }
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
describe "#{operator}" do
|
30
|
+
it "should give the correct result" do
|
31
|
+
expect(subject).to eq expected_result
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should return a column' do
|
35
|
+
expect(subject).to be_a ObjectTable::Column
|
36
|
+
end
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
40
|
+
shared_examples 'NArray slicing' do |is_column, *args|
|
41
|
+
let(:x_na) { NArray.to_na(x.to_a) }
|
42
|
+
|
43
|
+
%w{ [] slice }.each do |method|
|
44
|
+
describe "##{method}" do
|
45
|
+
let(:result) { x.send(method, *args) }
|
46
|
+
let(:expected_result) { x_na.send(method, *args) }
|
47
|
+
|
48
|
+
it "should give the correct result" do
|
49
|
+
expect(result).to eq expected_result
|
50
|
+
end
|
51
|
+
|
52
|
+
if is_column
|
53
|
+
it 'should return a column' do
|
54
|
+
expect(result).to be_a ObjectTable::Column
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
34
62
|
shared_examples 'a vectorized operator' do |method|
|
35
63
|
it "should vectorize :#{method} over the array" do
|
36
64
|
expect(subject.send(method).to_a).to eql subject.to_a.map{|x| x.send(method)}
|
@@ -64,15 +92,23 @@ describe ObjectTable::Column do
|
|
64
92
|
|
65
93
|
end
|
66
94
|
|
67
|
-
describe '#
|
68
|
-
let(:
|
69
|
-
let(:column) { ObjectTable::Column.make(value) }
|
70
|
-
let(:index) { 30 }
|
95
|
+
describe '#to_object' do
|
96
|
+
let(:column){ ObjectTable::Column[1, 2, 3] }
|
71
97
|
|
72
|
-
|
98
|
+
it 'should coerce the column into objects' do
|
99
|
+
expect(column.typecode).to eql NArray.int(0).typecode
|
100
|
+
expect(column.to_object.typecode).to eql NArray.object(0).typecode
|
101
|
+
expect(column.to_object).to eq column
|
102
|
+
end
|
103
|
+
end
|
73
104
|
|
74
|
-
|
75
|
-
|
105
|
+
describe '#to_bool' do
|
106
|
+
let(:column){ ObjectTable::Column.cast([true, false, nil, 'abcd', 1234], 'object') }
|
107
|
+
|
108
|
+
it 'should coerce the column into objects' do
|
109
|
+
expect(column.typecode).to eql NArray.object(0).typecode
|
110
|
+
expect(column.to_bool.typecode).to eql NArray.byte(0).typecode
|
111
|
+
expect(column.to_bool).to eq column.map{|i| i ? 1 : 0}
|
76
112
|
end
|
77
113
|
end
|
78
114
|
|
@@ -123,6 +159,100 @@ describe ObjectTable::Column do
|
|
123
159
|
it_behaves_like 'a NArray', '-@', unary: true
|
124
160
|
it_behaves_like 'a NArray', 'abs', unary: true
|
125
161
|
it_behaves_like 'a NArray', 'not', unary: true
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'slicing' do
|
166
|
+
let(:x){ ObjectTable::Column.float(10, 10, 10).random! }
|
167
|
+
|
168
|
+
it_behaves_like 'NArray slicing', false, 0
|
169
|
+
it_behaves_like 'NArray slicing', true, nil
|
170
|
+
it_behaves_like 'NArray slicing', false, 1, 2, 3
|
171
|
+
it_behaves_like 'NArray slicing', true, nil, nil, 5
|
172
|
+
it_behaves_like 'NArray slicing', true, nil, 5, 5
|
173
|
+
it_behaves_like 'NArray slicing', true, nil, true, false
|
174
|
+
it_behaves_like 'NArray slicing', true, [1, 2, 3, 4], nil, nil
|
175
|
+
it_behaves_like 'NArray slicing', true, [1, 2, 3, 4], nil, [1, 2]
|
176
|
+
it_behaves_like 'NArray slicing', true, 3...6
|
177
|
+
it_behaves_like 'NArray slicing', true, nil, nil, 3...6
|
178
|
+
it_behaves_like 'NArray slicing', true, 6...3, nil, 3...6
|
179
|
+
it_behaves_like 'NArray slicing', true, NArray[1..10] > 5, nil, nil
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "#mask" do
|
183
|
+
let(:x) { ObjectTable::Column.float(10, 10, 10).random! }
|
184
|
+
let(:mask) { x < 0.5 }
|
185
|
+
|
186
|
+
let(:expected_result) { NArray.to_na(x.to_a)[mask] }
|
187
|
+
|
188
|
+
subject{ x.mask(mask) }
|
189
|
+
|
190
|
+
it "should give the correct result" do
|
191
|
+
expect(subject).to eq expected_result
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'should return a column' do
|
195
|
+
expect(subject).to be_a ObjectTable::Column
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
context 'when empty' do
|
200
|
+
let(:col) { ObjectTable::Column.float(0) }
|
201
|
+
|
202
|
+
describe '#[]=' do
|
203
|
+
context 'on an empty array' do
|
204
|
+
subject{ col[] = [] }
|
205
|
+
|
206
|
+
it 'should work' do
|
207
|
+
expect{subject}.to_not raise_error
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'on an empty narray' do
|
212
|
+
subject{ col[] = NArray[] }
|
213
|
+
|
214
|
+
it 'should work' do
|
215
|
+
expect{subject}.to_not raise_error
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
context 'on anything else' do
|
220
|
+
subject{ col[] = 3 }
|
221
|
+
|
222
|
+
it 'should not work' do
|
223
|
+
expect{subject}.to raise_error
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe '#stack' do
|
231
|
+
let(:columns) do
|
232
|
+
[
|
233
|
+
ObjectTable::Column.float(10, 10).random!,
|
234
|
+
NArray.float(10, 30).random!,
|
235
|
+
ObjectTable::Column.to_na([[100] * 10] * 5),
|
236
|
+
]
|
237
|
+
end
|
238
|
+
|
239
|
+
subject{ columns[0].stack(*columns[1..-1]) }
|
240
|
+
|
241
|
+
it 'should return a column in the correct format' do
|
242
|
+
expect(subject).to be_a ObjectTable::Column
|
243
|
+
expect(subject.typecode).to eql columns[0].typecode
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'should return a column with the correct size' do
|
247
|
+
expect(subject.shape[0...-1]).to eql columns[0].shape[0...-1]
|
248
|
+
expect(subject.shape[-1]).to eql (10 + 30 + 5)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should stack the columns' do
|
252
|
+
expect(subject[nil, 0...10]).to eq columns[0]
|
253
|
+
expect(subject[nil, 10...40]).to eq columns[1]
|
254
|
+
expect(subject[nil, 40...45]).to eq columns[2]
|
255
|
+
end
|
126
256
|
end
|
127
257
|
|
128
258
|
end
|
@@ -4,9 +4,7 @@ require 'object_table/grouped'
|
|
4
4
|
describe ObjectTable::Grouped do
|
5
5
|
let(:table){ ObjectTable.new(col1: [1, 2, 3, 4], col2: [5, 6, 7, 8] ) }
|
6
6
|
# group based on parity (even vs odd)
|
7
|
-
let(:
|
8
|
-
let(:groups){ {[0] => even, [1] => odd} }
|
9
|
-
let(:grouped){ ObjectTable::Grouped.new(table, names, groups) }
|
7
|
+
let(:grouped){ ObjectTable::Grouped.new(table){ {parity: col1 % 2} } }
|
10
8
|
|
11
9
|
let(:even){ (table.col1 % 2).eq(0).where }
|
12
10
|
let(:odd) { (table.col1 % 2).eq(1).where }
|
@@ -31,6 +29,85 @@ describe ObjectTable::Grouped do
|
|
31
29
|
|
32
30
|
end
|
33
31
|
|
32
|
+
describe '#initialize' do
|
33
|
+
|
34
|
+
context 'when the block takes an argument' do
|
35
|
+
it 'should not evaluate in the context of the table' do
|
36
|
+
rspec_context = self
|
37
|
+
|
38
|
+
grouped = ObjectTable::Grouped.new(table) do |tbl|
|
39
|
+
receiver = eval('self', binding)
|
40
|
+
expect(receiver).to_not be table
|
41
|
+
expect(receiver).to be rspec_context
|
42
|
+
{}
|
43
|
+
end
|
44
|
+
grouped._groups # call _groups to make it call the block
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should pass the table into the block' do
|
48
|
+
grouped = ObjectTable::Grouped.new(table) do |tbl|
|
49
|
+
expect(tbl).to be table
|
50
|
+
{}
|
51
|
+
end
|
52
|
+
grouped._groups # call _groups to make it call the block
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when the block takes no arguments' do
|
57
|
+
it 'should call the block in the context of the table' do
|
58
|
+
_ = self
|
59
|
+
grouped = ObjectTable::Grouped.new(table) do
|
60
|
+
receiver = eval('self', binding)
|
61
|
+
_.expect(receiver).to _.be _.table
|
62
|
+
{}
|
63
|
+
end
|
64
|
+
grouped._groups # call _groups to make it call the block
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'with changes to the parent' do
|
71
|
+
subject{ grouped }
|
72
|
+
|
73
|
+
it 'should mirror changes to the parent' do
|
74
|
+
expect(subject._groups[1]).to eql ({[0] => NArray[1, 3], [1] => NArray[0, 2]})
|
75
|
+
table[:col1] = [2, 3, 4, 5]
|
76
|
+
expect(subject._groups[1]).to eql ({[0] => NArray[0, 2], [1] => NArray[1, 3]})
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#_groups' do
|
81
|
+
subject{ grouped._groups }
|
82
|
+
|
83
|
+
it 'should return the names' do
|
84
|
+
expect(subject[0]).to eql [:parity]
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should return the group key => row mapping' do
|
88
|
+
groups = subject[1]
|
89
|
+
expect(groups[[0]]).to eql even
|
90
|
+
expect(groups[[1]]).to eql odd
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when grouping by columns' do
|
94
|
+
let(:table){ ObjectTable.new(key1: [0]*4 + [1]*4, key2: [0, 0, 1, 1]*2, data: 1..8 ) }
|
95
|
+
let(:grouped){ ObjectTable::Grouped.new(table, :key1, :key2) }
|
96
|
+
|
97
|
+
it 'should use the columns as group names' do
|
98
|
+
expect(subject[0]).to eql [:key1, :key2]
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should use the columns as groups' do
|
102
|
+
groups = subject[1]
|
103
|
+
expect(groups[[0, 0]]).to eql (table.key1.eq(0) & table.key2.eq(0)).where
|
104
|
+
expect(groups[[0, 1]]).to eql (table.key1.eq(0) & table.key2.eq(1)).where
|
105
|
+
expect(groups[[1, 0]]).to eql (table.key1.eq(1) & table.key2.eq(0)).where
|
106
|
+
expect(groups[[1, 1]]).to eql (table.key1.eq(1) & table.key2.eq(1)).where
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
34
111
|
describe '#each' do
|
35
112
|
let(:even_group){ table.where{ (col1 % 2).eq(0) } }
|
36
113
|
let(:odd_group) { table.where{ (col1 % 2).eq(1) } }
|
@@ -103,14 +180,16 @@ describe ObjectTable::Grouped do
|
|
103
180
|
|
104
181
|
describe 'value column auto naming' do
|
105
182
|
it 'should auto name the value column' do
|
106
|
-
grouped = ObjectTable::Grouped.new(table
|
183
|
+
grouped = ObjectTable::Grouped.new(table){{parity: 1}}
|
107
184
|
result = grouped.apply{|group| group.col1.sum}
|
185
|
+
expect(result).to have_column :v_0
|
108
186
|
expect(result.v_0.to_a).to eql [table.col1.sum]
|
109
187
|
end
|
110
188
|
|
111
189
|
it 'should auto name the value column' do
|
112
|
-
grouped = ObjectTable::Grouped.new(table
|
190
|
+
grouped = ObjectTable::Grouped.new(table){{v_0: 1}}
|
113
191
|
result = grouped.apply{|group| group.col1.sum}
|
192
|
+
expect(result).to have_column :v_1
|
114
193
|
expect(result.v_1.to_a).to eql [table.col1.sum]
|
115
194
|
end
|
116
195
|
end
|
@@ -157,4 +236,54 @@ describe ObjectTable::Grouped do
|
|
157
236
|
end
|
158
237
|
end
|
159
238
|
|
239
|
+
describe 'enumerators' do
|
240
|
+
shared_examples 'enumerator method' do |method, *args, block, _expected|
|
241
|
+
let(:expected){ _expected }
|
242
|
+
|
243
|
+
describe "##{method}" do
|
244
|
+
|
245
|
+
it 'should work with a block without args' do
|
246
|
+
result = grouped.send(method, *args){ block.call(self) }
|
247
|
+
if result.is_a? Array
|
248
|
+
expect(result).to match_array expected
|
249
|
+
else
|
250
|
+
expect(result).to eql expected
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'should work with a block with args' do
|
255
|
+
result = grouped.send(method, *args, &block)
|
256
|
+
if result.is_a? Array
|
257
|
+
expect(result).to match_array expected
|
258
|
+
else
|
259
|
+
expect(result).to eql expected
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
|
267
|
+
it_behaves_like 'enumerator method', 'all?', lambda{|grp| grp.col1[0] == 1}, false
|
268
|
+
it_behaves_like 'enumerator method', 'any?', lambda{|grp| grp.col1[0] == 1}, true
|
269
|
+
|
270
|
+
it_behaves_like 'enumerator method', 'collect', lambda{|grp| grp.nrows} do
|
271
|
+
let(:expected){ [even.length, odd.length] }
|
272
|
+
end
|
273
|
+
it_behaves_like 'enumerator method', 'map', lambda{|grp| grp.nrows} do
|
274
|
+
let(:expected){ [even.length, odd.length] }
|
275
|
+
end
|
276
|
+
|
277
|
+
it_behaves_like 'enumerator method', 'collect_concat', lambda{|grp| grp.col1.to_a} do
|
278
|
+
let(:expected){ table.col1 }
|
279
|
+
end
|
280
|
+
it_behaves_like 'enumerator method', 'flat_map', lambda{|grp| grp.col1.to_a} do
|
281
|
+
let(:expected){ table.col1 }
|
282
|
+
end
|
283
|
+
|
284
|
+
it_behaves_like 'enumerator method', 'count', lambda{|grp| grp.col1[0] == 1}, 1
|
285
|
+
it_behaves_like 'enumerator method', 'none?', lambda{|grp| grp.col1[0] > 100}, true
|
286
|
+
it_behaves_like 'enumerator method', 'one?', lambda{|grp| grp.col1[0] < 100}, false
|
287
|
+
end
|
288
|
+
|
160
289
|
end
|
@@ -2,11 +2,12 @@ require 'object_table/masked_column'
|
|
2
2
|
|
3
3
|
describe ObjectTable::MaskedColumn do
|
4
4
|
|
5
|
-
let(:parent) { ObjectTable::Column.
|
5
|
+
let(:parent) { ObjectTable::Column.float(10).random! }
|
6
6
|
let(:indices) { NArray[1, 3, 4, 6] }
|
7
7
|
let(:other_indices) { NArray.to_na((0...parent.length).to_a - indices.to_a) }
|
8
|
+
let(:masked) { ObjectTable::MaskedColumn.mask(parent, indices) }
|
8
9
|
|
9
|
-
subject{
|
10
|
+
subject{ masked }
|
10
11
|
|
11
12
|
describe '.mask' do
|
12
13
|
it 'should mask the parent' do
|
@@ -29,91 +30,98 @@ describe ObjectTable::MaskedColumn do
|
|
29
30
|
expect(subject.rank).to eql 0
|
30
31
|
end
|
31
32
|
end
|
33
|
+
|
34
|
+
context 'with an empty parent' do
|
35
|
+
let(:parent) { NArray.int(0) }
|
36
|
+
let(:indices){ NArray.int(0) }
|
37
|
+
|
38
|
+
it 'should still work' do
|
39
|
+
expect{subject}.to_not raise_error
|
40
|
+
expect(subject.rank).to eql 0
|
41
|
+
end
|
42
|
+
end
|
32
43
|
end
|
33
44
|
|
34
45
|
|
35
|
-
shared_examples '
|
46
|
+
shared_examples '#[]=' do |slice|
|
36
47
|
let(:value) { 1000 }
|
37
48
|
let!(:original){ parent.clone }
|
38
49
|
let(:slice){ slice }
|
39
50
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
51
|
+
context "slicing with a #{slice.class}" do
|
52
|
+
|
53
|
+
it "should modify the parent" do
|
54
|
+
subject[slice] = value
|
55
|
+
expect(parent[indices].to_a).to eql subject.to_a
|
56
|
+
expect(parent[other_indices].to_a).to eql original[other_indices].to_a
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'without a parent' do
|
60
|
+
subject{ ObjectTable::MaskedColumn[1, 2, 3, 4] }
|
61
|
+
|
62
|
+
it 'should still work' do
|
63
|
+
expect{subject[slice] = value}.to_not raise_error
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
44
67
|
end
|
45
68
|
end
|
46
69
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
70
|
+
include_examples '#[]=', 0
|
71
|
+
include_examples '#[]=', NArray.cast([1, 0, 0, 1], 'byte')
|
72
|
+
include_examples '#[]=', 1...4
|
73
|
+
include_examples '#[]=', [0, 2]
|
74
|
+
include_examples '#[]=', true
|
75
|
+
include_examples '#[]=', nil
|
53
76
|
|
54
77
|
|
55
|
-
shared_examples '
|
78
|
+
shared_examples 'destructive methods' do |method, *args|
|
56
79
|
let!(:original) { parent.clone }
|
57
|
-
|
80
|
+
|
81
|
+
let(:perform) do
|
58
82
|
if defined? block
|
59
83
|
subject.send(method, *args, &block)
|
60
84
|
else
|
61
85
|
subject.send(method, *args)
|
62
86
|
end
|
87
|
+
end
|
63
88
|
|
89
|
+
it "#{method} should affect the parent" do
|
90
|
+
perform
|
64
91
|
expect(parent[indices].to_a).to eql subject.to_a
|
65
92
|
expect(parent[other_indices].to_a).to eql original[other_indices].to_a
|
66
93
|
end
|
67
|
-
end
|
68
94
|
|
69
|
-
|
70
|
-
|
71
|
-
it_behaves_like 'a parent modifier', 'fill!', 100
|
72
|
-
it_behaves_like 'a parent modifier', 'random!'
|
73
|
-
it_behaves_like 'a parent modifier', 'conj!'
|
74
|
-
it_behaves_like 'a parent modifier', 'map!' do
|
75
|
-
let(:block) { proc{|x| x + 1} }
|
76
|
-
end
|
77
|
-
it_behaves_like 'a parent modifier', 'collect!' do
|
78
|
-
let(:block) { proc{|x| x + 1} }
|
79
|
-
end
|
80
|
-
it_behaves_like 'a parent modifier', 'imag=', 56
|
81
|
-
it_behaves_like 'a parent modifier', 'add!', 56
|
82
|
-
it_behaves_like 'a parent modifier', 'sbt!', 56
|
83
|
-
it_behaves_like 'a parent modifier', 'mul!', 56
|
84
|
-
it_behaves_like 'a parent modifier', 'div!', 56
|
85
|
-
|
86
|
-
%w{ * + / - xor or and <= >= le ge < > gt lt % ** ne eq & | ^ to_type }.each do |op|
|
87
|
-
context "when performing '#{op}'" do
|
88
|
-
let(:parent) { ObjectTable::Column.make([0, 1, 2, 3, *(4...10)]) }
|
89
|
-
|
90
|
-
it 'should return a ObjectTable::Column' do
|
91
|
-
expect(subject.send(op, subject)).to be_a ObjectTable::Column
|
92
|
-
end
|
95
|
+
context 'without a parent' do
|
96
|
+
subject{ ObjectTable::MaskedColumn[1, 2, 3, 4] }
|
93
97
|
|
94
|
-
it
|
95
|
-
expect
|
98
|
+
it "#{method} should still work" do
|
99
|
+
expect{perform}.to_not raise_error
|
96
100
|
end
|
97
101
|
end
|
98
102
|
end
|
99
103
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
104
|
+
include_examples 'destructive methods', 'indgen!'
|
105
|
+
include_examples 'destructive methods', 'indgen'
|
106
|
+
include_examples 'destructive methods', 'fill!', 100
|
107
|
+
include_examples 'destructive methods', 'random!'
|
108
|
+
include_examples 'destructive methods', 'mod!', 2
|
109
|
+
include_examples 'destructive methods', 'add!', 56
|
110
|
+
include_examples 'destructive methods', 'sbt!', 56
|
111
|
+
include_examples 'destructive methods', 'mul!', 56
|
112
|
+
include_examples 'destructive methods', 'div!', 56
|
113
|
+
include_examples 'destructive methods', 'map!' do
|
114
|
+
let(:block) { proc{|x| x + 1} }
|
115
|
+
end
|
116
|
+
include_examples 'destructive methods', 'collect!' do
|
117
|
+
let(:block) { proc{|x| x + 1} }
|
112
118
|
end
|
113
119
|
|
114
|
-
context 'with
|
115
|
-
let(:parent) { ObjectTable::Column.
|
116
|
-
|
120
|
+
context 'with complex numbers' do
|
121
|
+
let(:parent) { ObjectTable::Column.complex(10).indgen! }
|
122
|
+
|
123
|
+
include_examples 'destructive methods', 'imag=', 56
|
124
|
+
include_examples 'destructive methods', 'conj!'
|
117
125
|
end
|
118
126
|
|
119
127
|
describe '#clone' do
|
data/spec/object_table_spec.rb
CHANGED
@@ -49,6 +49,24 @@ describe ObjectTable do
|
|
49
49
|
|
50
50
|
end
|
51
51
|
|
52
|
+
describe '#inspect' do
|
53
|
+
context 'with an empty table' do
|
54
|
+
subject{ ObjectTable.new }
|
55
|
+
it 'should say it is empty' do
|
56
|
+
text = subject.inspect.split("\n")[1..-1].map(&:rstrip).join("\n")
|
57
|
+
expect(text).to eql "(empty table)"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with table with no rows' do
|
62
|
+
subject{ ObjectTable.new(col1: [], col2: []) }
|
63
|
+
it 'should give the columns' do
|
64
|
+
text = subject.inspect.split("\n")[1..-1].map(&:rstrip).join("\n")
|
65
|
+
expect(text).to eql "(empty table with columns: col1, col2)"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
52
70
|
context '#set_column' do
|
53
71
|
let(:value){ [4, 5, 6] }
|
54
72
|
let(:args) { [] }
|
@@ -162,6 +180,15 @@ describe ObjectTable do
|
|
162
180
|
subject
|
163
181
|
expect(table.columns[column].to_a).to eq value
|
164
182
|
end
|
183
|
+
|
184
|
+
context 'and setting an empty array to the column' do
|
185
|
+
it 'should work' do
|
186
|
+
subject
|
187
|
+
expect{table[column] = []}.to_not raise_error
|
188
|
+
expect(table[column]).to be_empty
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
165
192
|
end
|
166
193
|
end
|
167
194
|
|
@@ -235,6 +262,14 @@ describe ObjectTable do
|
|
235
262
|
end
|
236
263
|
end
|
237
264
|
|
265
|
+
context 'with tables with empty rows' do
|
266
|
+
let(:others) { [ ObjectTable.new(col1: [1, 2, 3], col2: 5), ObjectTable.new(col1: [], col2: []) ] }
|
267
|
+
|
268
|
+
it 'should ignore empty tables' do
|
269
|
+
expect(subject).to eql others[0]
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
238
273
|
context 'with empty grids' do
|
239
274
|
let(:others) { [ ObjectTable.new(col1: [1, 2, 3], col2: 5), ObjectTable::BasicGrid.new ] }
|
240
275
|
|
@@ -258,4 +293,85 @@ describe ObjectTable do
|
|
258
293
|
end
|
259
294
|
end
|
260
295
|
|
296
|
+
describe '#join' do
|
297
|
+
let(:left) do
|
298
|
+
ObjectTable.new(
|
299
|
+
key1: [ "a", "b", "a", "b", "c"],
|
300
|
+
lvalue: [ 0, 1, 2, 3, 4],
|
301
|
+
)
|
302
|
+
end
|
303
|
+
|
304
|
+
let(:right) do
|
305
|
+
ObjectTable.new(
|
306
|
+
key1: [ "d", "c", "b"],
|
307
|
+
rvalue: [ 0, 1, 2],
|
308
|
+
)
|
309
|
+
end
|
310
|
+
|
311
|
+
context 'inner join' do
|
312
|
+
subject{ left.join(right, key=:key1, type: 'inner') }
|
313
|
+
|
314
|
+
let(:result) do
|
315
|
+
ObjectTable.new(
|
316
|
+
key1: [ "b", "b", "c"],
|
317
|
+
lvalue: [ 1, 3, 4],
|
318
|
+
rvalue: [ 2, 2, 1],
|
319
|
+
)
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'should return the joined result' do
|
323
|
+
expect(subject).to eql result
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context 'left join' do
|
328
|
+
subject{ left.join(right, key=:key1, type: 'left') }
|
329
|
+
|
330
|
+
let(:result) do
|
331
|
+
ObjectTable.new(
|
332
|
+
key1: [ "b", "b", "c", "a", "a"],
|
333
|
+
lvalue: [ 1, 3, 4, 0, 2],
|
334
|
+
rvalue: [ 2, 2, 1, 0, 0],
|
335
|
+
)
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'should return the joined result' do
|
339
|
+
expect(subject).to eql result
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
context 'right join' do
|
344
|
+
subject{ left.join(right, key=:key1, type: 'right') }
|
345
|
+
|
346
|
+
let(:result) do
|
347
|
+
ObjectTable.new(
|
348
|
+
key1: [ "b", "b", "c", "d"],
|
349
|
+
lvalue: [ 1, 3, 4, 0],
|
350
|
+
rvalue: [ 2, 2, 1, 0],
|
351
|
+
)
|
352
|
+
end
|
353
|
+
|
354
|
+
it 'should return the joined result' do
|
355
|
+
expect(subject).to eql result
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
context 'outer join' do
|
360
|
+
subject{ left.join(right, key=:key1, type: 'outer') }
|
361
|
+
|
362
|
+
let(:result) do
|
363
|
+
ObjectTable.new(
|
364
|
+
key1: [ "b", "b", "c", "a", "a", "d"],
|
365
|
+
lvalue: [ 1, 3, 4, 0, 2, 0],
|
366
|
+
rvalue: [ 2, 2, 1, 0, 0, 0],
|
367
|
+
)
|
368
|
+
end
|
369
|
+
|
370
|
+
it 'should return the joined result' do
|
371
|
+
expect(subject).to eql result
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
end
|
376
|
+
|
261
377
|
end
|