iostreams 1.11.0 → 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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -2
  3. data/Rakefile +7 -0
  4. data/lib/io_streams/builder.rb +9 -9
  5. data/lib/io_streams/bzip2/writer.rb +1 -1
  6. data/lib/io_streams/encode/reader.rb +2 -2
  7. data/lib/io_streams/encode/writer.rb +5 -5
  8. data/lib/io_streams/gzip/reader.rb +1 -1
  9. data/lib/io_streams/gzip/writer.rb +1 -1
  10. data/lib/io_streams/io_streams.rb +45 -19
  11. data/lib/io_streams/line/reader.rb +2 -2
  12. data/lib/io_streams/line/writer.rb +1 -1
  13. data/lib/io_streams/path.rb +2 -2
  14. data/lib/io_streams/paths/file.rb +10 -10
  15. data/lib/io_streams/paths/http.rb +80 -7
  16. data/lib/io_streams/paths/matcher.rb +3 -3
  17. data/lib/io_streams/paths/s3.rb +3 -3
  18. data/lib/io_streams/paths/sftp.rb +7 -8
  19. data/lib/io_streams/pgp/reader.rb +23 -10
  20. data/lib/io_streams/pgp/writer.rb +93 -32
  21. data/lib/io_streams/pgp.rb +188 -60
  22. data/lib/io_streams/reader.rb +4 -4
  23. data/lib/io_streams/record/reader.rb +3 -4
  24. data/lib/io_streams/record/writer.rb +3 -4
  25. data/lib/io_streams/row/reader.rb +1 -1
  26. data/lib/io_streams/row/writer.rb +1 -1
  27. data/lib/io_streams/stream.rb +36 -30
  28. data/lib/io_streams/symmetric_encryption/reader.rb +2 -2
  29. data/lib/io_streams/symmetric_encryption/writer.rb +4 -4
  30. data/lib/io_streams/tabular/header.rb +18 -6
  31. data/lib/io_streams/tabular/parser/array.rb +0 -10
  32. data/lib/io_streams/tabular/parser/csv.rb +6 -38
  33. data/lib/io_streams/tabular/parser/fixed.rb +5 -5
  34. data/lib/io_streams/tabular/parser/psv.rb +0 -12
  35. data/lib/io_streams/tabular.rb +5 -10
  36. data/lib/io_streams/utils.rb +3 -2
  37. data/lib/io_streams/version.rb +1 -1
  38. data/lib/io_streams/writer.rb +6 -6
  39. data/lib/io_streams/xlsx/reader.rb +1 -1
  40. data/lib/io_streams/zip/writer.rb +22 -10
  41. data/lib/iostreams.rb +0 -1
  42. metadata +28 -111
  43. data/lib/io_streams/deprecated.rb +0 -216
  44. data/lib/io_streams/tabular/utility/csv_row.rb +0 -105
  45. data/test/builder_test.rb +0 -311
  46. data/test/bzip2_reader_test.rb +0 -27
  47. data/test/bzip2_writer_test.rb +0 -56
  48. data/test/deprecated_test.rb +0 -121
  49. data/test/encode_reader_test.rb +0 -51
  50. data/test/encode_writer_test.rb +0 -90
  51. data/test/files/embedded_lines_test.csv +0 -7
  52. data/test/files/multiple_files.zip +0 -0
  53. data/test/files/spreadsheet.xlsx +0 -0
  54. data/test/files/test.csv +0 -4
  55. data/test/files/test.json +0 -3
  56. data/test/files/test.psv +0 -4
  57. data/test/files/text file.txt +0 -3
  58. data/test/files/text.txt +0 -3
  59. data/test/files/text.txt.bz2 +0 -0
  60. data/test/files/text.txt.gz +0 -0
  61. data/test/files/text.txt.gz.zip +0 -0
  62. data/test/files/text.zip +0 -0
  63. data/test/files/text.zip.gz +0 -0
  64. data/test/files/unclosed_quote_large_test.csv +0 -1658
  65. data/test/files/unclosed_quote_test.csv +0 -4
  66. data/test/files/unclosed_quote_test2.csv +0 -3
  67. data/test/gzip_reader_test.rb +0 -27
  68. data/test/gzip_writer_test.rb +0 -52
  69. data/test/io_streams_test.rb +0 -132
  70. data/test/line_reader_test.rb +0 -325
  71. data/test/line_writer_test.rb +0 -59
  72. data/test/minimal_file_reader.rb +0 -25
  73. data/test/path_test.rb +0 -55
  74. data/test/paths/file_test.rb +0 -213
  75. data/test/paths/http_test.rb +0 -34
  76. data/test/paths/matcher_test.rb +0 -120
  77. data/test/paths/s3_test.rb +0 -220
  78. data/test/paths/sftp_test.rb +0 -106
  79. data/test/pgp_reader_test.rb +0 -46
  80. data/test/pgp_test.rb +0 -267
  81. data/test/pgp_writer_test.rb +0 -130
  82. data/test/record_reader_test.rb +0 -60
  83. data/test/record_writer_test.rb +0 -82
  84. data/test/row_reader_test.rb +0 -35
  85. data/test/row_writer_test.rb +0 -56
  86. data/test/stream_test.rb +0 -577
  87. data/test/tabular_test.rb +0 -338
  88. data/test/test_helper.rb +0 -40
  89. data/test/utils_test.rb +0 -20
  90. data/test/xlsx_reader_test.rb +0 -37
  91. data/test/zip_reader_test.rb +0 -53
  92. data/test/zip_writer_test.rb +0 -48
