fat_core 1.7.1 → 2.0.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.
@@ -1,990 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module FatCore
4
- describe Table do
5
- before :all do
6
- @csv_file_body = <<-EOS
7
- Ref,Date,Code,RawShares,Shares,Price,Info
8
- 1,2006-05-02,P,5000,5000,8.6000,2006-08-09-1-I
9
- 2,2006-05-03,P,5000,5000,8.4200,2006-08-09-1-I
10
- 3,2006-05-04,P,5000,5000,8.4000,2006-08-09-1-I
11
- 4,2006-05-10,P,8600,8600,8.0200,2006-08-09-1-D
12
- 5,2006-05-12,P,10000,10000,7.2500,2006-08-09-1-D
13
- 6,2006-05-12,P,2000,2000,6.7400,2006-08-09-1-I
14
- 7,2006-05-16,P,5000,5000,7.0000,2006-08-09-1-D
15
- 8,2006-05-17,P,5000,5000,6.7000,2006-08-09-1-D
16
- 9,2006-05-17,P,2000,2000,6.7400,2006-08-09-1-I
17
- 10,2006-05-19,P,1000,1000,7.2500,2006-08-09-1-I
18
- 11,2006-05-19,P,1000,1000,7.2500,2006-08-09-1-I
19
- 12,2006-05-31,P,2000,2000,7.9200,2006-08-09-1-I
20
- 13,2006-06-05,P,1000,1000,7.9200,2006-08-09-1-I
21
- 14,2006-06-15,P,5000,5000,6.9800,2006-08-09-1-I
22
- 15,2006-06-16,P,1000,1000,6.9300,2006-08-09-1-I
23
- 16,2006-06-16,P,1000,1000,6.9400,2006-08-09-1-I
24
- 17,2006-06-29,P,4000,4000,7.0000,2006-08-09-1-I
25
- 18,2006-07-14,P,2000,2000,6.2000,2006-08-09-1-D
26
- 19,2006-08-03,P,1400,1400,4.3900,2006-08-09-1-D
27
- 20,2006-08-07,P,1100,1100,4.5900,2006-08-09-1-D
28
- 21,2006-08-08,P,16000,16000,4.7000,2006-08-21-1-D
29
- 22,2006-08-08,S,16000,16000,4.7000,2006-08-21-1-I
30
- 23,2006-08-15,P,16000,16000,4.8000,2006-08-21-1-D
31
- 24,2006-08-15,S,16000,16000,4.8000,2006-08-21-1-I
32
- 25,2006-08-16,P,2100,2100,5.2900,2006-08-21-1-I
33
- 26,2006-08-17,P,2900,2900,5.7000,2006-08-21-1-I
34
- 27,2006-08-23,P,8000,8000,5.2400,2006-08-25-1-D
35
- 28,2006-08-23,S,8000,8000,5.2400,2006-08-29-1-I
36
- 29,2006-08-28,P,1000,1000,5.4000,2006-08-29-1-D
37
- 30,2006-08-29,P,2000,2000,5.4000,2006-08-30-1-D
38
- 31,2006-08-29,S,2000,2000,5.4000,2006-08-30-1-I
39
- 32,2006-09-05,P,2700,2700,5.7500,2006-09-06-1-I
40
- 33,2006-09-11,P,4000,4000,5.7200,2006-09-15-1-D
41
- 34,2006-09-11,S,4000,4000,5.7200,2006-09-15-1-I
42
- 35,2006-09-12,P,3000,3000,5.4800,2006-09-15-2-I
43
- 36,2006-09-13,P,1700,1700,5.4100,2006-09-15-2-I
44
- 37,2006-09-20,P,7500,7500,5.4900,2006-09-21-1-I
45
- 38,2006-12-07,S,6000,6000,7.8900,2006-12-11-1-I
46
- 39,2006-12-11,S,100,100,8.0000,2006-12-11-1-I
47
- 40,2007-01-29,P,2500,2500,12.1000,2007-04-27-1-I
48
- 41,2007-01-31,P,2500,2500,13.7000,2007-04-27-1-I
49
- 42,2007-02-02,P,4000,4000,15.1500,2007-04-27-1-I
50
- 43,2007-02-06,P,5000,5000,14.9500,2007-04-27-1-I
51
- 44,2007-02-07,P,400,400,15.0000,2007-04-27-1-I
52
- 45,2007-02-08,P,4600,4600,15.0000,2007-04-27-1-I
53
- 46,2007-02-12,P,3500,3500,14.9100,2007-04-27-1-I
54
- 47,2007-02-13,P,1500,1500,14.6500,2007-04-27-1-D
55
- 48,2007-02-14,P,2000,2000,14.4900,2007-04-27-1-D
56
- 49,2007-02-15,P,3000,3000,14.3000,2007-04-27-1-I
57
- 50,2007-02-21,P,8500,8500,14.6500,2007-04-27-1-D
58
- 51,2007-02-21,S,8500,8500,14.6500,2007-04-27-1-I
59
- 52,2007-02-22,P,1500,1500,14.8800,2007-04-27-1-I
60
- 53,2007-02-23,P,3000,3000,14.9700,2007-04-27-1-I
61
- 54,2007-02-23,P,5000,5000,14.9700,2007-04-27-1-I
62
- 55,2007-02-27,P,5200,5200,13.8800,2007-04-27-1-I
63
- 56,2007-02-28,P,6700,6700,13.0000,2007-04-27-1-D
64
- 57,2007-02-28,P,800,800,13.0000,2007-04-27-1-I
65
- 58,2007-02-28,P,8400,8400,13.0000,2007-04-27-1-I
66
- 59,2007-03-01,P,2500,2500,12.2500,2007-04-27-1-D
67
- 60,2007-03-05,P,1800,1800,11.9700,2007-04-27-1-D
68
- 61,2007-03-06,P,500,500,12.1300,2007-04-27-1-D
69
- 62,2007-03-07,P,3000,3000,12.3700,2007-04-27-1-D
70
- 63,2007-03-08,P,2000,2000,12.6000,2007-04-27-1-I
71
- 64,2007-03-09,P,7700,7700,12.8100,2007-04-27-1-I
72
- 65,2007-03-12,P,4200,4200,12.4600,2007-04-27-1-I
73
- 66,2007-03-13,P,800,800,12.2500,2007-04-27-1-I
74
- 67,2007-03-19,P,2000,2000,14.5500,2007-04-27-2-I
75
- 68,2007-03-19,P,5000,5000,14.5500,2007-04-27-2-I
76
- 69,2007-03-19,P,2000,2000,14.3300,2007-04-27-2-I
77
- 70,2007-03-20,P,1000,1000,14.4600,2007-04-27-2-I
78
- 71,2007-03-20,P,1500,1500,14.4600,2007-04-27-2-I
79
- 72,2007-03-21,P,3900,3900,16.9000,2007-04-27-2-I
80
- 73,2007-03-23,P,8000,8000,14.9700,2007-04-27-1-D
81
- 74,2007-03-27,P,1000,1000,16.9300,2007-04-27-2-I
82
- 75,2007-03-28,P,1000,1000,16.5000,2007-04-27-2-D
83
- 76,2007-03-29,P,1000,1000,16.2500,2007-04-27-2-D
84
- 77,2007-04-04,P,200,200,17.8600,2007-04-27-2-I
85
- 78,2007-04-04,P,2000,2000,19.5000,2007-04-27-2-I
86
- 79,2007-04-04,P,3000,3000,19.1300,2007-04-27-2-I
87
- 80,2007-04-05,P,1000,1000,19.1500,2007-04-27-2-I
88
- 81,2007-04-10,P,2000,2000,20.7500,2007-04-27-2-I
89
- 82,2007-04-11,P,1000,1000,20.5000,2007-04-27-2-I
90
- 83,2007-04-12,P,600,600,21.5000,2007-04-27-2-I
91
- 84,2007-04-12,P,1000,1000,21.4500,2007-04-27-2-I
92
- 85,2007-04-13,P,2100,2100,21.5000,2007-04-27-2-I
93
- 86,2007-04-16,P,500,500,22.6000,2007-04-27-2-I
94
- 87,2007-04-17,P,3500,3500,23.5500,2007-04-27-2-D
95
- 88,2007-04-17,S,3500,3500,23.5500,2007-04-27-2-I
96
- 89,2007-04-23,P,5000,5000,23.4500,2007-04-27-2-I
97
- 90,2007-04-24,P,5000,5000,24.3000,2007-04-27-2-I
98
- 91,2007-04-25,S,10000,10000,25.7000,2007-04-27-2-I
99
- EOS
100
-
101
- @org_file_body = <<-EOS
102
-
103
- * Morgan Transactions
104
- :PROPERTIES:
105
- :TABLE_EXPORT_FILE: morgan.csv
106
- :END:
107
-
108
- #+TBLNAME: morgan_tab
109
- | Ref | Date | Code | Raw | Shares | Price | Info |
110
- |-----+------------+------+---------+--------+----------+--------|
111
- | 29 | 2013-05-02 | P | 795,546 | 2,609 | 1.18500 | ZMPEF1 |
112
- | 30 | 2013-05-02 | P | 118,186 | 388 | 11.85000 | ZMPEF1 |
113
- | 31 | 2013-05-02 | P | 340,948 | 1,926 | 1.18500 | ZMPEF2 |
114
- | 32 | 2013-05-02 | P | 50,651 | 286 | 11.85000 | ZMPEF2 |
115
- | 33 | 2013-05-20 | S | 12,000 | 32 | 28.28040 | ZMEAC |
116
- | 34 | 2013-05-20 | S | 85,000 | 226 | 28.32240 | ZMEAC |
117
- | 35 | 2013-05-20 | S | 33,302 | 88 | 28.63830 | ZMEAC |
118
- | 36 | 2013-05-23 | S | 8,000 | 21 | 27.10830 | ZMEAC |
119
- | 37 | 2013-05-23 | S | 23,054 | 61 | 26.80150 | ZMEAC |
120
- | 38 | 2013-05-23 | S | 39,906 | 106 | 25.17490 | ZMEAC |
121
- | 39 | 2013-05-29 | S | 13,459 | 36 | 24.74640 | ZMEAC |
122
- | 40 | 2013-05-29 | S | 15,700 | 42 | 24.77900 | ZMEAC |
123
- | 41 | 2013-05-29 | S | 15,900 | 42 | 24.58020 | ZMEAC |
124
- | 42 | 2013-05-30 | S | 6,679 | 18 | 25.04710 | ZMEAC |
125
-
126
- * Another Heading
127
- EOS
128
-
129
- @org_file_body_with_groups = <<EOS
130
-
131
- #+TBLNAME: morgan_tab
132
- |-----+------------+------+---------+--------+----------+--------|
133
- | Ref | Date | Code | Raw | Shares | Price | Info |
134
- |-----+------------+------+---------+--------+----------+--------|
135
- | 29 | 2013-05-02 | P | 795,546 | 2,609 | 1.18500 | ZMPEF1 |
136
- |-----+------------+------+---------+--------+----------+--------|
137
- | 30 | 2013-05-02 | P | 118,186 | 388 | 11.85000 | ZMPEF1 |
138
- | 31 | 2013-05-02 | P | 340,948 | 1,926 | 1.18500 | ZMPEF2 |
139
- | 32 | 2013-05-02 | P | 50,651 | 286 | 11.85000 | ZMPEF2 |
140
- |-----+------------+------+---------+--------+----------+--------|
141
- | 33 | 2013-05-20 | S | 12,000 | 32 | 28.28040 | ZMEAC |
142
- | 34 | 2013-05-20 | S | 85,000 | 226 | 28.32240 | ZMEAC |
143
- | 35 | 2013-05-20 | S | 33,302 | 88 | 28.63830 | ZMEAC |
144
- | 36 | 2013-05-23 | S | 8,000 | 21 | 27.10830 | ZMEAC |
145
- | 37 | 2013-05-23 | S | 23,054 | 61 | 26.80150 | ZMEAC |
146
- | 38 | 2013-05-23 | S | 39,906 | 106 | 25.17490 | ZMEAC |
147
- | 39 | 2013-05-29 | S | 13,459 | 36 | 24.74640 | ZMEAC |
148
- |-----+------------+------+---------+--------+----------+--------|
149
- | 40 | 2013-05-29 | S | 15,700 | 42 | 24.77900 | ZMEAC |
150
- | 41 | 2013-05-29 | S | 15,900 | 42 | 24.58020 | ZMEAC |
151
- | 42 | 2013-05-30 | S | 6,679 | 18 | 25.04710 | ZMEAC |
152
- |-----+------------+------+---------+--------+----------+--------|
153
-
154
- EOS
155
- end
156
-
157
- describe 'construction' do
158
- it 'should be create-able from a CSV string' do
159
- tab = Table.from_csv_string(@csv_file_body)
160
- expect(tab.class).to eq(Table)
161
- expect(tab.rows.size).to be > 20
162
- expect(tab.headers.sort)
163
- .to eq [:code, :date, :info, :price, :rawshares, :ref, :shares]
164
- tab.rows.each do |row|
165
- row.each_pair do |k, _v|
166
- expect(k.class).to eq Symbol
167
- end
168
- expect(row[:code].class).to eq String
169
- expect(row[:date].class).to eq Date
170
- expect(row[:shares].is_a?(Numeric)).to be true
171
- unless row[:rawshares].nil?
172
- expect(row[:rawshares].is_a?(Numeric)).to be true
173
- end
174
- expect(row[:price].is_a?(Numeric)).to be true
175
- expect([Numeric, String].any? { |t| row[:ref].is_a?(t) }).to be true
176
- end
177
- end
178
-
179
- it 'should be create-able from an Org string' do
180
- tab = Table.from_org_string(@org_file_body)
181
- expect(tab.class).to eq(Table)
182
- expect(tab.rows.size).to be > 10
183
- expect(tab.headers.sort)
184
- .to eq [:code, :date, :info, :price, :raw, :ref, :shares]
185
- tab.rows.each do |row|
186
- row.each_pair do |k, _v|
187
- expect(k.class).to eq Symbol
188
- end
189
- expect(row[:code].class).to eq String
190
- expect(row[:date].class).to eq Date
191
- expect(row[:shares].is_a?(Numeric)).to be true
192
- unless row[:rawshares].nil?
193
- expect(row[:rawshares].is_a?(Numeric)).to be true
194
- end
195
- expect(row[:price].is_a?(BigDecimal)).to be true
196
- expect([Numeric, String].any? { |t| row[:ref].is_a?(t) }).to be true
197
- expect(row[:info].class).to eq String
198
- end
199
- end
200
-
201
- it 'should be create-able from an Org string with groups' do
202
- tab = Table.from_org_string(@org_file_body)
203
- expect(tab.class).to eq(Table)
204
- expect(tab.rows.size).to be > 10
205
- expect(tab.headers.sort)
206
- .to eq [:code, :date, :info, :price, :raw, :ref, :shares]
207
- tab.rows.each do |row|
208
- row.each_pair do |k, _v|
209
- expect(k.class).to eq Symbol
210
- end
211
- expect(row[:code].class).to eq String
212
- expect(row[:date].class).to eq Date
213
- expect(row[:shares].is_a?(Numeric)).to be true
214
- unless row[:rawshares].nil?
215
- expect(row[:rawshares].is_a?(Numeric)).to be true
216
- end
217
- expect(row[:price].is_a?(BigDecimal)).to be true
218
- expect([Numeric, String].any? { |t| row[:ref].is_a?(t) }).to be true
219
- expect(row[:info].class).to eq String
220
- end
221
- end
222
-
223
- it 'should be create-able from a CSV file' do
224
- File.open('/tmp/junk.csv', 'w') { |f| f.write(@csv_file_body) }
225
- tab = Table.from_csv_file('/tmp/junk.csv')
226
- expect(tab.class).to eq(Table)
227
- expect(tab.rows.size).to be > 20
228
- expect(tab.headers.sort)
229
- .to eq [:code, :date, :info, :price, :rawshares, :ref, :shares]
230
- tab.rows.each do |row|
231
- row.each_pair do |k, _v|
232
- expect(k.class).to eq Symbol
233
- end
234
- expect(row[:code].class).to eq String
235
- expect(row[:date].class).to eq Date
236
- expect(row[:shares].is_a?(Numeric)).to be true
237
- unless row[:rawshares].nil?
238
- expect(row[:rawshares].is_a?(Numeric)).to be true
239
- end
240
- expect(row[:price].is_a?(BigDecimal)).to be true
241
- expect([Numeric, String].any? { |t| row[:ref].is_a?(t) }).to be true
242
- expect(row[:info].class).to eq Date
243
- end
244
- end
245
-
246
- it 'should be create-able from an Org file' do
247
- File.open('/tmp/junk.org', 'w') { |f| f.write(@org_file_body) }
248
- tab = Table.from_org_file('/tmp/junk.org')
249
- expect(tab.class).to eq(Table)
250
- expect(tab.rows.size).to be > 10
251
- expect(tab.rows[0].keys.sort)
252
- .to eq [:code, :date, :info, :price, :raw, :ref, :shares]
253
- tab.rows.each do |row|
254
- row.each_pair do |k, _v|
255
- expect(k.class).to eq Symbol
256
- end
257
- expect(row[:code].class).to eq String
258
- expect(row[:date].class).to eq Date
259
- expect(row[:shares].is_a?(Numeric)).to be true
260
- unless row[:rawshares].nil?
261
- expect(row[:rawshares].is_a?(Numeric)).to be true
262
- end
263
- expect(row[:price].is_a?(BigDecimal)).to be true
264
- expect([Numeric, String].any? { |t| row[:ref].is_a?(t) }).to be true
265
- expect(row[:info].class).to eq String
266
- end
267
- end
268
-
269
- it 'should be create-able from an Array of Arrays with header and hrule' do
270
- # rubocop:disable Style/WordArray
271
- aoa = [
272
- ['First', 'Second', 'Third'],
273
- ['|---------+----------+---------|', nil, nil],
274
- ['1', '2', '3.2'],
275
- ['4', '5', '6.4'],
276
- ['7', '8', '9.0'],
277
- [10, 11, 12.1]
278
- ]
279
- tab = Table.from_aoa(aoa)
280
- expect(tab.class).to eq(Table)
281
- expect(tab.rows.size).to eq(4)
282
- expect(tab.rows[0].keys.sort).to eq [:first, :second, :third]
283
- tab.rows.each do |row|
284
- row.each_pair do |k, _v|
285
- expect(k.class).to eq Symbol
286
- end
287
- expect(row[:first].is_a?(Numeric)).to be true
288
- expect(row[:second].is_a?(Numeric)).to be true
289
- expect(row[:third].is_a?(BigDecimal)).to be true
290
- end
291
- end
292
-
293
- it 'should be create-able from an Array of Arrays with nil-marked header' do
294
- aoa = [
295
- ['First', 'Second', 'Third'],
296
- nil,
297
- ['1', '2', '3.2'],
298
- ['4', '5', '6.4'],
299
- ['7', '8', '9.0'],
300
- [10, 11, 12.1]
301
- ]
302
- tab = Table.from_aoa(aoa)
303
- expect(tab.class).to eq(Table)
304
- expect(tab.rows.size).to eq(4)
305
- expect(tab.headers.sort).to eq [:first, :second, :third]
306
- tab.rows.each do |row|
307
- row.each_pair do |k, _v|
308
- expect(k.class).to eq Symbol
309
- end
310
- expect(row[:first].is_a?(Numeric)).to be true
311
- expect(row[:second].is_a?(Numeric)).to be true
312
- expect(row[:third].is_a?(BigDecimal)).to be true
313
- end
314
- end
315
-
316
- it 'should be create-able from an Array of Arrays sans Header' do
317
- aoa = [
318
- ['1', '2', '3.2'],
319
- ['4', '5', '6.4'],
320
- ['7', '8', '9.0'],
321
- [7, 8, 9.3]
322
- ]
323
- # rubocop:enable Style/WordArray
324
- tab = Table.from_aoa(aoa)
325
- expect(tab.class).to eq(Table)
326
- expect(tab.rows.size).to eq(4)
327
- expect(tab.headers.sort).to eq [:col1, :col2, :col3]
328
- tab.rows.each do |row|
329
- row.each_pair do |k, _v|
330
- expect(k.class).to eq Symbol
331
- end
332
- expect(row[:col1].is_a?(Numeric)).to be true
333
- expect(row[:col2].is_a?(Numeric)).to be true
334
- expect(row[:col3].is_a?(BigDecimal)).to be true
335
- end
336
- end
337
-
338
- it 'should be create-able from an Array of Hashes' do
339
- aoh = [
340
- { a: '1', 'Two words' => '2', c: '3.2' },
341
- { a: '4', 'Two words' => '5', c: '6.4' },
342
- { a: '7', 'Two words' => '8', c: '9.0' },
343
- { a: 10, 'Two words' => 11, c: 12.4 }
344
- ]
345
- tab = Table.from_aoh(aoh)
346
- expect(tab.class).to eq(Table)
347
- expect(tab.rows.size).to eq(4)
348
- expect(tab.rows[0].keys.sort).to eq [:a, :c, :two_words]
349
- tab.rows.each do |row|
350
- row.each_pair do |k, _v|
351
- expect(k.class).to eq Symbol
352
- end
353
- expect(row[:a].is_a?(Numeric)).to be true
354
- expect(row[:two_words].is_a?(Numeric)).to be true
355
- expect(row[:c].is_a?(BigDecimal)).to be true
356
- end
357
- end
358
-
359
- it 'should set T F columns to Boolean' do
360
- cwd = File.dirname(__FILE__)
361
- dwtab = Table.from_org_file(cwd + '/../example_files/datawatch.org')
362
- expect(dwtab.column(:g10).type).to eq('Boolean')
363
- expect(dwtab.column(:qp10).type).to eq('Boolean')
364
- dwo = dwtab.where('qp10 || g10')
365
- dwo.rows.each do |row|
366
- expect(row[:qp10].class.to_s).to match(/TrueClass|FalseClass/)
367
- end
368
- end
369
- end
370
-
371
- describe 'indexing' do
372
- before :all do
373
- @tab = Table.from_aoh([
374
- { a: '1', 'Two words' => '2', c: '3,123', d: 'apple' },
375
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
376
- { a: '7', 'Two words' => '8', c: '$9,888', d: 'pear' }])
377
- end
378
-
379
- it 'should be able to index by column head' do
380
- expect(@tab[:a]).to eq([1, 4, 7])
381
- expect(@tab[:d]).to eq(%w(apple orange pear))
382
- expect { @tab[:r] }.to raise_error /not in table/
383
- end
384
-
385
- it 'should be able to index by row number' do
386
- expect(@tab[1]).to eq({a: 1, two_words: 2, c: 3123, d: 'apple'})
387
- expect(@tab[3]).to eq({a: 7, two_words: 8, c: 9888, d: 'pear'})
388
- expect { @tab[0] }.to raise_error(/out of range/)
389
- expect { @tab[4] }.to raise_error(/out of range/)
390
- end
391
- end
392
-
393
- describe 'column operations' do
394
- it 'should be able to sum a column' do
395
- aoh = [
396
- { a: '1', 'Two words' => '2', c: '3,123', d: 'apple' },
397
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
398
- { a: '7', 'Two words' => '8', c: '$9,888', d: 'pear' }
399
- ]
400
- tab = Table.from_aoh(aoh)
401
- expect(tab.column(:a).sum).to eq 12
402
- expect(tab[:two_words].sum).to eq 15
403
- expect(tab.column(:c).sum).to eq 19_423
404
- expect(tab.column(:d).sum).to eq 'appleorangepear'
405
- end
406
-
407
- it 'should be able to sum a column ignoring nils' do
408
- aoh = [
409
- { a: '', 'Two words' => '2', c: '', d: 'apple' },
410
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
411
- { a: '7', 'Two words' => '8', c: '$9,888', d: 'pear' }
412
- ]
413
- tab = Table.from_aoh(aoh)
414
- expect(tab.column(:a).sum).to eq 11
415
- expect(tab.column(:two_words).sum).to eq 15
416
- expect(tab.column(:c).sum).to eq 16_300
417
- expect(tab.column(:d).sum).to eq 'appleorangepear'
418
- end
419
-
420
- it 'should be able to report its headings' do
421
- tab = Table.from_csv_string(@csv_file_body)
422
- expect(tab.headers.sort)
423
- .to eq [:code, :date, :info, :price, :rawshares, :ref, :shares]
424
- end
425
-
426
- it 'should be able to extract a column as an array' do
427
- aoh = [
428
- { a: '1', 'Two words' => '2', c: '3,123', d: 'apple' },
429
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
430
- { a: '7', 'Two words' => '8', c: '$9,888', d: 'pear' }
431
- ]
432
- tab = Table.from_aoh(aoh)
433
- expect(tab[:a]).to eq [1, 4, 7]
434
- expect(tab[:c]).to eq [3123, 6412, 9888]
435
- end
436
-
437
- it 'should be able to sum a column' do
438
- aoh = [
439
- { a: '1', 'Two words' => '2', c: '3,123', d: 'apple' },
440
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
441
- { a: '7', 'Two words' => '8', c: '$9,888', d: 'pear' }
442
- ]
443
- tab = Table.from_aoh(aoh)
444
- expect(tab.column(:a).sum).to eq 12
445
- expect(tab.column(:c).sum).to eq 19_423
446
- expect(tab.column(:c).sum.is_a?(Integer)).to be true
447
- end
448
-
449
- it 'should be able to average a column' do
450
- aoh = [
451
- { a: '1', 'Two words' => '2', c: '3,123', d: 'apple' },
452
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
453
- { a: '7', 'Two words' => '8', c: '$9,888', d: 'pear' }
454
- ]
455
- tab = Table.from_aoh(aoh)
456
- expect(tab.column(:a).avg).to eq 4
457
- expect(tab.column(:c).avg.round(4)).to eq 6474.3333
458
- expect(tab.column(:c).avg.class).to eq BigDecimal
459
- end
460
-
461
- it 'should be able to get column minimum' do
462
- aoh = [
463
- { a: '1', 'Two words' => '2', c: '3,123', d: 'apple' },
464
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
465
- { a: '7', 'Two words' => '8', c: '$9,888', d: 'pear' }
466
- ]
467
- tab = Table.from_aoh(aoh)
468
- expect(tab.column(:a).min).to eq 1
469
- expect(tab.column(:c).min.round(4)).to eq 3123
470
- expect(tab.column(:c).min.is_a?(Integer)).to be true
471
- expect(tab.column(:d).min).to eq 'apple'
472
- end
473
-
474
- it 'should be able to get column maximum' do
475
- aoh = [
476
- { a: '1', 'Two words' => '2', c: '3,123', d: 'apple' },
477
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
478
- { a: '7', 'Two words' => '8', c: '$9,888', d: 'pear' }
479
- ]
480
- tab = Table.from_aoh(aoh)
481
- expect(tab.column(:a).max).to eq 7
482
- expect(tab.column(:c).max.round(4)).to eq 9888
483
- expect(tab.column(:c).max.is_a?(Integer)).to be true
484
- expect(tab.column(:d).max).to eq 'pear'
485
- end
486
- end
487
-
488
- describe 'sorting' do
489
- it 'should be able to sort its rows on one column' do
490
- aoh = [
491
- { a: '5', 'Two words' => '20', c: '3,123', d: 'apple' },
492
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
493
- { a: '7', 'Two words' => '8', c: '$1,888', d: 'apple' }
494
- ]
495
- tab = Table.from_aoh(aoh).order_by(:a)
496
- expect(tab.rows[0][:a]).to eq 4
497
- end
498
-
499
- it 'should be able to sort its rows on multiple columns' do
500
- aoh = [
501
- { a: '5', 'Two words' => '20', c: '3,123', d: 'apple' },
502
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
503
- { a: '7', 'Two words' => '8', c: '$1,888', d: 'apple' }
504
- ]
505
- tab = Table.from_aoh(aoh).order_by(:d, :c)
506
- expect(tab.rows[0][:a]).to eq 7
507
- end
508
-
509
- it 'should be able to reverse sort its rows on one column' do
510
- aoh = [
511
- { a: '5', 'Two words' => '20', c: '3,123', d: 'apple' },
512
- { a: '4', 'Two words' => '5', c: '6,412', d: 'orange' },
513
- { a: '7', 'Two words' => '8', c: '$1,888', d: 'apple' }
514
- ]
515
- tab = Table.from_aoh(aoh).order_by(:d!)
516
- expect(tab.rows[0][:d]).to eq 'orange'
517
- expect(tab.rows[2][:d]).to eq 'apple'
518
- end
519
-
520
- it 'should sort its rows on mixed forward and reverse columns' do
521
- aoh = [
522
- { a: '5', 'Two words' => '20', c: '3,123', d: 'apple' },
523
- { a: '4', 'Two words' => '5', c: 6412, d: 'orange' },
524
- { a: '7', 'Two words' => '8', c: '$1,888', d: 'apple' }
525
- ]
526
- tab = Table.from_aoh(aoh).order_by(:d!, :c)
527
- expect(tab.rows[0][:d]).to eq 'orange'
528
- expect(tab.rows[1][:d]).to eq 'apple'
529
- expect(tab.rows[1][:c]).to eq 1888
530
- expect(tab.rows[2][:d]).to eq 'apple'
531
- end
532
- end
533
-
534
- describe 'union' do
535
- it 'should be able to union with a compatible table' do
536
- aoh = [
537
- { a: '5', 'Two words' => '20', c: '3,123', d: 'apple' },
538
- { a: '4', 'Two words' => '5', c: 6412, d: 'orange' },
539
- { a: '7', 'Two words' => '8', c: '$1,888', d: 'apple' }
540
- ]
541
- tab1 = Table.from_aoh(aoh)
542
- aoh2 = [
543
- { t: '8', 'Two worlds' => '65', s: '5,143', u: 'kiwi' },
544
- { t: '87', 'Two worlds' => '12', s: 412, u: 'banana' },
545
- { t: '13', 'Two worlds' => '11', s: '$1,821', u: 'grape' }
546
- ]
547
- tab2 = Table.from_aoh(aoh2)
548
- utab = tab1.union(tab2)
549
- expect(utab.rows.size).to eq(6)
550
- end
551
-
552
- it 'should throw an exception for union with different sized tables' do
553
- aoh = [
554
- { a: '5', 'Two words' => '20', c: '3,123' },
555
- { a: '4', 'Two words' => '5', c: 6412 },
556
- { a: '7', 'Two words' => '8', c: '$1,888' }
557
- ]
558
- tab1 = Table.from_aoh(aoh)
559
- aoh2 = [
560
- { t: '8', 'Two worlds' => '65', s: '5,143', u: 'kiwi' },
561
- { t: '87', 'Two worlds' => '12', s: 412, u: 'banana' },
562
- { t: '13', 'Two worlds' => '11', s: '$1,821', u: 'grape' }
563
- ]
564
- tab2 = Table.from_aoh(aoh2)
565
- expect {
566
- tab1.union(tab2)
567
- }.to raise_error(/different number of columns/)
568
- end
569
-
570
- it 'should throw an exception for union with different types' do
571
- aoh = [
572
- { a: '5', 'Two words' => '20', s: '5143', c: '3123' },
573
- { a: '4', 'Two words' => '5', s: 412, c: 6412 },
574
- { a: '7', 'Two words' => '8', s: '$1821', c: '$1888' }
575
- ]
576
- tab1 = Table.from_aoh(aoh)
577
- aoh2 = [
578
- { t: '8', 'Two worlds' => '65', s: '2016-01-17', u: 'kiwi' },
579
- { t: '87', 'Two worlds' => '12', s: Date.today, u: 'banana' },
580
- { t: '13', 'Two worlds' => '11', s: '[2015-05-21]', u: 'grape' }
581
- ]
582
- tab2 = Table.from_aoh(aoh2)
583
- expect {
584
- tab1.union(tab2)
585
- }.to raise_error(/different column types/)
586
- end
587
- end
588
-
589
- describe 'select' do
590
- it 'should be able to select by column names' do
591
- aoh = [
592
- { a: '5', 'Two words' => '20', s: '5143', c: '3123' },
593
- { a: '4', 'Two words' => '5', s: 412, c: 6412 },
594
- { a: '7', 'Two words' => '8', s: '$1821', c: '$1888' }
595
- ]
596
- tab1 = Table.from_aoh(aoh)
597
- tab2 = tab1.select(:s, :a, :c)
598
- expect(tab2.headers).to eq [:s, :a, :c]
599
- end
600
-
601
- it 'should be able to select by column names renaming columns' do
602
- aoh = [
603
- { a: '5', 'Two words' => '20', s: '5143', c: '3123' },
604
- { a: '4', 'Two words' => '5', s: 412, c: 6412 },
605
- { a: '7', 'Two words' => '8', s: '$1821', c: '$1888' }
606
- ]
607
- tab1 = Table.from_aoh(aoh)
608
- tab2 = tab1.select(former_s: :s, new_a: :a, renew_c: :c)
609
- expect(tab2.headers).to eq [:former_s, :new_a, :renew_c]
610
- end
611
-
612
- it 'should be able to select new columns computed from prior' do
613
- aoh = [
614
- { a: '5', 'Two words' => '20', s: '5143', c: '3123' },
615
- { a: '4', 'Two words' => '5', s: 412, c: 6412 },
616
- { a: '7', 'Two words' => '8', s: '$1821', c: '$1888' }
617
- ]
618
- tab1 = Table.from_aoh(aoh)
619
- tab2 = tab1.select(:two_words, row: '@row', s_squared: 's * s',
620
- arb: 's_squared / (a + c).to_d')
621
- expect(tab2.headers).to eq [:two_words, :row, :s_squared, :arb]
622
- end
623
-
624
- it 'should be able to use old value of current column to compute new value' do
625
- aoh = [
626
- { a: '5', 'Two words' => '20', s: '5_143', c: '3123' },
627
- { a: '4', 'Two words' => '5', s: 412, c: 6412 },
628
- { a: '7', 'Two words' => '8', s: '$1821', c: '$1_888' }
629
- ]
630
- tab1 = Table.from_aoh(aoh)
631
- tab2 = tab1.select(:two_words, s: 's * s', nc: 'c + c', c: 'nc+nc')
632
- expect(tab2.headers).to eq [:two_words, :s, :nc, :c]
633
- expect(tab2[:s]).to eq([26450449, 169744, 3316041])
634
- expect(tab2[:c]).to eq([12492, 25648, 7552])
635
- end
636
-
637
- it 'should have access to @row and @group vars in evaluating' do
638
- aoh = [
639
- { a: '5', 'Two words' => '20', s: '5_143', c: '3123' },
640
- { a: '4', 'Two words' => '5', s: 412, c: 6412 },
641
- { a: '7', 'Two words' => '8', s: '$1721', c: '$1_888' },
642
- { a: '5', 'Two words' => '20', s: '4_143', c: '4123' },
643
- { a: '4', 'Two words' => '5', s: 512, c: 5412 },
644
- { a: '7', 'Two words' => '8', s: '$1621', c: '$2_888' },
645
- { a: '5', 'Two words' => '20', s: '3_143', c: '5123' },
646
- { a: '4', 'Two words' => '5', s: 412, c: 4412 },
647
- { a: '7', 'Two words' => '8', s: '$1521', c: '$3_888' }
648
- ]
649
- tab = Table.from_aoh(aoh).order_by(:a, :two_words)
650
- tab2 = tab.select(:a, :two_words, number: '@row', group: '@group')
651
- expect(tab2.headers).to eq [:a, :two_words, :number, :group]
652
- expect(tab2[:number]).to eq([1, 2, 3, 4, 5, 6, 7, 8, 9])
653
- expect(tab2[:group]).to eq([1, 1, 1, 2, 2, 2, 3, 3, 3])
654
- end
655
- end
656
-
657
- describe 'where' do
658
- it 'should be able to filter rows by expression' do
659
- tab1 = Table.from_csv_string(@csv_file_body)
660
- tab2 = tab1.where("date < Date.parse('2006-06-01')")
661
- expect(tab2[:date].max).to be < Date.parse('2006-06-01')
662
- end
663
-
664
- it 'should where by boolean columns' do
665
- aoa =
666
- [['Ref', 'Date', 'Code', 'Raw', 'Shares', 'Price', 'Info', 'Bool'],
667
- nil,
668
- [1, '2013-05-02', 'P', 795_546.20, 795_546.2, 1.1850, 'ZMPEF1', 'T'],
669
- [2, '2013-05-02', 'P', 118_186.40, 118_186.4, 11.8500, 'ZMPEF1', 'T'],
670
- [7, '2013-05-20', 'S', 12_000.00, 5046.00, 28.2804, 'ZMEAC', 'F'],
671
- [8, '2013-05-20', 'S', 85_000.00, 35_742.50, 28.3224, 'ZMEAC', 'T'],
672
- [9, '2013-05-20', 'S', 33_302.00, 14_003.49, 28.6383, 'ZMEAC', 'T'],
673
- [10, '2013-05-23', 'S', 8000.00, 3364.00, 27.1083, 'ZMEAC', 'T'],
674
- [11, '2013-05-23', 'S', 23_054.00, 9694.21, 26.8015, 'ZMEAC', 'F'],
675
- [12, '2013-05-23', 'S', 39_906.00, 16_780.47, 25.1749, 'ZMEAC', 'T'],
676
- [13, '2013-05-29', 'S', 13_459.00, 5659.51, 24.7464, 'ZMEAC', 'T'],
677
- [14, '2013-05-29', 'S', 15_700.00, 6601.85, 24.7790, 'ZMEAC', 'F'],
678
- [15, '2013-05-29', 'S', 15_900.00, 6685.95, 24.5802, 'ZMEAC', 'T'],
679
- [16, '2013-05-30', 'S', 6_679.00, 2808.52, 25.0471, 'ZMEAC', 'T']]
680
- tab = Table.from_aoa(aoa)
681
- tab2 = tab.where('!bool || code == "P"')
682
- expect(tab2.rows.size).to eq(5)
683
- tab2 = tab.where('code == "S" && raw < 10_000')
684
- expect(tab2.rows.size).to eq(2)
685
- tab2 = tab.where('@row > 10')
686
- expect(tab2.rows.size).to eq(2)
687
- tab2 = tab.where('info =~ /zmeac/i')
688
- expect(tab2.rows.size).to eq(10)
689
- tab2 = tab.where('info =~ /xxxx/')
690
- expect(tab2.rows.size).to eq(0)
691
- end
692
-
693
- it 'where clause with row and group' do
694
- aoa =
695
- [['Ref', 'Date', 'Code', 'Raw', 'Shares', 'Price', 'Info', 'Bool'],
696
- nil,
697
- [1, '2013-05-02', 'P', 795_546.20, 795_546.2, 1.1850, 'ZMPEF1', 'T'],
698
- [2, '2013-05-02', 'P', 118_186.40, 118_186.4, 11.8500, 'ZMPEF1', 'T'],
699
- [7, '2013-05-20', 'S', 12_000.00, 5046.00, 28.2804, 'ZMEAC', 'F'],
700
- [8, '2013-05-20', 'S', 85_000.00, 35_742.50, 28.3224, 'ZMEAC', 'T'],
701
- [9, '2013-05-20', 'S', 33_302.00, 14_003.49, 28.6383, 'ZMEAC', 'T'],
702
- [10, '2013-05-23', 'S', 8000.00, 3364.00, 27.1083, 'ZMEAC', 'T'],
703
- [11, '2013-05-23', 'S', 23_054.00, 9694.21, 26.8015, 'ZMEAC', 'F'],
704
- [12, '2013-05-23', 'S', 39_906.00, 16_780.47, 25.1749, 'ZMEAC', 'T'],
705
- [13, '2013-05-29', 'S', 13_459.00, 5659.51, 24.7464, 'ZMEAC', 'T'],
706
- [14, '2013-05-29', 'S', 15_700.00, 6601.85, 24.7790, 'ZMEAC', 'F'],
707
- [15, '2013-05-29', 'S', 15_900.00, 6685.95, 24.5802, 'ZMEAC', 'T'],
708
- [16, '2013-05-30', 'S', 6_679.00, 2808.52, 25.0471, 'ZMEAC', 'T']]
709
- tab = Table.from_aoa(aoa).order_by(:date, :code)
710
- tab2 = tab.where('@row > 10')
711
- expect(tab2.rows.size).to eq(2)
712
- tab2 = tab.where('@group == 3')
713
- expect(tab2.rows.size).to eq(3)
714
- end
715
- end
716
-
717
- describe 'group_by' do
718
- it 'should be able to group by equal columns' do
719
- tab1 = Table.from_csv_string(@csv_file_body)
720
- tab2 = tab1.group_by(:date, :code, shares: :sum, ref: :first)
721
- expect(tab2.headers).to eq([:date, :code, :sum_shares, :first_ref,
722
- :first_rawshares, :first_price, :first_info])
723
- end
724
- end
725
-
726
- describe 'join' do
727
- # These tests are taken from https://www.tutorialspoint.com/postgresql/postgresql_using_joins.htm
728
- before :all do
729
- @tab_a = Table.from_aoh([
730
- { id: 1, name: 'Paul', age: 32, address: 'California', salary: 20000, join_date: '2001-07-13' },
731
- { id: 3, name: 'Teddy', age: 23, address: 'Norway', salary: 20000},
732
- { id: 4, name: 'Mark', age: 25, address: 'Rich-Mond', salary: 65000, join_date: '2007-12-13' },
733
- { id: 5, name: 'David', age: 27, address: 'Texas', salary: 85000, join_date: '2007-12-13' },
734
- { id: 2, name: 'Allen', age: 25, address: 'Texas', salary: nil, join_date: '2007-12-13' },
735
- { id: 8, name: 'Paul', age: 24, address: 'Houston', salary: 20000, join_date: '2005-07-13' },
736
- { id: 9, name: 'James', age: 44, address: 'Norway', salary: 5000, join_date: '2005-07-13' },
737
- { id: 10, name: 'James', age: 45, address: 'Texas', salary: 5000, join_date: '2005-07-13' }
738
- ])
739
- @tab_b = Table.from_aoh([
740
- { id: 1, dept: 'IT Billing', emp_id: 1 },
741
- { id: 2, dept: 'Engineering', emp_id: 2 },
742
- { id: 3, dept: 'Finance', emp_id: 7 }
743
- ])
744
- end
745
-
746
- it 'should be able to do an inner join' do
747
- join_tab = @tab_a.join(@tab_b, :id_a, :emp_id_b)
748
- expect(join_tab.class).to eq Table
749
- expect(join_tab.size).to eq(2)
750
- expect(join_tab[:name]).to include('Paul')
751
- expect(join_tab[:name]).to include('Allen')
752
- expect(join_tab.headers).to eq([:id, :name, :age, :address, :salary,
753
- :join_date, :id_b, :dept])
754
- end
755
-
756
- it 'should be able to do an inner join on a string exp' do
757
- join_tab = @tab_a.join(@tab_b, 'id_a == emp_id_b')
758
- expect(join_tab.class).to eq Table
759
- expect(join_tab.size).to eq(2)
760
- expect(join_tab[:name]).to include('Paul')
761
- expect(join_tab[:name]).to include('Allen')
762
- expect(join_tab.headers).to eq([:id, :name, :age, :address, :salary,
763
- :join_date, :id_b, :dept, :emp_id])
764
- end
765
-
766
- it 'should be able to do a left join' do
767
- join_tab = @tab_a.left_join(@tab_b, :id_a, :emp_id_b)
768
- expect(join_tab.class).to eq Table
769
- expect(join_tab.size).to eq(8)
770
- expect(join_tab[:name]).to include('Paul')
771
- expect(join_tab[:name]).to include('Allen')
772
- expect(join_tab[:name]).to include('Teddy')
773
- expect(join_tab[:name]).to include('Mark')
774
- expect(join_tab[:name]).to include('David')
775
- expect(join_tab[:name]).to include('James')
776
- expect(join_tab.headers).to eq([:id, :name, :age, :address, :salary,
777
- :join_date, :id_b, :dept, :emp_id])
778
- end
779
-
780
- it 'should be able to do a right join' do
781
- join_tab = @tab_a.right_join(@tab_b, :id_a, :emp_id_b)
782
- expect(join_tab.class).to eq Table
783
- expect(join_tab.size).to eq(3)
784
- expect(join_tab[:name]).to include('Paul')
785
- expect(join_tab[:name]).to include('Allen')
786
- expect(join_tab[:dept]).to include('IT Billing')
787
- expect(join_tab[:dept]).to include('Engineering')
788
- expect(join_tab[:dept]).to include('Finance')
789
- expect(join_tab.headers).to eq([:id, :name, :age, :address, :salary,
790
- :join_date, :id_b, :dept, :emp_id])
791
- end
792
-
793
- it 'should be able to do a full join' do
794
- join_tab = @tab_a.full_join(@tab_b, :id_a, :emp_id_b)
795
- expect(join_tab.class).to eq Table
796
- expect(join_tab.size).to eq(9)
797
- expect(join_tab[:name]).to include('Paul')
798
- expect(join_tab[:name]).to include('Allen')
799
- expect(join_tab[:name]).to include('Teddy')
800
- expect(join_tab[:name]).to include('Mark')
801
- expect(join_tab[:name]).to include('David')
802
- expect(join_tab[:name]).to include('James')
803
- expect(join_tab[:dept]).to include('IT Billing')
804
- expect(join_tab[:dept]).to include('Engineering')
805
- expect(join_tab[:dept]).to include('Finance')
806
- expect(join_tab.headers).to eq([:id, :name, :age, :address, :salary,
807
- :join_date, :id_b, :dept, :emp_id])
808
- end
809
-
810
- it 'should be able to do a cross join' do
811
- join_tab = @tab_a.cross_join(@tab_b)
812
- expect(join_tab.class).to eq Table
813
- expect(join_tab.size).to eq(24)
814
- expect(join_tab[:name]).to include('Paul')
815
- expect(join_tab[:name]).to include('Allen')
816
- expect(join_tab[:name]).to include('Teddy')
817
- expect(join_tab[:name]).to include('Mark')
818
- expect(join_tab[:name]).to include('David')
819
- expect(join_tab[:name]).to include('James')
820
- expect(join_tab[:dept]).to include('IT Billing')
821
- expect(join_tab[:dept]).to include('Engineering')
822
- expect(join_tab[:dept]).to include('Finance')
823
- expect(join_tab.headers).to eq([:id, :name, :age, :address, :salary,
824
- :join_date, :id_b, :dept, :emp_id])
825
- end
826
- end
827
-
828
- describe 'group boundaries' do
829
- before :all do
830
- @tab_a = Table.from_aoh([
831
- { id: 1, name: 'Paul', age: 32, address: 'California', salary: 20000, join_date: '2001-07-13' },
832
- { id: 3, name: 'Teddy', age: 23, address: 'Norway', salary: 20000},
833
- { id: 4, name: 'Mark', age: 25, address: 'Rich-Mond', salary: 65000, join_date: '2007-12-13' },
834
- { id: 5, name: 'David', age: 27, address: 'Texas', salary: 85000, join_date: '2007-12-13' },
835
- { id: 2, name: 'Allen', age: 25, address: 'Texas', salary: nil, join_date: '2007-12-13' },
836
- { id: 8, name: 'Paul', age: 24, address: 'Houston', salary: 20000, join_date: '2005-07-13' },
837
- { id: 9, name: 'James', age: 44, address: 'Norway', salary: 5000, join_date: '2005-07-13' },
838
- { id: 10, name: 'James', age: 45, address: 'Texas', salary: 5000, join_date: '2005-07-13' }
839
- ])
840
- # Union compatible with tab_a
841
- @tab_a1 = Table.from_aoh([
842
- { id: 21, name: 'Paula', age: 23, address: 'Kansas', salary: 20000, join_date: '2001-07-13' },
843
- { id: 23, name: 'Jenny', age: 32, address: 'Missouri', salary: 20000},
844
- { id: 24, name: 'Forrest', age: 52, address: 'Richmond', salary: 65000, join_date: '2007-12-13' },
845
- { id: 25, name: 'Syrano', age: 72, address: 'Nebraska', salary: 85000, join_date: '2007-12-13' },
846
- # Next four are the same as row as in @tab_a
847
- { id: 2, name: 'Allen', age: 25, address: 'Texas', salary: nil, join_date: '2007-12-13' },
848
- { id: 8, name: 'Paul', age: 24, address: 'Houston', salary: 20000, join_date: '2005-07-13' },
849
- { id: 9, name: 'James', age: 44, address: 'Norway', salary: 5000, join_date: '2005-07-13' },
850
- { id: 10, name: 'James', age: 45, address: 'Texas', salary: 5000, join_date: '2005-07-13' },
851
- { id: 22, name: 'Paula', age: 52, address: 'Iowa', salary: nil, join_date: '2007-12-13' },
852
- { id: 28, name: 'Paula', age: 42, address: 'Oklahoma', salary: 20000, join_date: '2005-07-13' },
853
- { id: 29, name: 'Patrick', age: 44, address: 'Lindsbourg', salary: 5000, join_date: '2005-07-13' },
854
- { id: 30, name: 'James', age: 54, address: 'Ottawa', salary: 5000, join_date: '2005-07-13' }
855
- ])
856
- @tab_b = Table.from_aoh([
857
- { id: 1, dept: 'IT Billing', emp_id: 1 },
858
- { id: 2, dept: 'Engineering', emp_id: 2 },
859
- { id: 3, dept: 'Finance', emp_id: 7 }
860
- ])
861
- @aoa =
862
- [['Ref', 'Date', 'Code', 'Raw', 'Shares', 'Price', 'Info', 'Bool'],
863
- nil,
864
- [1, '2013-05-02', 'P', 795_546.20, 795_546.2, 1.1850, 'ZMPEF1', 'T'],
865
- nil,
866
- [2, '2013-05-02', 'P', 118_186.40, 118_186.4, 11.8500, 'ZMPEF1', 'T'],
867
- [7, '2013-05-20', 'S', 12_000.00, 5046.00, 28.2804, 'ZMEAC', 'F'],
868
- [8, '2013-05-20', 'S', 85_000.00, 35_742.50, 28.3224, 'ZMEAC', 'T'],
869
- nil,
870
- [9, '2013-05-20', 'S', 33_302.00, 14_003.49, 28.6383, 'ZMEAC', 'T'],
871
- [10, '2013-05-23', 'S', 8000.00, 3364.00, 27.1083, 'ZMEAC', 'T'],
872
- [11, '2013-05-23', 'S', 23_054.00, 9694.21, 26.8015, 'ZMEAC', 'F'],
873
- [12, '2013-05-23', 'S', 39_906.00, 16_780.47, 25.1749, 'ZMEAC', 'T'],
874
- [13, '2013-05-29', 'S', 13_459.00, 5659.51, 24.7464, 'ZMEAC', 'T'],
875
- [14, '2013-05-29', 'S', 15_700.00, 6601.85, 24.7790, 'ZMEAC', 'F'],
876
- [15, '2013-05-29', 'S', 15_900.00, 6685.95, 24.5802, 'ZMEAC', 'T'],
877
- nil,
878
- [16, '2013-05-30', 'S', 6_679.00, 2808.52, 25.0471, 'ZMEAC', 'T']]
879
- @aoh = [
880
- { id: 1, name: 'Paul', age: 32, address: 'California', salary: 20000, join_date: '2001-07-13' },
881
- nil,
882
- { id: 3, name: 'Teddy', age: 23, address: 'Norway', salary: 20000},
883
- { id: 4, name: 'Mark', age: 25, address: 'Rich-Mond', salary: 65000, join_date: '2007-12-13' },
884
- { id: 5, name: 'David', age: 27, address: 'Texas', salary: 85000, join_date: '2007-12-13' },
885
- nil,
886
- { id: 2, name: 'Allen', age: 25, address: 'Texas', salary: nil, join_date: '2007-12-13' },
887
- { id: 8, name: 'Paul', age: 24, address: 'Houston', salary: 20000, join_date: '2005-07-13' },
888
- { id: 9, name: 'James', age: 44, address: 'Norway', salary: 5000, join_date: '2005-07-13' },
889
- nil,
890
- { id: 10, name: 'James', age: 45, address: 'Texas', salary: 5000, join_date: '2005-07-13' }
891
- ]
892
- end
893
-
894
- it 'an empty table should have no groups' do
895
- expect(Table.new.groups.size).to eq(0)
896
- end
897
-
898
- it 'default group boundaries of whole table' do
899
- expect(@tab_a.groups.size).to eq(1)
900
- end
901
-
902
- it 'add group boundaries on reading from org text' do
903
- tab = Table.from_org_string(@org_file_body_with_groups)
904
- expect(tab.groups.size).to eq(4)
905
- expect(tab.groups[0].size).to eq(1)
906
- expect(tab.groups[1].size).to eq(3)
907
- expect(tab.groups[2].size).to eq(7)
908
- expect(tab.groups[3].size).to eq(3)
909
- end
910
-
911
- it 'add group boundaries on reading from aoa' do
912
- tab = Table.from_aoa(@aoa)
913
- expect(tab.groups.size).to eq(4)
914
- expect(tab.groups[0].size).to eq(1)
915
- expect(tab.groups[1].size).to eq(3)
916
- expect(tab.groups[2].size).to eq(7)
917
- expect(tab.groups[3].size).to eq(1)
918
- end
919
-
920
- it 'add group boundaries on reading from aoh' do
921
- tab = Table.from_aoh(@aoh)
922
- expect(tab.groups.size).to eq(4)
923
- expect(tab.groups[0].size).to eq(1)
924
- expect(tab.groups[1].size).to eq(3)
925
- expect(tab.groups[2].size).to eq(3)
926
- expect(tab.groups[3].size).to eq(1)
927
- end
928
-
929
- it 'add group boundaries on order_by' do
930
- tab = @tab_a.order_by(:name)
931
- # Now the table is ordered by name, and the names are: Allen, David,
932
- # James, James, Mark, Paul, Paul, Teddy. So there are groups of size 1,
933
- # 1, 2, 1, 2, and 1. Six groups in all.
934
- expect(tab.groups.size).to eq(6)
935
- expect(tab.groups[0].size).to eq(1)
936
- expect(tab.groups[1].size).to eq(1)
937
- expect(tab.groups[2].size).to eq(2)
938
- tab.groups[2].each do |row|
939
- expect(row[:name]).to eq('James')
940
- end
941
- expect(tab.groups[3].size).to eq(1)
942
- expect(tab.groups[4].size).to eq(2)
943
- tab.groups[4].each do |row|
944
- expect(row[:name]).to eq('Paul')
945
- end
946
- expect(tab.groups[5].size).to eq(1)
947
- end
948
-
949
- it 'add group boundaries on union_all' do
950
- tab = @tab_a.union_all(@tab_a1)
951
- expect(tab.size).to eq(20)
952
- expect(tab.groups.size).to eq(2)
953
- expect(tab.groups[0].size).to eq(8)
954
- expect(tab.groups[1].size).to eq(12)
955
- end
956
-
957
- it 'inherit group boundaries on union_all' do
958
- tab1 = @tab_a.order_by(:name)
959
- tab2 = @tab_a1.order_by(:name)
960
- tab = tab1.union_all(tab2)
961
- expect(tab.size).to eq(20)
962
- expect(tab.groups.size).to eq(tab1.groups.size + tab2.groups.size)
963
- tab.groups.each do |grp|
964
- names = grp.map {|r| r[:name]}
965
- expect(names.uniq.size).to eq(1)
966
- end
967
- end
968
-
969
- it 'inherit group boundaries on select' do
970
- tab = @tab_a.order_by(:name).select(:name, :age, :join_date)
971
- # Now the table is ordered by name, and the names are: Allen, David,
972
- # James, James, Mark, Paul, Paul, Teddy. So there are groups of size 1,
973
- # 1, 2, 1, 2, and 1. Six groups in all.
974
- expect(tab.groups.size).to eq(6)
975
- expect(tab.groups[0].size).to eq(1)
976
- expect(tab.groups[1].size).to eq(1)
977
- expect(tab.groups[2].size).to eq(2)
978
- tab.groups[2].each do |row|
979
- expect(row[:name]).to eq('James')
980
- end
981
- expect(tab.groups[3].size).to eq(1)
982
- expect(tab.groups[4].size).to eq(2)
983
- tab.groups[4].each do |row|
984
- expect(row[:name]).to eq('Paul')
985
- end
986
- expect(tab.groups[5].size).to eq(1)
987
- end
988
- end
989
- end
990
- end