mdarray-jcsv 0.6.3-java

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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +23 -0
  3. data/README.md +2 -0
  4. data/Rakefile +46 -0
  5. data/config.rb +104 -0
  6. data/lib/constraints.rb +205 -0
  7. data/lib/date_filters.rb +252 -0
  8. data/lib/dimensions.rb +276 -0
  9. data/lib/filters.rb +332 -0
  10. data/lib/jcsv.rb +107 -0
  11. data/lib/list_reader.rb +200 -0
  12. data/lib/locale.rb +192 -0
  13. data/lib/map_reader.rb +192 -0
  14. data/lib/mdarray-jcsv.rb +24 -0
  15. data/lib/mdarray_reader.rb +110 -0
  16. data/lib/numeric_filters.rb +225 -0
  17. data/lib/reader.rb +547 -0
  18. data/lib/supercsv_interface.rb +231 -0
  19. data/test/test_complete.rb +37 -0
  20. data/test/test_critbit.rb +442 -0
  21. data/test/test_customer_list.rb +436 -0
  22. data/test/test_customer_map.rb +209 -0
  23. data/test/test_customer_nhlist.rb +161 -0
  24. data/test/test_deep_map.rb +264 -0
  25. data/test/test_del.rb +73 -0
  26. data/test/test_dimensions.rb +231 -0
  27. data/test/test_example.rb +79 -0
  28. data/test/test_filters.rb +374 -0
  29. data/test/test_list_dimensions.rb +110 -0
  30. data/test/test_mdarray.rb +227 -0
  31. data/test/test_missing_data.rb +57 -0
  32. data/vendor/commons-beanutils-1.8.3.jar +0 -0
  33. data/vendor/commons-lang3-3.1.jar +0 -0
  34. data/vendor/dozer-5.4.0.jar +0 -0
  35. data/vendor/jcl-over-slf4j-1.6.6.jar +0 -0
  36. data/vendor/joda-time-2.7.jar +0 -0
  37. data/vendor/slf4j-api-1.7.5.jar +0 -0
  38. data/vendor/snakeyaml-1.14.jar +0 -0
  39. data/vendor/super-csv-2.4.0.jar +0 -0
  40. data/vendor/super-csv-dozer-2.4.0.jar +0 -0
  41. data/vendor/super-csv-java8-2.4.0.jar +0 -0
  42. data/vendor/super-csv-joda-2.4.0.jar +0 -0
  43. data/version.rb +2 -0
  44. metadata +196 -0