data/test/stream_test.rb DELETED
@@ -1,577 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class StreamTest < Minitest::Test
4
- describe IOStreams::Stream do
5
- let :source_file_name do
6
- File.join(__dir__, "files", "text.txt")
7
- end
8
-
9
- let :data do
10
- File.read(source_file_name)
11
- end
12
-
13
- let :bad_data do
14
- [
15
- "New M\xE9xico,NE".b,
16
- "good line",
17
- "New M\xE9xico,\x07SF".b
18
- ].join("\n").encode("BINARY")
19
- end
20
-
21
- let :stripped_data do
22
- bad_data.gsub("\xE9".b, "").gsub("\x07", "")
23
- end
24
-
25
- let :multiple_zip_file_name do
26
- File.join(File.dirname(__FILE__), "files", "multiple_files.zip")
27
- end
28
-
29
- let :zip_gz_file_name do
30
- File.join(File.dirname(__FILE__), "files", "text.zip.gz")
31
- end
32
-
33
- let :contents_test_txt do
34
- File.read(File.join(File.dirname(__FILE__), "files", "text.txt"))
35
- end
36
-
37
- let :contents_test_json do
38
- File.read(File.join(File.dirname(__FILE__), "files", "test.json"))
39
- end
40
-
41
- let(:string_io) { StringIO.new(data) }
42
- let(:stream) { IOStreams::Stream.new(string_io) }
43
-
44
- describe ".reader" do
45
- it "reads a zip file" do
46
- File.open(multiple_zip_file_name, "rb") do |io|
47
- result = IOStreams::Stream.new(io).
48
- file_name(multiple_zip_file_name).
49
- option(:zip, entry_file_name: "test.json").
50
- read
51
- assert_equal contents_test_json, result
52
- end
53
- end
54
-
55
- it "reads a zip file from within a gz file" do
56
- File.open(zip_gz_file_name, "rb") do |io|
57
- result = IOStreams::Stream.new(io).
58
- file_name(zip_gz_file_name).
59
- read
60
- assert_equal contents_test_txt, result
61
- end
62
- end
63
- end
64
-
65
- describe ".line_reader" do
66
- end
67
-
68
- describe ".row_reader" do
69
- end
70
-
71
- describe ".record_reader" do
72
- end
73
-
74
- describe "#each(:line)" do
75
- it "returns a line at a time" do
76
- lines = []
77
- stream.stream(:none)
78
- count = stream.each(:line) { |line| lines << line }
79
- assert_equal data.lines.map(&:strip), lines
80
- assert_equal data.lines.count, count
81
- end
82
-
83
- it "strips non-printable characters" do
84
- input = StringIO.new(bad_data)
85
- lines = []
86
- stream = IOStreams::Stream.new(input)
87
- stream.stream(:encode, encoding: "UTF-8", cleaner: :printable, replace: "")
88
- count = stream.each(:line) { |line| lines << line }
89
- assert_equal stripped_data.lines.map(&:strip), lines
90
- assert_equal stripped_data.lines.count, count
91
- end
92
- end
93
-
94
- describe "#each(:array)" do
95
- describe "csv" do
96
- let :source_file_name do
97
- File.join(__dir__, "files", "test.csv")
98
- end
99
-
100
- let :expected_rows do
101
- rows = []
102
- CSV.open(source_file_name).each { |row| rows << row }
103
- rows
104
- end
105
-
106
- it "detects format from file_name" do
107
- output = []
108
- stream.file_name = source_file_name
109
- stream.each(:array) { |record| output << record }
110
- assert_equal expected_rows, output
111
- end
112
-
113
- it "honors format" do
114
- output = []
115
- stream.file_name = "blah"
116
- stream.format = :csv
117
- stream.each(:array) { |record| output << record }
118
- assert_equal expected_rows, output
119
- end
120
- end
121
-
122
- describe "psv" do
123
- let :source_file_name do
124
- File.join(__dir__, "files", "test.psv")
125
- end
126
-
127
- let :expected_rows do
128
- File.readlines(source_file_name).collect { |line| line.chomp.split("|") }
129
- end
130
-
131
- it "detects format from file_name" do
132
- output = []
133
- stream.file_name = source_file_name
134
- stream.each(:array) { |record| output << record }
135
- assert_equal expected_rows, output
136
- end
137
-
138
- it "honors format" do
139
- output = []
140
- stream.file_name = "blah"
141
- stream.format = :psv
142
- stream.each(:array) { |record| output << record }
143
- assert_equal expected_rows, output
144
- end
145
- end
146
-
147
- describe "json" do
148
- let :source_file_name do
149
- File.join(__dir__, "files", "test.json")
150
- end
151
-
152
- let :expected_rows do
153
- hash_rows = File.readlines(source_file_name).collect { |line| JSON.load(line) }
154
- rows = []
155
- rows << hash_rows.first.keys
156
- hash_rows.each { |hash| rows << hash.values }
157
- rows
158
- end
159
-
160
- it "detects format from file_name" do
161
- skip "TODO: Support reading json files as arrays"
162
- output = []
163
- stream.file_name = source_file_name
164
- stream.each(:array) { |record| output << record }
165
- assert_equal expected_rows, output
166
- end
167
-
168
- it "honors format" do
169
- skip "TODO: Support reading json files as arrays"
170
- output = []
171
- stream.file_name = "blah"
172
- stream.format = :json
173
- stream.each(:array) { |record| output << record }
174
- assert_equal expected_rows, output
175
- end
176
- end
177
- end
178
-
179
- describe ".each hash" do
180
- let :source_file_name do
181
- File.join(__dir__, "files", "test.json")
182
- end
183
-
184
- let :expected_json do
185
- File.readlines(source_file_name).collect { |line| JSON.load(line) }
186
- end
187
-
188
- it "detects format from file_name" do
189
- output = []
190
- stream.file_name = source_file_name
191
- stream.each(:hash) { |record| output << record }
192
- assert_equal expected_json, output
193
- end
194
-
195
- it "honors format" do
196
- output = []
197
- stream.file_name = "blah"
198
- stream.format = :json
199
- stream.each(:hash) { |record| output << record }
200
- assert_equal expected_json, output
201
- end
202
- end
203
-
204
- describe "#writer" do
205
- describe "#write" do
206
- it "one block" do
207
- io = StringIO.new
208
- IOStreams::Stream.new(io).writer do |stream|
209
- stream.write("Hello World")
210
- end
211
- assert_equal "Hello World", io.string
212
- end
213
-
214
- it "multiple blocks" do
215
- io = StringIO.new
216
- IOStreams::Stream.new(io).writer do |stream|
217
- stream.write("He")
218
- stream.write("l")
219
- stream.write("lo ")
220
- stream.write("World")
221
- end
222
- assert_equal "Hello World", io.string
223
- end
224
-
225
- it "empty blocks" do
226
- io = StringIO.new
227
- IOStreams::Stream.new(io).writer do |stream|
228
- stream.write("")
229
- stream.write("He")
230
- stream.write("")
231
- stream.write("l")
232
- stream.write("")
233
- stream.write("lo ")
234
- stream.write("World")
235
- stream.write("")
236
- end
237
- assert_equal "Hello World", io.string
238
- end
239
-
240
- it "nil blocks" do
241
- io = StringIO.new
242
- IOStreams::Stream.new(io).writer do |stream|
243
- stream.write(nil)
244
- stream.write("He")
245
- stream.write(nil)
246
- stream.write("l")
247
- stream.write(nil)
248
- stream.write("lo ")
249
- stream.write("World")
250
- stream.write(nil)
251
- end
252
- assert_equal "Hello World", io.string
253
- end
254
- end
255
-
256
- describe "#<<" do
257
- it "one block" do
258
- io = StringIO.new
259
- IOStreams::Stream.new(io).writer do |stream|
260
- stream << "Hello World"
261
- end
262
- assert_equal "Hello World", io.string
263
- end
264
-
265
- it "multiple blocks" do
266
- io = StringIO.new
267
- IOStreams::Stream.new(io).writer do |stream|
268
- stream << "He"
269
- stream << "l" << "lo " << "World"
270
- end
271
- assert_equal "Hello World", io.string
272
- end
273
-
274
- it "empty blocks" do
275
- io = StringIO.new
276
- IOStreams::Stream.new(io).writer do |stream|
277
- stream << ""
278
- stream << "He" << "" << "l" << ""
279
- stream << "lo " << "World"
280
- stream << ""
281
- end
282
- assert_equal "Hello World", io.string
283
- end
284
-
285
- it "nil blocks" do
286
- io = StringIO.new
287
- IOStreams::Stream.new(io).writer do |stream|
288
- stream << nil
289
- stream << "He" << nil << "l" << nil
290
- stream << "lo " << "World"
291
- stream << nil
292
- end
293
- assert_equal "Hello World", io.string
294
- end
295
- end
296
- end
297
-
298
- describe "#writer(:line)" do
299
- describe "#write" do
300
- it "one block" do
301
- io = StringIO.new
302
- IOStreams::Stream.new(io).writer(:line) do |stream|
303
- stream.write("Hello World")
304
- end
305
- assert_equal "Hello World\n", io.string
306
- end
307
-
308
- it "multiple blocks" do
309
- io = StringIO.new
310
- IOStreams::Stream.new(io).writer(:line) do |stream|
311
- stream.write("He")
312
- stream.write("l")
313
- stream.write("lo ")
314
- stream.write("World")
315
- end
316
- assert_equal "He\nl\nlo \nWorld\n", io.string
317
- end
318
-
319
- it "empty blocks" do
320
- io = StringIO.new
321
- IOStreams::Stream.new(io).writer(:line) do |stream|
322
- stream.write("")
323
- stream.write("He")
324
- stream.write("")
325
- stream.write("l")
326
- stream.write("")
327
- stream.write("lo ")
328
- stream.write("World")
329
- stream.write("")
330
- end
331
- assert_equal "\nHe\n\nl\n\nlo \nWorld\n\n", io.string, io.string.inspect
332
- end
333
-
334
- it "nil blocks" do
335
- io = StringIO.new
336
- IOStreams::Stream.new(io).writer(:line) do |stream|
337
- stream.write(nil)
338
- stream.write("He")
339
- stream.write(nil)
340
- stream.write("l")
341
- stream.write(nil)
342
- stream.write("lo ")
343
- stream.write("World")
344
- stream.write(nil)
345
- end
346
- assert_equal "\nHe\n\nl\n\nlo \nWorld\n\n", io.string, io.string.inspect
347
- end
348
- end
349
-
350
- describe "#<<" do
351
- it "one block" do
352
- io = StringIO.new
353
- IOStreams::Stream.new(io).writer(:line) do |stream|
354
- stream << "Hello World"
355
- end
356
- assert_equal "Hello World\n", io.string
357
- end
358
-
359
- it "multiple blocks" do
360
- io = StringIO.new
361
- IOStreams::Stream.new(io).writer(:line) do |stream|
362
- stream << "He"
363
- stream << "l" << "lo " << "World"
364
- end
365
- assert_equal "He\nl\nlo \nWorld\n", io.string
366
- end
367
-
368
- it "empty blocks" do
369
- io = StringIO.new
370
- IOStreams::Stream.new(io).writer(:line) do |stream|
371
- stream << ""
372
- stream << "He" << "" << "l" << ""
373
- stream << "lo " << "World"
374
- stream << ""
375
- end
376
- assert_equal "\nHe\n\nl\n\nlo \nWorld\n\n", io.string
377
- end
378
-
379
- it "nil blocks" do
380
- io = StringIO.new
381
- IOStreams::Stream.new(io).writer(:line) do |stream|
382
- stream << nil
383
- stream << "He" << nil << "l" << nil
384
- stream << "lo " << "World"
385
- stream << nil
386
- end
387
- assert_equal "\nHe\n\nl\n\nlo \nWorld\n\n", io.string
388
- end
389
- end
390
-
391
- describe "line writers within line writers" do
392
- it "uses existing line writer" do
393
- io = StringIO.new
394
- IOStreams::Stream.new(io).writer(:line) do |stream|
395
- stream.write("Before")
396
- IOStreams::Stream.new(stream).writer(:line) do |inner|
397
- stream.write("Inner")
398
- assert_equal inner.object_id, stream.object_id
399
- end
400
- stream.write("After")
401
- end
402
- assert_equal "Before\nInner\nAfter\n", io.string, io.string.inspect
403
- end
404
- end
405
- end
406
-
407
- describe "#writer(:array)" do
408
- describe "#write" do
409
- it "one block" do
410
- io = StringIO.new
411
- IOStreams::Stream.new(io).writer(:array) do |stream|
412
- stream << %w[Hello World]
413
- end
414
- assert_equal "Hello,World\n", io.string
415
- end
416
-
417
- it "multiple blocks" do
418
- io = StringIO.new
419
- IOStreams::Stream.new(io).writer(:array) do |stream|
420
- stream << %w[He]
421
- stream << %w[l lo\ World]
422
- stream << ["He", "", "l", ""]
423
- stream << ["lo ", "World"]
424
- end
425
- assert_equal "He\nl,lo ,World\nHe,\"\",l,\"\"\nlo ,World\n", io.string, io.string.inspect
426
- end
427
-
428
- it "empty blocks" do
429
- # skip "TODO"
430
- io = StringIO.new
431
- IOStreams::Stream.new(io).writer(:array) do |stream|
432
- stream << %w[He]
433
- stream << []
434
- stream << %w[l lo\ World]
435
- stream << ["He", "", "l", ""]
436
- stream << ["lo ", "World"]
437
- stream << []
438
- end
439
- assert_equal "He\n\nl,lo ,World\nHe,\"\",l,\"\"\nlo ,World\n\n", io.string, io.string.inspect
440
- end
441
-
442
- it "nil values" do
443
- io = StringIO.new
444
- IOStreams::Stream.new(io).writer(:array) do |stream|
445
- stream << %w[He]
446
- stream << %w[l lo\ World]
447
- stream << ["He", nil, "l", nil]
448
- stream << ["lo ", "World"]
449
- end
450
- assert_equal "He\nl,lo ,World\nHe,,l,\nlo ,World\n", io.string, io.string.inspect
451
- end
452
-
453
- it "empty leading array" do
454
- skip "TODO"
455
- io = StringIO.new
456
- IOStreams::Stream.new(io).writer(:array) do |stream|
457
- stream << []
458
- stream << %w[He]
459
- stream << %w[l lo\ World]
460
- stream << ["He", "", "l", ""]
461
- stream << ["lo ", "World"]
462
- stream << []
463
- end
464
- assert_equal "\nHe\n\nl\n\nlo \nWorld\n\n", io.string, io.string.inspect
465
- end
466
-
467
- it "honors format" do
468
- io = StringIO.new
469
- IOStreams::Stream.new(io).format(:psv).writer(:array) do |stream|
470
- stream << %w[first_name last_name]
471
- stream << %w[Jack Johnson]
472
- end
473
- assert_equal "first_name|last_name\nJack|Johnson\n", io.string, io.string.inspect
474
- end
475
-
476
- it "auto detects format" do
477
- io = StringIO.new
478
- IOStreams::Stream.new(io).file_name("abc.psv").writer(:array) do |stream|
479
- stream << %w[first_name last_name]
480
- stream << %w[Jack Johnson]
481
- end
482
- assert_equal "first_name|last_name\nJack|Johnson\n", io.string, io.string.inspect
483
- end
484
- end
485
- end
486
-
487
- describe "#writer(:hash)" do
488
- describe "#write" do
489
- it "one block" do
490
- io = StringIO.new
491
- IOStreams::Stream.new(io).writer(:hash) do |stream|
492
- stream << {first_name: "Jack", last_name: "Johnson"}
493
- end
494
- assert_equal "first_name,last_name\nJack,Johnson\n", io.string, io.string.inspect
495
- end
496
-
497
- it "multiple blocks" do
498
- io = StringIO.new
499
- IOStreams::Stream.new(io).writer(:hash) do |stream|
500
- stream << {first_name: "Jack", last_name: "Johnson"}
501
- stream << {first_name: "Able", last_name: "Smith"}
502
- end
503
- assert_equal "first_name,last_name\nJack,Johnson\nAble,Smith\n", io.string, io.string.inspect
504
- end
505
-
506
- it "empty hashes" do
507
- io = StringIO.new
508
- IOStreams::Stream.new(io).writer(:hash) do |stream|
509
- stream << {first_name: "Jack", last_name: "Johnson"}
510
- stream << {} << {first_name: "Able", last_name: "Smith"}
511
- stream << {}
512
- end
513
- # Accept both old and new hash syntax formats due to Ruby version differences
514
- expected_old = "first_name,last_name\nJack,Johnson\n\n{:first_name=>\"Able\", :last_name=>\"Smith\"}\n\n"
515
- expected_new = "first_name,last_name\nJack,Johnson\n\n{first_name: \"Able\", last_name: \"Smith\"}\n\n"
516
- assert_includes [expected_old, expected_new], io.string, io.string.inspect
517
- end
518
-
519
- it "nil values" do
520
- skip "TODO"
521
- io = StringIO.new
522
- IOStreams::Stream.new(io).writer(:hash) do |stream|
523
- stream << {first_name: "Jack", last_name: "Johnson"}
524
- stream << {} << {first_name: "Able", last_name: "Smith"}
525
- stream << {first_name: "Able", last_name: nil}
526
- stream << {}
527
- end
528
- assert_equal "first_name,last_name\nJack,Johnson\n\n{:first_name=>\"Able\", :last_name=>\"Smith\"}\n\n", io.string, io.string.inspect
529
- end
530
-
531
- it "honors format" do
532
- io = StringIO.new
533
- IOStreams::Stream.new(io).format(:json).writer(:hash) do |stream|
534
- stream << {first_name: "Jack", last_name: "Johnson"}
535
- end
536
- assert_equal "{\"first_name\":\"Jack\",\"last_name\":\"Johnson\"}\n", io.string, io.string.inspect
537
- end
538
-
539
- it "auto detects format" do
540
- io = StringIO.new
541
- IOStreams::Stream.new(io).file_name("abc.json").writer(:hash) do |stream|
542
- stream << {first_name: "Jack", last_name: "Johnson"}
543
- end
544
- assert_equal "{\"first_name\":\"Jack\",\"last_name\":\"Johnson\"}\n", io.string, io.string.inspect
545
- end
546
- end
547
- end
548
-
549
- describe "#format" do
550
- it "detects the format from the file name" do
551
- stream.file_name = "abc.json"
552
- assert_equal :json, stream.format
553
- end
554
-
555
- it "is nil if the file name has no meaningful format" do
556
- assert_nil stream.format
557
- end
558
-
559
- it "returns set format with no file_name" do
560
- stream.format = :csv
561
- assert_equal :csv, stream.format
562
- end
563
-
564
- it "returns set format with file_name" do
565
- stream.file_name = "abc.json"
566
- stream.format = :csv
567
- assert_equal :csv, stream.format
568
- end
569
-
570
- it "validates bad format" do
571
- assert_raises ArgumentError do
572
- stream.format = :blah
573
- end
574
- end
575
- end
576
- end
577
- end