object_table 0.1.0

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.
@@ -0,0 +1,115 @@
1
+ require 'object_table'
2
+ require 'object_table/grouped'
3
+
4
+ describe ObjectTable::Grouped do
5
+ let(:table){ ObjectTable.new(col1: [1, 2, 3, 4], col2: [5, 6, 7, 8] ) }
6
+ # group based on parity (even vs odd)
7
+ let(:names){ [:parity] }
8
+ let(:groups){ {[0] => even, [1] => odd} }
9
+ let(:grouped){ ObjectTable::Grouped.new(table, names, groups) }
10
+
11
+ let(:even){ (table.col1 % 2).eq(0).where }
12
+ let(:odd) { (table.col1 % 2).eq(1).where }
13
+
14
+ describe '._generate_name' do
15
+ let(:prefix){ 'key_' }
16
+ subject{ ObjectTable::Grouped._generate_name(prefix, existing_keys) }
17
+
18
+ context 'with no matching keys' do
19
+ let(:existing_keys){ ['a', 'b', 'c'] }
20
+ it 'should suffix the key with 0' do
21
+ expect(subject).to eql "key_0"
22
+ end
23
+ end
24
+
25
+ context 'with matching keys' do
26
+ let(:existing_keys){ ['key_1', 'key_67', 'key_8', 'abcd'] }
27
+ it 'should suffix the key with the next available number' do
28
+ expect(subject).to eql "key_68"
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ describe '#each' do
35
+ let(:even_group){ table.where{ (col1 % 2).eq(0) } }
36
+ let(:odd_group) { table.where{ (col1 % 2).eq(1) } }
37
+
38
+ it 'should yield the groups' do
39
+ groups = []
40
+ grouped.each do |group|
41
+ groups << group
42
+ end
43
+
44
+ expect(groups).to match_array [even_group, odd_group]
45
+ end
46
+
47
+ it 'should give access to the keys' do
48
+ keys = []
49
+ grouped.each do |group|
50
+ keys << @K
51
+ end
52
+
53
+ expect(keys).to match_array [{parity: 0}, {parity: 1}]
54
+ end
55
+
56
+ it 'should give access to the correct key' do
57
+ keys = []
58
+ correct_keys = []
59
+ grouped.each do |group|
60
+ keys << [@K[:parity]]
61
+ correct_keys << (self.col1 % 2).uniq.to_a
62
+ end
63
+
64
+ expect(keys).to match_array(correct_keys)
65
+ end
66
+ end
67
+
68
+ describe '#apply' do
69
+ let(:even_group){ table.where{ (col1 % 2).eq(0) } }
70
+ let(:odd_group) { table.where{ (col1 % 2).eq(1) } }
71
+
72
+ subject{ grouped.apply{|group| group.col1.sum} }
73
+
74
+ it 'should return a table with the group keys' do
75
+ expect(subject).to be_a ObjectTable
76
+ expect(subject.colnames).to include :parity
77
+ end
78
+
79
+ it 'should concatenate the results of the block' do
80
+ expect(subject.sort_by(subject.parity)).to eql ObjectTable.new(parity: [0, 1], v_0: [6, 4])
81
+ end
82
+
83
+ describe 'value column auto naming' do
84
+ it 'should auto name the value column' do
85
+ grouped = ObjectTable::Grouped.new(table, names, {[123] => NArray[0, 1, 2, 3]})
86
+ result = grouped.apply{|group| group.col1.sum}
87
+ expect(result.v_0.to_a).to eql [table.col1.sum]
88
+ end
89
+
90
+ it 'should auto name the value column' do
91
+ grouped = ObjectTable::Grouped.new(table, [:v_0], {[123] => NArray[0, 1, 2, 3]})
92
+ result = grouped.apply{|group| group.col1.sum}
93
+ expect(result.v_1.to_a).to eql [table.col1.sum]
94
+ end
95
+ end
96
+
97
+ context 'with results that are grids' do
98
+ subject{ grouped.apply{|g| @R[sum: g.col1.sum, mean: g.col2.mean]} }
99
+
100
+ it 'should return a table with the group keys' do
101
+ expect(subject).to be_a ObjectTable
102
+ expect(subject.colnames).to include :parity
103
+ end
104
+
105
+ it 'should stack the grids' do
106
+ expect(subject.sort_by(subject.parity)).to eql ObjectTable.new(
107
+ parity: [0, 1],
108
+ sum: [even_group.col1.sum, odd_group.col1.sum],
109
+ mean: [even_group.col2.mean, odd_group.col2.mean],
110
+ )
111
+ end
112
+ end
113
+ end
114
+
115
+ end
@@ -0,0 +1,132 @@
1
+ require 'object_table/masked_column'
2
+
3
+ describe ObjectTable::MaskedColumn do
4
+
5
+ let(:parent) { ObjectTable::Column.make([0, 1, 2, Complex(2, 3), *(4...10)]) }
6
+ let(:indices) { NArray[1, 3, 4, 6] }
7
+ let(:other_indices) { NArray.to_na((0...parent.length).to_a - indices.to_a) }
8
+
9
+ subject{ ObjectTable::MaskedColumn.mask(parent, indices) }
10
+
11
+ describe '.mask' do
12
+ it 'should mask the parent' do
13
+ expect(subject.to_a).to eql parent[indices].to_a
14
+ end
15
+
16
+ it 'should set the parent' do
17
+ expect(subject.parent).to eql parent
18
+ end
19
+
20
+ it 'should set the indices' do
21
+ expect(subject.indices).to eql indices
22
+ end
23
+
24
+ context 'with no indices' do
25
+ let(:indices) { NArray.int(0) }
26
+
27
+ it 'should still work' do
28
+ expect{subject}.to_not raise_error
29
+ expect(subject.rank).to eql 0
30
+ end
31
+ end
32
+ end
33
+
34
+
35
+ shared_examples 'a parent slice modifier' do |slice|
36
+ let(:value) { 1000 }
37
+ let!(:original){ parent.clone }
38
+ let(:slice){ slice }
39
+
40
+ it "should modify the parent with a #{slice.class} slice" do
41
+ subject[slice] = value
42
+ expect(parent[indices].to_a).to eql subject.to_a
43
+ expect(parent[other_indices].to_a).to eql original[other_indices].to_a
44
+ end
45
+ end
46
+
47
+ it_behaves_like 'a parent slice modifier', 0
48
+ it_behaves_like 'a parent slice modifier', NArray.cast([1, 0, 0, 1], 'byte')
49
+ it_behaves_like 'a parent slice modifier', 1...4
50
+ it_behaves_like 'a parent slice modifier', [0, 2]
51
+ it_behaves_like 'a parent slice modifier', true
52
+ it_behaves_like 'a parent slice modifier', nil
53
+
54
+
55
+ shared_examples 'a parent modifier' do |method, *args|
56
+ let!(:original) { parent.clone }
57
+ it "should affect the parent table on #{method}" do
58
+ if defined? block
59
+ subject.send(method, *args, &block)
60
+ else
61
+ subject.send(method, *args)
62
+ end
63
+
64
+ expect(parent[indices].to_a).to eql subject.to_a
65
+ expect(parent[other_indices].to_a).to eql original[other_indices].to_a
66
+ end
67
+ end
68
+
69
+ it_behaves_like 'a parent modifier', 'indgen!'
70
+ it_behaves_like 'a parent modifier', 'indgen'
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
93
+
94
+ it 'should not be a masked' do
95
+ expect(subject.send(op, subject)).to_not be_a ObjectTable::MaskedColumn
96
+ end
97
+ end
98
+ end
99
+
100
+ %w{ not abs -@ ~ }.each do |op|
101
+ context "when performing '#{op}'" do
102
+ let(:parent) { ObjectTable::Column.make([0, 1, 2, 3, *(4...10)]) }
103
+
104
+ it 'should return a ObjectTable::Column' do
105
+ expect(subject.send(op)).to be_a ObjectTable::Column
106
+ end
107
+
108
+ it 'should not be a masked' do
109
+ expect(subject.send(op)).to_not be_a ObjectTable::MaskedColumn
110
+ end
111
+ end
112
+ end
113
+
114
+ context 'with real values' do
115
+ let(:parent) { ObjectTable::Column.make(0...10) }
116
+ it_behaves_like 'a parent modifier', 'mod!', 2
117
+ end
118
+
119
+ describe '#clone' do
120
+ let(:clone){ subject.clone }
121
+
122
+ it 'returns a Column' do
123
+ expect(clone).to be_an_instance_of ObjectTable::Column
124
+ expect(clone).to_not be_an_instance_of ObjectTable::MaskedColumn
125
+ end
126
+
127
+ it 'should clone the data' do
128
+ expect(clone.to_a).to eql subject.to_a
129
+ end
130
+ end
131
+
132
+ end
@@ -0,0 +1,105 @@
1
+ require 'object_table'
2
+ require 'object_table/temp_grouped'
3
+
4
+ describe ObjectTable::TempGrouped do
5
+ let(:table){ ObjectTable.new(col1: [1, 2, 3, 4], col2: [5, 6, 7, 8] ) }
6
+ # group based on parity (even vs odd)
7
+ let(:grouped){ ObjectTable::TempGrouped.new(table){ {parity: col1 % 2} } }
8
+
9
+ let(:even){ (table.col1 % 2).eq(0).where }
10
+ let(:odd) { (table.col1 % 2).eq(1).where }
11
+
12
+ context 'with changes to the parent' do
13
+ subject{ grouped }
14
+
15
+ it 'should mirror changes to the parent' do
16
+ expect(subject._groups[1]).to eql ({[0] => NArray[1, 3], [1] => NArray[0, 2]})
17
+ table[:col1] = [2, 3, 4, 5]
18
+ expect(subject._groups[1]).to eql ({[0] => NArray[0, 2], [1] => NArray[1, 3]})
19
+ end
20
+ end
21
+
22
+ describe '#_groups' do
23
+ subject{ grouped._groups }
24
+
25
+ it 'should return the names' do
26
+ expect(subject[0]).to eql [:parity]
27
+ end
28
+
29
+ it 'should return the group key => row mapping' do
30
+ groups = subject[1]
31
+ expect(groups[[0]]).to eql even
32
+ expect(groups[[1]]).to eql odd
33
+ end
34
+
35
+ context 'when grouping by columns' do
36
+ let(:table){ ObjectTable.new(key1: [0]*4 + [1]*4, key2: [0, 0, 1, 1]*2, data: 1..8 ) }
37
+ let(:grouped){ ObjectTable::TempGrouped.new(table, :key1, :key2) }
38
+
39
+ it 'should use the columns as group names' do
40
+ expect(subject[0]).to eql [:key1, :key2]
41
+ end
42
+
43
+ it 'should use the columns as groups' do
44
+ groups = subject[1]
45
+ expect(groups[[0, 0]]).to eql (table.key1.eq(0) & table.key2.eq(0)).where
46
+ expect(groups[[0, 1]]).to eql (table.key1.eq(0) & table.key2.eq(1)).where
47
+ expect(groups[[1, 0]]).to eql (table.key1.eq(1) & table.key2.eq(0)).where
48
+ expect(groups[[1, 1]]).to eql (table.key1.eq(1) & table.key2.eq(1)).where
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#each' do
54
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
55
+ let(:block){ Proc.new{col1 + 100} }
56
+
57
+ let(:names){ subject._groups[0] }
58
+ let(:groups){ subject._groups[1] }
59
+
60
+ subject{ ObjectTable::TempGrouped.new(table){ {parity: col1 % 2} } }
61
+
62
+ it 'should create a group' do
63
+ group = spy('group')
64
+ expect(ObjectTable::Grouped).to receive(:new).with(table, names, groups){ group }
65
+ subject.each(&block)
66
+ end
67
+
68
+ it 'should call #each on the view' do
69
+ group = spy('group')
70
+ expect(ObjectTable::Grouped).to receive(:new){ group }
71
+ expect(group).to receive(:each) do |&b|
72
+ expect(b).to be block
73
+ end
74
+
75
+ subject.each(&block)
76
+ end
77
+ end
78
+
79
+ describe '#apply' do
80
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
81
+ let(:block){ Proc.new{col1 + 100} }
82
+
83
+ let(:names){ subject._groups[0] }
84
+ let(:groups){ subject._groups[1] }
85
+
86
+ subject{ ObjectTable::TempGrouped.new(table){ {parity: col1 % 2} } }
87
+
88
+ it 'should create a group' do
89
+ group = spy('group')
90
+ expect(ObjectTable::Grouped).to receive(:new).with(table, names, groups){ group }
91
+ subject.apply(&block)
92
+ end
93
+
94
+ it 'should call #apply on the view' do
95
+ group = spy('group')
96
+ expect(ObjectTable::Grouped).to receive(:new){ group }
97
+ expect(group).to receive(:apply) do |&b|
98
+ expect(b).to be block
99
+ end
100
+
101
+ subject.apply(&block)
102
+ end
103
+ end
104
+
105
+ end
@@ -0,0 +1,209 @@
1
+ require 'object_table'
2
+ require 'object_table/temp_view'
3
+
4
+ require 'support/object_table_example'
5
+
6
+ describe ObjectTable::TempView do
7
+ it_behaves_like 'an object table', ObjectTable::TempView
8
+
9
+ context 'with changes to the parent' do
10
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
11
+ subject{ ObjectTable::TempView.new(table){ col1 > 2 } }
12
+
13
+ it 'should mirror changes to the parent' do
14
+ expect(subject).to eql ObjectTable.new(col1: 3, col2: 5)
15
+ table[:col1] = [5, 6, 7]
16
+ expect(subject).to eql ObjectTable.new(col1: [5, 6, 7], col2: 5)
17
+ end
18
+ end
19
+
20
+ context 'with nested views' do
21
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
22
+ let(:view1){ table.where{col1 > 1} }
23
+ let(:view2){ view1.where{col1 < 3} }
24
+
25
+ it 'should add columns correctly' do
26
+ view2[:col3] = 5
27
+ expect(view2.col3.to_a).to eql [5]
28
+ expect(view1.col3.to_a).to eql [5, nil]
29
+ expect(table.col3.to_a).to eql [nil, 5, nil]
30
+ end
31
+ end
32
+
33
+ describe '#apply' do
34
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
35
+ let(:block){ Proc.new{col1 + 100} }
36
+
37
+ subject{ ObjectTable::TempView.new(table){ col1 > 2 } }
38
+
39
+ it 'should create a view' do
40
+ view = spy('view')
41
+ expect(ObjectTable::View).to receive(:new).with(table, (table.col1 > 2).where){ view }
42
+ subject.apply(&block)
43
+ end
44
+
45
+ it 'should call #apply on the view' do
46
+ view = spy('view')
47
+ expect(ObjectTable::View).to receive(:new){ view }
48
+ expect(view).to receive(:apply) do |&b|
49
+ expect(b).to be block
50
+ end
51
+
52
+ subject.apply(&block)
53
+ end
54
+ end
55
+
56
+ describe '#group' do
57
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
58
+ let(:block){ Proc.new{col1 + 100} }
59
+
60
+ subject{ ObjectTable::TempView.new(table){ col1 > 2 } }
61
+
62
+ it 'should create a view' do
63
+ view = spy('view')
64
+ expect(ObjectTable::View).to receive(:new).with(table, (table.col1 > 2).where){ view }
65
+ subject.group(&block)
66
+ end
67
+
68
+ it 'should call #group on the view' do
69
+ view = spy('view')
70
+ expect(ObjectTable::View).to receive(:new){ view }
71
+ expect(view).to receive(:group) do |&b|
72
+ expect(b).to be block
73
+ end
74
+
75
+ subject.group(&block)
76
+ end
77
+ end
78
+
79
+ describe '#columns' do
80
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
81
+
82
+ subject{ ObjectTable::TempView.new(table){ col1 > 2 } }
83
+
84
+ it 'should mask the columns of the parent table' do
85
+ mask = table.col1 > 2
86
+ table.columns.each do |k, v|
87
+ expect(subject.columns[k].to_a).to eql v[mask].to_a
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#set_column' do
93
+ let(:table) { ObjectTable.new(col1: [0, 1, 2, 3], col2: 5) }
94
+ let(:view) { ObjectTable::TempView.new(table){ col1 > 0 } }
95
+
96
+ let(:column){ :col2 }
97
+ let(:value) { [10, 20, 30] }
98
+ let(:args) { [] }
99
+
100
+ subject{ view.set_column(column, value, *args) }
101
+
102
+ context 'on an existing column' do
103
+ it 'should assign values to the column' do
104
+ subject
105
+ expect(view.columns[column].to_a).to eql value
106
+ end
107
+
108
+ it 'should not modify anything outside the view' do
109
+ subject
110
+ expect(table.columns[column].to_a).to eql [5] + value
111
+ end
112
+
113
+ end
114
+
115
+ context 'with a scalar' do
116
+ let(:value){ 10 }
117
+ it 'should fill the column with that value' do
118
+ subject
119
+ expect(view.columns[column].to_a).to eql ([value] * view.nrows)
120
+ end
121
+ end
122
+
123
+ context 'with a range' do
124
+ let(:value){ 0...3 }
125
+ it 'should assign the range values' do
126
+ subject
127
+ expect(view.columns[column].to_a).to eql value.to_a
128
+ end
129
+ end
130
+
131
+ context 'with the wrong length' do
132
+ let(:value) { [1, 2] }
133
+
134
+ it 'should fail' do
135
+ expect{subject}.to raise_error
136
+ end
137
+ end
138
+
139
+ context 'for a new column' do
140
+ let(:column){ :col3 }
141
+
142
+ it 'should create a new column' do
143
+ subject
144
+ expect(view.columns).to include column
145
+ expect(view.columns[column].to_a).to eql value
146
+ end
147
+
148
+ it 'should affect the parent table' do
149
+ subject
150
+ expect(table.columns).to include column
151
+ end
152
+
153
+ it 'should fill values outside the view with a default value' do
154
+ subject
155
+ default = NArray.new(table.columns[column].typecode, 1)[0]
156
+ expect(table.columns[column].to_a).to eql [default] + value
157
+ end
158
+
159
+ context 'with an NArray' do
160
+ let(:value){ NArray.int(3, 4, view.nrows).random! }
161
+
162
+ it 'should use the narray parameters' do
163
+ subject
164
+ expect(view.columns[column].to_a).to eql value.to_a
165
+ end
166
+ end
167
+
168
+ context 'when failed to add column' do
169
+ let(:value){ NArray[1, 2, 3] }
170
+
171
+ it 'should not have that column' do
172
+ expect(view).to receive(:add_column).with(column, value.typecode) do
173
+ view.columns[column] = ObjectTable::Column.make([0] * 10)
174
+ table.columns[column] = ObjectTable::Column.make([0] * 10)
175
+ end
176
+
177
+ # the assignment is going to chuck an error
178
+ subject rescue nil
179
+ expect(view.columns).to_not include column
180
+ expect(table.columns).to_not include column
181
+ end
182
+ end
183
+
184
+ end
185
+
186
+ end
187
+
188
+ describe '#pop_column' do
189
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
190
+
191
+ let(:view) { ObjectTable::TempView.new(table){ col1 > 2 } }
192
+ let(:name) { :col2 }
193
+
194
+ subject{ view.pop_column(name) }
195
+
196
+ it 'should remove the column' do
197
+ subject
198
+ expect(view.colnames).to_not include name
199
+ expect(view.columns).to_not include name
200
+ end
201
+
202
+ it 'should remove the column from the parent too' do
203
+ subject
204
+ expect(table.colnames).to_not include name
205
+ expect(table.columns).to_not include name
206
+ end
207
+ end
208
+
209
+ end
@@ -0,0 +1,140 @@
1
+ require 'object_table'
2
+ require 'object_table/view'
3
+
4
+ require 'support/object_table_example'
5
+
6
+ describe ObjectTable::View do
7
+ it_behaves_like 'an object table', ObjectTable::View
8
+
9
+ describe '#columns' do
10
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
11
+
12
+ subject{ ObjectTable::View.new(table, (table.col1 > 2).where) }
13
+
14
+ it 'should mask the columns of the parent table' do
15
+ mask = table.col1 > 2
16
+ table.columns.each do |k, v|
17
+ expect(subject.columns[k].to_a).to eql v[mask].to_a
18
+ end
19
+ end
20
+
21
+ it 'should make masked columns' do
22
+ subject.columns.each do |k, v|
23
+ expect(v).to be_a ObjectTable::MaskedColumn
24
+ end
25
+ end
26
+
27
+ context 'with a matrix in a column' do
28
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
29
+ end
30
+ end
31
+
32
+ describe '#set_column' do
33
+ let(:table) { ObjectTable.new(col1: [0, 1, 2, 3], col2: 5) }
34
+ let(:view) { ObjectTable::View.new(table, (table.col1 > 0).where) }
35
+
36
+ let(:column){ :col1 }
37
+ let(:value) { [10, 20, 30] }
38
+
39
+ let(:args) { [] }
40
+
41
+ subject{ view.set_column(column, value, *args) }
42
+
43
+ context 'on an existing column' do
44
+ it 'should assign values to the column' do
45
+ subject
46
+ expect(view.columns[column].to_a).to eql value
47
+ end
48
+
49
+ it 'should not modify anything outside the view' do
50
+ subject
51
+ expect(table.columns[column].to_a).to eql [0] + value
52
+ end
53
+
54
+ end
55
+
56
+ context 'with a scalar' do
57
+ let(:value){ 10 }
58
+ it 'should fill the column with that value' do
59
+ subject
60
+ expect(view.columns[column].to_a).to eql ([value] * view.nrows)
61
+ end
62
+ end
63
+
64
+ context 'with the wrong length' do
65
+ let(:value) { [1, 2] }
66
+ it 'should fail' do
67
+ expect{subject}.to raise_error
68
+ end
69
+ end
70
+
71
+ context 'for a new column' do
72
+ let(:column){ :col3 }
73
+
74
+ it 'should create a new column' do
75
+ subject
76
+ expect(view.columns).to include column
77
+ expect(view.columns[column].to_a).to eql value
78
+ end
79
+
80
+ it 'should affect the parent table' do
81
+ subject
82
+ expect(table.columns).to include column
83
+ end
84
+
85
+ it 'should fill values outside the view with a default' do
86
+ subject
87
+ default = NArray.new(table.columns[column].typecode, 1)[0]
88
+ expect(table.columns[column].to_a).to eql [default] + value
89
+ end
90
+
91
+ context 'with an NArray' do
92
+ let(:value){ NArray.int(3, 4, view.nrows).random! }
93
+
94
+ it 'should use the narray parameters' do
95
+ subject
96
+ expect(view.columns[column].to_a).to eql value.to_a
97
+ end
98
+ end
99
+
100
+ context 'when failed to add column' do
101
+ let(:value){ NArray[1, 2, 3] }
102
+
103
+ it 'should not have that column' do
104
+ expect(view).to receive(:add_column).with(column, value.typecode) do
105
+ table.columns[column] = ObjectTable::Column.make([0] * 10)
106
+ view.columns[column] = ObjectTable::Column.make([0] * 10)
107
+ end
108
+
109
+ # the assignment is going to chuck an error
110
+ subject rescue nil
111
+ expect(view.columns).to_not include column
112
+ expect(table.columns).to_not include column
113
+ end
114
+ end
115
+ end
116
+
117
+ end
118
+
119
+ describe '#pop_column' do
120
+ let(:table){ ObjectTable.new(col1: [1, 2, 3], col2: 5) }
121
+
122
+ let(:view) { ObjectTable::View.new(table, (table.col1 > 2).where) }
123
+ let(:name) { :col2 }
124
+
125
+ subject{ view.pop_column(name) }
126
+
127
+ it 'should remove the column' do
128
+ subject
129
+ expect(view.colnames).to_not include name
130
+ expect(view.columns).to_not include name
131
+ end
132
+
133
+ it 'should remove the column from the parent too' do
134
+ subject
135
+ expect(table.colnames).to_not include name
136
+ expect(table.columns).to_not include name
137
+ end
138
+ end
139
+
140
+ end