iostreams 2.1.0 → 2.2.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.
- checksums.yaml +4 -4
- data/docs/config.md +13 -9
- data/docs/copy_files.md +20 -2
- data/docs/extensions.md +18 -4
- data/docs/formats.md +644 -16
- data/docs/path.md +18 -2
- data/docs/streams.md +54 -9
- data/docs/tutorial.md +14 -2
- data/docs/upgrading.md +470 -23
- data/lib/io_streams/builder/deprecations.rb +250 -0
- data/lib/io_streams/builder.rb +256 -39
- data/lib/io_streams/bzip2/reader.rb +18 -2
- data/lib/io_streams/bzip2/writer.rb +11 -2
- data/lib/io_streams/deprecation/methods.rb +51 -0
- data/lib/io_streams/deprecation/once.rb +27 -0
- data/lib/io_streams/deprecation/option_names.rb +26 -0
- data/lib/io_streams/deprecation/words.rb +42 -0
- data/lib/io_streams/deprecation.rb +259 -0
- data/lib/io_streams/encode/reader.rb +54 -3
- data/lib/io_streams/encode/writer.rb +19 -2
- data/lib/io_streams/encode.rb +99 -0
- data/lib/io_streams/errors.rb +51 -0
- data/lib/io_streams/gzip/reader.rb +11 -0
- data/lib/io_streams/io_streams.rb +365 -35
- data/lib/io_streams/line/reader.rb +2 -1
- data/lib/io_streams/line/utf8_reader.rb +23 -0
- data/lib/io_streams/path.rb +125 -35
- data/lib/io_streams/paths/file.rb +72 -9
- data/lib/io_streams/paths/http.rb +48 -2
- data/lib/io_streams/paths/matcher.rb +6 -3
- data/lib/io_streams/paths/s3.rb +180 -9
- data/lib/io_streams/paths/sftp.rb +47 -3
- data/lib/io_streams/paths.rb +23 -0
- data/lib/io_streams/pgp/reader.rb +18 -0
- data/lib/io_streams/pgp/writer.rb +16 -0
- data/lib/io_streams/pgp.rb +16 -2
- data/lib/io_streams/reader.rb +44 -0
- data/lib/io_streams/record/reader.rb +59 -68
- data/lib/io_streams/record/writer.rb +17 -10
- data/lib/io_streams/row/header_row.rb +21 -0
- data/lib/io_streams/row/reader.rb +52 -15
- data/lib/io_streams/row/writer.rb +64 -13
- data/lib/io_streams/schema/columns.rb +456 -0
- data/lib/io_streams/schema/constraints.rb +99 -0
- data/lib/io_streams/schema/field.rb +967 -0
- data/lib/io_streams/schema/json_number.rb +56 -0
- data/lib/io_streams/schema/keys.rb +78 -0
- data/lib/io_streams/schema/pattern.rb +257 -0
- data/lib/io_streams/schema/source.rb +31 -0
- data/lib/io_streams/schema.rb +616 -0
- data/lib/io_streams/stream.rb +836 -67
- data/lib/io_streams/symmetric_encryption/reader.rb +8 -0
- data/lib/io_streams/tabular/header.rb +29 -0
- data/lib/io_streams/tabular/header_mapping.rb +332 -0
- data/lib/io_streams/tabular/mapping.rb +165 -0
- data/lib/io_streams/tabular/parser/array.rb +5 -0
- data/lib/io_streams/tabular/parser/base.rb +24 -0
- data/lib/io_streams/tabular/parser/fixed.rb +197 -0
- data/lib/io_streams/tabular/parser/fixed_fields.rb +160 -0
- data/lib/io_streams/tabular/parser/hash.rb +10 -0
- data/lib/io_streams/tabular/parser/json.rb +17 -0
- data/lib/io_streams/tabular/parser/json_fields.rb +132 -0
- data/lib/io_streams/tabular/schema_mapping.rb +361 -0
- data/lib/io_streams/tabular.rb +344 -30
- data/lib/io_streams/utils.rb +441 -6
- data/lib/io_streams/version.rb +1 -1
- data/lib/io_streams/writer.rb +27 -0
- data/lib/io_streams/xlsx/cells.rb +127 -0
- data/lib/io_streams/xlsx/reader.rb +56 -0
- data/lib/io_streams/xlsx/schema_reader.rb +90 -0
- data/lib/io_streams/xlsx/v3_writer.rb +16 -0
- data/lib/io_streams/zip/reader.rb +7 -0
- data/lib/io_streams/zip/writer.rb +24 -2
- data/lib/iostreams.rb +21 -17
- metadata +28 -2
data/docs/path.md
CHANGED
|
@@ -309,7 +309,8 @@ end
|
|
|
309
309
|
|
|
310
310
|
A username and password supplied in the url remain part of it, so `#to_s` returns them,
|
|
311
311
|
as does any log or error message that includes the path. To keep them out of logs, supply them
|
|
312
|
-
with the `username:` and `password:` arguments instead
|
|
312
|
+
with the `username:` and `password:` arguments instead, and log `#display_name`, which never
|
|
313
|
+
includes them.
|
|
313
314
|
|
|
314
315
|
#### Optional Arguments:
|
|
315
316
|
|
|
@@ -378,7 +379,8 @@ Notes:
|
|
|
378
379
|
|
|
379
380
|
A username and password supplied in the url remain part of it, so `#to_s` returns them,
|
|
380
381
|
as does any log or error message that includes the path. To keep them out of logs, supply them
|
|
381
|
-
with the `username:` and `password:` arguments instead
|
|
382
|
+
with the `username:` and `password:` arguments instead, and log `#display_name`, which never
|
|
383
|
+
includes them.
|
|
382
384
|
|
|
383
385
|
#### Optional Arguments:
|
|
384
386
|
|
|
@@ -487,6 +489,20 @@ IOStreams.path("sample/data").mkpath
|
|
|
487
489
|
Inspect the components of a path's file name:
|
|
488
490
|
|
|
489
491
|
~~~ruby
|
|
492
|
+
# The full name of the path, without any user name, password or query in an SFTP or HTTP url,
|
|
493
|
+
# for logging. Unlike #to_s it cannot be used to create the path again.
|
|
494
|
+
IOStreams.path("sftp://jack:secret@sftp.example.org/data/ruby.rb").display_name
|
|
495
|
+
# => "sftp://sftp.example.org/data/ruby.rb"
|
|
496
|
+
|
|
497
|
+
# The options for creating a path, such as a password, with each secret replaced, for an application
|
|
498
|
+
# that stores a url and its options, and displays them. The path class of the url decides which are
|
|
499
|
+
# secret. `redact_stream_options` does the same for the options of streams.
|
|
500
|
+
IOStreams.redact_path_options("sftp://sftp.example.org/data/ruby.rb", username: "jack", password: "secret")
|
|
501
|
+
# => {username: "jack", password: "[FILTERED]"}
|
|
502
|
+
|
|
503
|
+
IOStreams.redact_stream_options(pgp: {passphrase: "secret", recipient: "a@b.org"})
|
|
504
|
+
# => {pgp: {passphrase: "[FILTERED]", recipient: "a@b.org"}}
|
|
505
|
+
|
|
490
506
|
# The last component of the path.
|
|
491
507
|
IOStreams.path("/home/gumby/work/ruby.rb").basename
|
|
492
508
|
# => "ruby.rb"
|
data/docs/streams.md
CHANGED
|
@@ -21,6 +21,12 @@ IOStreams.path("example.csv").reader do |io|
|
|
|
21
21
|
end
|
|
22
22
|
~~~
|
|
23
23
|
|
|
24
|
+
The stream that the block receives answers the methods of an IO that read, such as `#read` and `#eof?`. Rely on
|
|
25
|
+
those, rather than on the class of the stream, which depends on how the file is stored, such as a `Zlib::GzipReader`
|
|
26
|
+
for a `.gz` file. Where a library needs a `File`, copy the data into a local file first, such as with
|
|
27
|
+
`IOStreams.temp_file` and `#copy_to`, and read that file. To read the data from the start again, open the reader
|
|
28
|
+
again.
|
|
29
|
+
|
|
24
30
|
Read one line at a time from the file:
|
|
25
31
|
~~~ruby
|
|
26
32
|
IOStreams.path("example.csv").each do |line|
|
|
@@ -50,8 +56,13 @@ Notes:
|
|
|
50
56
|
tabular format quotes its fields, such as CSV (detected from a `.csv` file name or set explicitly via
|
|
51
57
|
`.format(:csv)`). `embedded_within` only needs to be supplied for quoted formats that are not
|
|
52
58
|
auto-detected, or to override the quote character.
|
|
59
|
+
* When reading rows or records, with `each(:array)` or `each(:hash)`, the format of the file decides where
|
|
60
|
+
its lines are split, since its parser must agree with them, so set the format with `format` instead.
|
|
61
|
+
Supplying `embedded_within` there is deprecated, and reports a deprecation warning, see
|
|
62
|
+
[Seeing deprecation warnings](upgrading#seeing-deprecation-warnings).
|
|
53
63
|
* A file that is named `.csv` but is actually pipe-delimited can avoid quote parsing by declaring its
|
|
54
|
-
real format with `.format(:psv)`, or by passing `embedded_within: nil` to disable it
|
|
64
|
+
real format with `.format(:psv)`, or when reading lines, by passing `embedded_within: nil` to disable it
|
|
65
|
+
explicitly:
|
|
55
66
|
~~~ruby
|
|
56
67
|
IOStreams.path("pipe_delimited.csv").format(:psv).each(:line) do |line|
|
|
57
68
|
puts line
|
|
@@ -72,6 +83,23 @@ IOStreams.path("example.csv").each(:hash) do |hash|
|
|
|
72
83
|
end
|
|
73
84
|
~~~
|
|
74
85
|
|
|
86
|
+
The tabular format of the rows and records, such as CSV or JSON, is detected from the file name, or set with
|
|
87
|
+
`#format`, see [File Formats](formats). Set a schema on the path with `#schema` to read each value as the type of
|
|
88
|
+
its field, such as an `Integer` or a `Date`, with the names of the fields as the keys of each record, see
|
|
89
|
+
[Schema](formats#schema):
|
|
90
|
+
~~~ruby
|
|
91
|
+
IOStreams.path("example.csv").schema(
|
|
92
|
+
fieldsMatch: "subset",
|
|
93
|
+
fields: [
|
|
94
|
+
{name: "name"},
|
|
95
|
+
{name: "zip_code", type: "integer"}
|
|
96
|
+
]
|
|
97
|
+
).each(:hash) do |hash|
|
|
98
|
+
p hash
|
|
99
|
+
end
|
|
100
|
+
# => {"name" => "Jack", "zip_code" => 1234}
|
|
101
|
+
~~~
|
|
102
|
+
|
|
75
103
|
Write data to the file.
|
|
76
104
|
~~~ruby
|
|
77
105
|
IOStreams.path("abc.txt").writer do |io|
|
|
@@ -258,10 +286,12 @@ IOStreams.path("example.csv.pgp").
|
|
|
258
286
|
|
|
259
287
|
An option that neither direction accepts, such as a misspelled one, raises an `ArgumentError`
|
|
260
288
|
that lists the valid options. The exception is BZip2, which ignores options it does not accept and
|
|
261
|
-
logs a warning instead.
|
|
289
|
+
logs a warning instead. One that neither reading nor writing takes also reports a deprecation warning,
|
|
290
|
+
since in v3.0 it will raise an `ArgumentError` too, while v3.0 ignores an option of the other direction.
|
|
262
291
|
|
|
263
292
|
Options for a stream that is not in the pipeline are still ignored, as described above,
|
|
264
|
-
since they are not passed to any reader or writer.
|
|
293
|
+
since they are not passed to any reader or writer. One that neither direction accepts reports a
|
|
294
|
+
deprecation warning when it is set, for every stream, since v3.0 raises an `ArgumentError` for it then.
|
|
265
295
|
|
|
266
296
|
#### Stream
|
|
267
297
|
|
|
@@ -305,7 +335,8 @@ In this example the file contains JSON data that was compressed with Zip, and si
|
|
|
305
335
|
~~~ruby
|
|
306
336
|
IOStreams.path("tempfile2527").
|
|
307
337
|
stream(:zip).
|
|
308
|
-
|
|
338
|
+
format(:json).
|
|
339
|
+
each(:hash) do |row|
|
|
309
340
|
p row
|
|
310
341
|
end
|
|
311
342
|
~~~
|
|
@@ -329,9 +360,23 @@ path.setting(:pgp)
|
|
|
329
360
|
# => {:passphrase=>"receiver_passphrase"}
|
|
330
361
|
~~~
|
|
331
362
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
363
|
+
#### Raw
|
|
364
|
+
|
|
365
|
+
To read or write the data as it is stored, applying no streams, neither those that the file name implies nor any
|
|
366
|
+
set with `option` or `stream`, and no encoding, use `raw`. For example, to checksum a compressed file as it is
|
|
367
|
+
stored, or to write data that is already compressed:
|
|
368
|
+
|
|
369
|
+
~~~ruby
|
|
370
|
+
Digest::SHA256.hexdigest(IOStreams.path("data.csv.gz").raw.read)
|
|
371
|
+
|
|
372
|
+
IOStreams.path("data.csv.gz").raw.write(gzipped_data)
|
|
337
373
|
~~~
|
|
374
|
+
|
|
375
|
+
Setting a stream, option or encoding after `raw` raises `ArgumentError`, since the data is as stored.
|
|
376
|
+
`raw?` returns whether `raw` was called. `raw` replaces `stream(:none)`, which is deprecated: it still works, and
|
|
377
|
+
reports a deprecation warning, see [Upgrading](upgrading#deprecated-and-what-replaces-it).
|
|
378
|
+
|
|
379
|
+
To copy a file as it is stored, such as downloading a zip file without unzipping it, use
|
|
380
|
+
`copy_to(target, convert: false)` instead, since the target applies its own streams. To read a file that is not
|
|
381
|
+
named for its format, such as a CSV file called `data.txt`, set the file name that names its format, for example
|
|
382
|
+
`file_name("data.csv")`.
|
data/docs/tutorial.md
CHANGED
|
@@ -429,8 +429,20 @@ Using `writer(:hash)` makes it easier to develop the application without regard
|
|
|
429
429
|
- Specialized escaping of values to handle row or column delimiters
|
|
430
430
|
|
|
431
431
|
Note: The first row written determines the column names as well as the order of the elements to be written.
|
|
432
|
-
To
|
|
433
|
-
|
|
432
|
+
To set the columns up front, in your own order, describe them with a [schema](formats#schema) on the path: its
|
|
433
|
+
fields are the columns, in order, and `fieldsMatch: "subset"` skips the other keys of each record:
|
|
434
|
+
~~~ruby
|
|
435
|
+
path = IOStreams.path("sample/logins.csv").schema(
|
|
436
|
+
fieldsMatch: "subset",
|
|
437
|
+
fields: [{name: "login"}, {name: "name"}]
|
|
438
|
+
)
|
|
439
|
+
path.writer(:hash) do |io|
|
|
440
|
+
io << {"name" => "Jack Jones", "login" => "jjones", "notes" => "Not written"}
|
|
441
|
+
io << {"login" => "jsmith", "name" => "Jill Smith"}
|
|
442
|
+
end
|
|
443
|
+
path.read
|
|
444
|
+
# => "login,name\njjones,Jack Jones\njsmith,Jill Smith\n"
|
|
445
|
+
~~~
|
|
434
446
|
|
|
435
447
|
Now lets write the same data into a JSON file, then read it to see what it looks like:
|
|
436
448
|
~~~ruby
|