@@ -0,0 +1,436 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ##########################################################################################
4
+ # Copyright © 2015 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
5
+ # and distribute this software and its documentation for educational, research, and
6
+ # not-for-profit purposes, without fee and without a signed licensing agreement, is hereby
7
+ # granted, provided that the above copyright notice, this paragraph and the following two
8
+ # paragraphs appear in all copies, modifications, and distributions. Contact Rodrigo
9
+ # Botafogo - rodrigo.a.botafogo@gmail.com for commercial licensing opportunities.
10
+ #
11
+ # IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
12
+ # INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
13
+ # THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
14
+ # POSSIBILITY OF SUCH DAMAGE.
15
+ #
16
+ # RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
18
+ # SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
19
+ # RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
20
+ # OR MODIFICATIONS.
21
+ ##########################################################################################
22
+
23
+ require 'rubygems'
24
+ require 'test/unit'
25
+ require 'shoulda'
26
+
27
+ require_relative '../config'
28
+ require 'jcsv'
29
+
30
+ class CSVTest < Test::Unit::TestCase
31
+
32
+ context "CSV test" do
33
+
34
+ setup do
35
+
36
+ end
37
+
38
+ #=begin
39
+ #-------------------------------------------------------------------------------------
40
+ #
41
+ #-------------------------------------------------------------------------------------
42
+
43
+ should "parse a csv file the quick way with headers" do
44
+
45
+ # Reads all rows in memory and return and array of arrays. Each line is stored in
46
+ # one array. Data is stored in the 'rows' instance variable.
47
+ # Create the reader with all default parameters. Headers are converted from string
48
+ # to symbol
49
+ reader = Jcsv.reader("../data/customer.csv")
50
+
51
+ # now read the whole csv file
52
+ content = reader.read
53
+
54
+ # Headers are converted to symbol
55
+ assert_equal([:customer_no, :first_name, :last_name, :birth_date, :mailing_address,
56
+ :married, :number_of_kids, :favourite_quote, :email, :loyalty_points],
57
+ reader.headers)
58
+
59
+ assert_equal(["1", "John", "Dunbar", "13/06/1945",
60
+ "1600 Amphitheatre Parkway\nMountain View, CA 94043\nUnited States",
61
+ nil, nil, "\"May the Force be with you.\" - Star Wars",
62
+ "jdunbar@gmail.com", "0"], content[0])
63
+
64
+ end
65
+
66
+ #-------------------------------------------------------------------------------------
67
+ #
68
+ #-------------------------------------------------------------------------------------
69
+
70
+ should "leave headers as string" do
71
+
72
+ # Reads all rows in memory and return and array of arrays. Each line is stored in
73
+ # one array. Data is stored in the 'rows' instance variable.
74
+ # Headers are kept as strings instead of symbol
75
+ reader = Jcsv.reader("../data/customer.csv", strings_as_keys: true)
76
+
77
+ # now read the whole csv file
78
+ content = reader.read
79
+
80
+ assert_equal(["customerNo", "firstName", "lastName", "birthDate", "mailingAddress",
81
+ "married", "numberOfKids", "favouriteQuote", "email", "loyaltyPoints"],
82
+ reader.headers)
83
+
84
+ end
85
+
86
+ #-------------------------------------------------------------------------------------
87
+ #
88
+ #-------------------------------------------------------------------------------------
89
+
90
+ should "parse a csv file passing a block" do
91
+
92
+ # read lines and pass them to a block for processing. The block receives the
93
+ # line_no (last line of the record), row_no, row and the headers. If has_haders is
94
+ # false, then headers will be nil. Instead of
95
+ # method foreach, one could also use method 'read' with a block. 'read' and
96
+ # 'foreach' are identical.
97
+ reader = Jcsv.reader("../data/customer.csv", headers: true, strings_as_keys: true)
98
+
99
+ reader.read do |line_no, row_no, row, headers|
100
+ assert_equal(4, line_no) if row_no == 2
101
+ assert_equal(7, line_no) if row_no == 3
102
+ assert_equal(10, line_no) if row_no == 4
103
+ assert_equal(13, line_no) if row_no == 5
104
+
105
+ assert_equal(["customerNo", "firstName", "lastName", "birthDate",
106
+ "mailingAddress", "married", "numberOfKids", "favouriteQuote",
107
+ "email", "loyaltyPoints"], headers)
108
+
109
+ # Since the file has a header, the third record is row_no = 4
110
+ assert_equal(["3", "Alice", "Wunderland",
111
+ "08/08/1985", "One Microsoft Way\nRedmond, WA 98052-6399\nUnited States",
112
+ "Y", "0", "\"Play it, Sam. Play \"As Time Goes By.\"\" - Casablanca",
113
+ "throughthelookingglass@yahoo.com", "2255887799"], row) if row_no == 4
114
+ end
115
+
116
+ end
117
+
118
+ #-------------------------------------------------------------------------------------
119
+ #
120
+ #-------------------------------------------------------------------------------------
121
+
122
+ should "parse a csv file with filters" do
123
+
124
+ # Add filters, to filter the columns according to given rules. numberOfKids is
125
+ # optional and should be converted to and int. married is optional and should be
126
+ # converted to a boolean
127
+ parser = Jcsv.reader("../data/customer.csv", default_filter: Jcsv.not_nil)
128
+
129
+ # Add filters, so that we get 'objects' instead of strings for filtered fields
130
+ parser.filters = {:number_of_kids => Jcsv.optional >> Jcsv.int,
131
+ :married => Jcsv.optional >> Jcsv.bool,
132
+ :customer_no => Jcsv.int,
133
+ :birth_date => Jcsv.date("dd/MM/yyyy")}
134
+
135
+ parser.read do |line_no, row_no, row, headers|
136
+
137
+ # First field is customer number, which is converted to int
138
+ assert_equal(1, row[0]) if row_no == 2
139
+ assert_equal("John", row[1]) if row_no == 2
140
+ # Field 5 is :married. It is optional, so leaving it blank (nil) is ok.
141
+ assert_equal(nil, row[5]) if row_no == 2
142
+
143
+ # notice that field married that was "Y" is now true. Number of kids is not "0",
144
+ # but 0, customerNo is also and int
145
+ assert_equal(true, row[5]) if row_no == 3
146
+
147
+ end
148
+
149
+ end
150
+
151
+ #-------------------------------------------------------------------------------------
152
+ #
153
+ #-------------------------------------------------------------------------------------
154
+
155
+ should "Read file in chunks passing a block" do
156
+
157
+ # Read chunks of the file. In this case, we are breaking the file in chunks of 2
158
+ reader = Jcsv.reader("../data/customer.csv", chunk_size: 2)
159
+
160
+ # Add filters, so that we get 'objects' instead of strings for filtered fields
161
+ reader.filters = {:number_of_kids => Jcsv.optional >> Jcsv.int,
162
+ :married => Jcsv.optional >> Jcsv.bool,
163
+ :customer_no => Jcsv.int}
164
+
165
+ reader.each do |line_no, row_no, chunk, headers|
166
+ # line_no and row_no are the last read line_no and row_no of the chunk. Since we
167
+ # have headers and are reading in chunks of two, the first chunk has row_no = 3
168
+ assert_equal([[1, "John", "Dunbar", "13/06/1945",
169
+ "1600 Amphitheatre Parkway\nMountain View, CA 94043\nUnited States",
170
+ nil, nil, "\"May the Force be with you.\" - Star Wars",
171
+ "jdunbar@gmail.com", "0"],
172
+ [2, "Bob", "Down", "25/02/1919",
173
+ "1601 Willow Rd.\nMenlo Park, CA 94025\nUnited States",
174
+ true, 0, "\"Frankly, my dear, I don't give a damn.\" - Gone With The Wind",
175
+ "bobdown@hotmail.com", "123456"]], chunk) if row_no == 3
176
+ end
177
+
178
+ end
179
+
180
+
181
+ #-------------------------------------------------------------------------------------
182
+ #
183
+ #-------------------------------------------------------------------------------------
184
+
185
+ should "Read file in chunks, last chunk smaller" do
186
+
187
+ # Read chunks of the file. In this case, we are breaking the file in chunks of 3.
188
+ # Since we only have 4 rows, the first chunk will have 3 rows and the second chunk
189
+ # will have 1 row
190
+ reader = Jcsv.reader("../data/customer.csv", chunk_size: 3)
191
+
192
+ enum = reader.each do |line_no, row_no, chunk, headers|
193
+ assert_equal([["1", "John", "Dunbar", "13/06/1945",
194
+ "1600 Amphitheatre Parkway\nMountain View, CA 94043\nUnited States",
195
+ nil, nil,
196
+ "\"May the Force be with you.\" - Star Wars", "jdunbar@gmail.com", "0"],
197
+ ["2", "Bob", "Down", "25/02/1919",
198
+ "1601 Willow Rd.\nMenlo Park, CA 94025\nUnited States",
199
+ "Y", "0", "\"Frankly, my dear, I don't give a damn.\" - Gone With The Wind",
200
+ "bobdown@hotmail.com", "123456"],
201
+ ["3", "Alice", "Wunderland", "08/08/1985",
202
+ "One Microsoft Way\nRedmond, WA 98052-6399\nUnited States", "Y", "0",
203
+ "\"Play it, Sam. Play \"As Time Goes By.\"\" - Casablanca",
204
+ "throughthelookingglass@yahoo.com", "2255887799"]], chunk) if row_no == 4
205
+
206
+ assert_equal([["4", "Bill", "Jobs", "10/07/1973",
207
+ "2701 San Tomas Expressway\nSanta Clara, CA 95050\nUnited States", "Y", "3",
208
+ "\"You've got to ask yourself one question: \"Do I feel lucky?\" Well, do ya, punk?\" - Dirty Harry",
209
+ "billy34@hotmail.com", "36"]], chunk) if row_no == 5
210
+
211
+ end
212
+
213
+ end
214
+
215
+ #-------------------------------------------------------------------------------------
216
+ #
217
+ #-------------------------------------------------------------------------------------
218
+
219
+ should "Read file in one big chunk" do
220
+
221
+ p "TODO: add some test cases... no need to go into the tutorial."
222
+
223
+ # Read chunks of the file. In this case, we are breaking the file in chunks of 2
224
+ reader = Jcsv.reader("../data/customer.csv", chunk_size: :all)
225
+
226
+ # Add filters, so that we get 'objects' instead of strings for filtered fields
227
+ reader.filters = {:number_of_kids => Jcsv.optional >> Jcsv.int,
228
+ :married => Jcsv.optional >> Jcsv.bool,
229
+ :customer_no => Jcsv.int}
230
+ end
231
+
232
+ #-------------------------------------------------------------------------------------
233
+ #
234
+ #-------------------------------------------------------------------------------------
235
+
236
+ should "Read file in chunks as enumerator" do
237
+
238
+ reader = Jcsv.reader("../data/customer.csv", chunk_size: 2)
239
+
240
+ # Add filters, so that we get 'objects' instead of strings for filtered fields
241
+ reader.filters = {:number_of_kids => Jcsv.optional >> Jcsv.int,
242
+ :married => Jcsv.optional >> Jcsv.bool,
243
+ :customer_no => Jcsv.int}
244
+
245
+ # Method each without a block returns an enumerator
246
+ enum = reader.each
247
+
248
+ # read the first chunk. Chunk is of size 2
249
+ chunk = enum.next
250
+
251
+ assert_equal(7, chunk[0])
252
+ assert_equal(3, chunk[1])
253
+ assert_equal([[1, "John", "Dunbar", "13/06/1945",
254
+ "1600 Amphitheatre Parkway\nMountain View, CA 94043\nUnited States", nil, nil,
255
+ "\"May the Force be with you.\" - Star Wars", "jdunbar@gmail.com", "0"],
256
+ [2, "Bob", "Down", "25/02/1919",
257
+ "1601 Willow Rd.\nMenlo Park, CA 94025\nUnited States",
258
+ true, 0, "\"Frankly, my dear, I don't give a damn.\" - Gone With The Wind",
259
+ "bobdown@hotmail.com", "123456"]], chunk[2])
260
+
261
+ # read second chunk
262
+ c = enum.next
263
+
264
+ # trying to read another chunk will raise StopIteration
265
+ assert_raise ( StopIteration ) { enum.next }
266
+
267
+ end
268
+
269
+ #-------------------------------------------------------------------------------------
270
+ #
271
+ #-------------------------------------------------------------------------------------
272
+
273
+ should "Read file in chunks as enumerator... last chunk smaller" do
274
+
275
+ # Same test with a chunk_size of 3
276
+ reader = Jcsv.reader("../data/customer.csv", chunk_size: 3)
277
+
278
+ # Method each without a block returns an enumerator
279
+ enum = reader.each
280
+
281
+ # read first chunk. Does nothing with the data.
282
+ enum.next
283
+
284
+
285
+ # read second chunk... only one row will be returned
286
+ chunk = enum.next
287
+
288
+ # assert_equal()
289
+ assert_equal([["4", "Bill", "Jobs", "10/07/1973",
290
+ "2701 San Tomas Expressway\nSanta Clara, CA 95050\nUnited States", "Y", "3",
291
+ "\"You've got to ask yourself one question: \"Do I feel lucky?\" Well, do ya, punk?\" - Dirty Harry",
292
+ "billy34@hotmail.com", "36"]], chunk[2])
293
+
294
+ # trying to read another chunk will raise StopIteration
295
+ assert_raise ( StopIteration ) { enum.next }
296
+
297
+ end
298
+
299
+ #-------------------------------------------------------------------------------------
300
+ #
301
+ #-------------------------------------------------------------------------------------
302
+
303
+ should "Read file skipping columns" do
304
+
305
+ reader = Jcsv.reader("../data/customer.csv")
306
+
307
+ # Add mapping. When column is mapped to false, it will not be retrieved from the
308
+ # file, improving time and speed efficiency
309
+ reader.mapping = {:customer_no => false, :number_of_kids => false,
310
+ :loyalty_points => false}
311
+
312
+ reader.read do |line_no, row_no, chunk, headers|
313
+ assert_equal([:first_name, :last_name, :birth_date, :mailing_address, :married,
314
+ :favourite_quote, :email], headers)
315
+ if (row_no == 2)
316
+ assert_equal("John", chunk[0])
317
+ assert_equal("Dunbar", chunk[1])
318
+ end
319
+ end
320
+
321
+ end
322
+
323
+ #-------------------------------------------------------------------------------------
324
+ #
325
+ #-------------------------------------------------------------------------------------
326
+
327
+ should "Read file columns as labels" do
328
+
329
+ reader = Jcsv.reader("../data/customer.csv")
330
+
331
+ # mapping cannot be to true
332
+ assert_raise (RuntimeError) {
333
+ reader.mapping = {:customer_no => true, :number_of_kids => true,
334
+ :loyalty_points => true}}
335
+
336
+ end
337
+
338
+ #=end
339
+
340
+ #-------------------------------------------------------------------------------------
341
+ #
342
+ #-------------------------------------------------------------------------------------
343
+
344
+ should "Read file skipping columns, with headers as string" do
345
+
346
+ reader = Jcsv.reader("../data/customer.csv", strings_as_keys: true)
347
+
348
+ # Add mapping. When column is mapped to false, it will not be retrieved from the
349
+ # file, improving time and speed efficiency
350
+ reader.mapping = {"customerNo" => false, "numberOfKids" => false,
351
+ "loyaltyPoints" => false}
352
+
353
+ reader.read do |line_no, row_no, chunk, headers|
354
+ assert_equal(["firstName", "lastName", "birthDate", "mailingAddress", "married",
355
+ "favouriteQuote", "email"], headers)
356
+ if (row_no == 2)
357
+ assert_equal("John", chunk[0])
358
+ assert_equal("Dunbar", chunk[1])
359
+ end
360
+ end
361
+
362
+ end
363
+
364
+ #-------------------------------------------------------------------------------------
365
+ #
366
+ #-------------------------------------------------------------------------------------
367
+
368
+ should "Read file reordering columns" do
369
+
370
+ # Here we are setting headers to false, so the first line will not be considere
371
+ # a header.
372
+ reader = Jcsv.reader("../data/customer.csv", chunk_size: 2)
373
+ # reading the headers returns false
374
+ # assert_equal(false, reader.headers)
375
+
376
+ reader.filters = {:number_of_kids => Jcsv.optional >> Jcsv.int,
377
+ :married => Jcsv.optional >> Jcsv.bool,
378
+ :customer_no => Jcsv.int}
379
+
380
+ # Mapping allows reordering of columns. In this example, column 0 (:customerno)
381
+ # in the csv file will be loaded in position 2 (3rd column); column 1 (:firstname)
382
+ # in the csv file will be loaded in position 0 (1st column); column 2 on the csv file
383
+ # will not be loaded (false); column 4 (:birthdate) will be loaded on position 3,
384
+ # and so on.
385
+ # When reordering columns, care should be taken to get the mapping right or unexpected
386
+ # behaviour could result.
387
+ reader.mapping = {:customer_no => 2, :first_name => 0, :last_name => false,
388
+ :birth_date => 3, :mailing_address => false, :married => false,
389
+ :number_of_kids => false, :favourite_quote => false, :email => 1,
390
+ :loyalty_points => 4}
391
+
392
+ reader.read do |line_no, row_no, chunk, headers|
393
+ assert_equal([:first_name, :email, :customer_no, :birth_date, :loyalty_points],
394
+ headers)
395
+ assert_equal("John", chunk[0][0]) if row_no == 3
396
+ assert_equal("Alice", chunk[0][0]) if row_no == 5
397
+ end
398
+
399
+ end
400
+ =begin
401
+ #-------------------------------------------------------------------------------------
402
+ # JRuby fiber seems to have a bug. Don't know if only JRuby fiber or fibers in
403
+ # general. When returning the first element the second is also retrieved (look
404
+ # forward: might be a reason, but prevents changing the behaviour in between calls to
405
+ # next.
406
+ #-------------------------------------------------------------------------------------
407
+
408
+ should "allow changing parameters in between reads" do
409
+
410
+ p "testing fiber"
411
+
412
+ # Start with chunk_size 1
413
+ reader = Jcsv.reader("../data/customer.csv", headers: true, chunk_size: 1)
414
+
415
+ # Method each without a block returns an enumerator
416
+ enum = reader.each
417
+
418
+ # read first chunk. Does nothing with the data. Got only one line of data
419
+ p enum.next
420
+
421
+ # change chunk_size to 2
422
+ reader.chunk_size = 2
423
+
424
+ # read second chunk... only one row will be returned
425
+ chunk = enum.next
426
+ p chunk
427
+ # assert_equal()
428
+
429
+ p enum.next
430
+
431
+ end
432
+ =end
433
+ end
434
+
435
+ end
436
+
@@ -0,0 +1,209 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ##########################################################################################
4
+ # Copyright © 2015 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
5
+ # and distribute this software and its documentation for educational, research, and
6
+ # not-for-profit purposes, without fee and without a signed licensing agreement, is hereby
7
+ # granted, provided that the above copyright notice, this paragraph and the following two
8
+ # paragraphs appear in all copies, modifications, and distributions. Contact Rodrigo
9
+ # Botafogo - rodrigo.a.botafogo@gmail.com for commercial licensing opportunities.
10
+ #
11
+ # IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
12
+ # INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
13
+ # THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
14
+ # POSSIBILITY OF SUCH DAMAGE.
15
+ #
16
+ # RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
18
+ # SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
19
+ # RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
20
+ # OR MODIFICATIONS.
21
+ ##########################################################################################
22
+
23
+ require 'rubygems'
24
+ require 'test/unit'
25
+ require 'shoulda'
26
+ require 'date'
27
+
28
+ require_relative '../config' if !@platform
29
+
30
+ require 'jcsv'
31
+
32
+ class CSVTest < Test::Unit::TestCase
33
+
34
+ context "CSV test" do
35
+
36
+ setup do
37
+
38
+ end
39
+
40
+ #-------------------------------------------------------------------------------------
41
+ #
42
+ #-------------------------------------------------------------------------------------
43
+
44
+ should "parse a csv file to map the quick way" do
45
+
46
+ reader = Jcsv.reader("../data/customer.csv", format: :map)
47
+ # map is an array of hashes
48
+ map = reader.read
49
+
50
+ # get customerNo of second row
51
+ assert_equal("2", map[1][:customer_no])
52
+ # loyaltyPoints from 4th row
53
+ assert_equal("36", map[3][:loyalty_points])
54
+
55
+ end
56
+
57
+ #-------------------------------------------------------------------------------------
58
+ #
59
+ #-------------------------------------------------------------------------------------
60
+
61
+ should "parse a csv file to map without filters nor mappings in chunks" do
62
+
63
+ # type is :map. Rows are hashes. Set the default filter to not_nil. That is, all
64
+ # fields are required unless explicitly set to optional.
65
+ reader = Jcsv.reader("../data/customer.csv", format: :map, chunk_size: 2,
66
+ strings_as_keys: true)
67
+
68
+ map = reader.read
69
+
70
+ # since chunk_size = 2, but we didn't pass a block to reader, we will get back
71
+ # 1 array, with 2 arrays each with a chunk. Every element of the internal arrays
72
+ # are maps (hashes)
73
+
74
+ # Bellow we are looking at the second chunk, element 0. Since our chunks are of
75
+ # size 2, the second chunk, element 0 is the third row.
76
+ assert_equal("2255887799", map[1][0]["loyaltyPoints"])
77
+
78
+ end
79
+
80
+ #-------------------------------------------------------------------------------------
81
+ #
82
+ #-------------------------------------------------------------------------------------
83
+
84
+ should "parse a csv file to map" do
85
+
86
+ # type is :map. Rows are hashes. Set the default filter to not_nil. That is, all
87
+ # fields are required unless explicitly set to optional.
88
+ reader = Jcsv.reader("../data/customer.csv", format: :map, default_filter: Jcsv.not_nil)
89
+
90
+ # Set numberOfKids and married as optional, otherwise an exception will be raised
91
+ reader.filters = {:number_of_kids => Jcsv.optional >> Jcsv.int,
92
+ :married => Jcsv.optional >> Jcsv.bool,
93
+ :loyalty_points => Jcsv.long,
94
+ :customer_no => Jcsv.int,
95
+ :birth_date => Jcsv.date("dd/MM/yyyy")}
96
+
97
+ # When parsing to map, it is possible to make a mapping. If column name is :false
98
+ # the column will be removed from the returned row
99
+ reader.mapping = {:number_of_kids => :numero_criancas,
100
+ :married => "casado",
101
+ :loyalty_points => "pontos fidelidade",
102
+ :customer_no => false}
103
+
104
+ reader.read do |line_no, row_no, row, headers|
105
+ if (row_no == 5)
106
+ assert_equal(nil, row[:customer_no])
107
+ assert_equal("Bill", row[:first_name])
108
+ assert_equal(true, row["casado"])
109
+ assert_equal("1973-07-10T00:00:00+00:00", row[:birth_date].to_s)
110
+ assert_equal("2701 San Tomas Expressway\nSanta Clara, CA 95050\nUnited States",
111
+ row[:mailing_address])
112
+ assert_equal(3, row[:numero_criancas])
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+
119
+ #-------------------------------------------------------------------------------------
120
+ #
121
+ #-------------------------------------------------------------------------------------
122
+
123
+ should "raise exception if no header when reading map" do
124
+
125
+ # Will raise an exception as reading a file as map requires the header
126
+ assert_raise ( Jcsv::MissingHeadersError ) {
127
+ Jcsv.reader("../data/customer.csv", format: :map, headers: false)
128
+ }
129
+
130
+ end
131
+
132
+ #-------------------------------------------------------------------------------------
133
+ #
134
+ #-------------------------------------------------------------------------------------
135
+
136
+ should "raise ConstraintViolation" do
137
+
138
+ reader = Jcsv.reader("../data/customer.csv", format: :map, default_filter: Jcsv.not_nil,
139
+ headers: true, strings_as_keys: true)
140
+
141
+ # Set numberOfKids and married as optional, otherwise an exception will be raised
142
+ reader.filters = {"numberOfKids" => Jcsv.optional >> Jcsv.int,
143
+ "loyaltyPoints" => Jcsv.long,
144
+ "customerNo" => Jcsv.int,
145
+ "birthDate" => Jcsv.date("dd/mm/yyyy")}
146
+
147
+ # reader.read { |line_no, row_no, row, headers| }
148
+ # Will raise an exception, as the default_filter is not_nil and there is a record
149
+ # in which field 'married' is nil
150
+ assert_raise ( Jcsv::ConstraintViolation ) {
151
+ reader.read { |line_no, row_no, row, headers| } }
152
+
153
+ end
154
+
155
+ #-------------------------------------------------------------------------------------
156
+ #
157
+ #-------------------------------------------------------------------------------------
158
+
159
+ should "catch FilterError" do
160
+
161
+ reader = Jcsv.reader("../data/customer.csv", format: :map, headers: true,
162
+ strings_as_keys: true)
163
+ # Set numberOfKids and married as optional, otherwise an exception will be raised
164
+ reader.filters = {"numberOfKids" => Jcsv.optional >> Jcsv.int,
165
+ "loyaltyPoints" => Jcsv.bool,
166
+ "customerNo" => Jcsv.int,
167
+ "birthDate" => Jcsv.date("dd/mm/yyyy")}
168
+
169
+ begin
170
+ reader.read do |line_no, row_no, row, headers|
171
+ p row
172
+ end
173
+ rescue Jcsv::FilterError => e
174
+ puts e.message
175
+ retry
176
+ end
177
+
178
+ end
179
+
180
+ #-------------------------------------------------------------------------------------
181
+ #
182
+ #-------------------------------------------------------------------------------------
183
+
184
+ should "Read file in chunks passing a block as iterator" do
185
+
186
+ # Read chunks of the file. In this case, we are breaking the file in chunks of two
187
+ reader = Jcsv.reader("../data/customer.csv", chunk_size: 2, format: :map,
188
+ strings_as_keys: true)
189
+
190
+ # Add filters, so that we get 'objects' instead of strings for filtered fields
191
+ reader.filters = {"numberOfKids" => Jcsv.optional >> Jcsv.int,
192
+ "married" => Jcsv.optional >> Jcsv.bool,
193
+ "customerNo" => Jcsv.int}
194
+
195
+ iter = reader.each
196
+ chunk1 = iter.next
197
+ # 3rd item in the chunk1 array is the data. 1st item is the line_no and 2nd item
198
+ # row_no. Chunks are of size 2, so chunk1[2][1] is the second element of the first
199
+ # chunk
200
+ assert_equal(2, chunk1[2][1]["customerNo"])
201
+ assert_equal("Down", chunk1[2][1]["lastName"])
202
+
203
+ chunk2 = iter.next
204
+
205
+ end
206
+
207
+ end
208
+
209
+ end