iostreams 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -22
- data/Rakefile +45 -0
- data/docs/CLAUDE.md +9 -0
- data/docs/config.md +157 -0
- data/docs/copy_files.md +75 -0
- data/docs/extensions.md +111 -0
- data/docs/formats.md +188 -0
- data/docs/index.md +388 -0
- data/docs/path.md +652 -0
- data/docs/pgp.md +436 -0
- data/docs/streams.md +337 -0
- data/docs/tutorial.md +483 -0
- data/docs/upgrading.md +217 -0
- data/lib/io_streams/builder.rb +62 -2
- data/lib/io_streams/bzip2/reader.rb +25 -2
- data/lib/io_streams/bzip2/writer.rb +26 -2
- data/lib/io_streams/encode/reader.rb +4 -0
- data/lib/io_streams/encode/writer.rb +4 -0
- data/lib/io_streams/errors.rb +4 -0
- data/lib/io_streams/gzip/reader.rb +4 -0
- data/lib/io_streams/gzip/writer.rb +11 -2
- data/lib/io_streams/io_streams.rb +111 -1
- data/lib/io_streams/line/reader.rb +7 -2
- data/lib/io_streams/path.rb +115 -6
- data/lib/io_streams/paths/file.rb +47 -1
- data/lib/io_streams/paths/http.rb +45 -4
- data/lib/io_streams/paths/s3.rb +66 -15
- data/lib/io_streams/paths/sftp/net_ssh.rb +104 -0
- data/lib/io_streams/paths/sftp.rb +97 -57
- data/lib/io_streams/pgp/reader.rb +42 -2
- data/lib/io_streams/pgp/writer.rb +26 -6
- data/lib/io_streams/pgp.rb +78 -21
- data/lib/io_streams/reader.rb +10 -1
- data/lib/io_streams/record/reader.rb +72 -2
- data/lib/io_streams/stream.rb +12 -7
- data/lib/io_streams/symmetric_encryption/reader.rb +4 -0
- data/lib/io_streams/symmetric_encryption/writer.rb +4 -0
- data/lib/io_streams/tabular/header.rb +31 -4
- data/lib/io_streams/tabular/parser/base.rb +10 -0
- data/lib/io_streams/tabular/parser/csv.rb +5 -0
- data/lib/io_streams/tabular/parser/fixed.rb +3 -1
- data/lib/io_streams/tabular/parser/psv.rb +6 -2
- data/lib/io_streams/utils.rb +31 -0
- data/lib/io_streams/version.rb +1 -1
- data/lib/io_streams/writer.rb +10 -1
- data/lib/io_streams/xlsx/reader.rb +5 -1
- data/lib/io_streams/zip/reader.rb +4 -0
- data/lib/io_streams/zip/writer.rb +4 -0
- metadata +24 -7
|
@@ -3,6 +3,7 @@ module IOStreams
|
|
|
3
3
|
module Parser
|
|
4
4
|
# For parsing a single line of Pipe-separated values
|
|
5
5
|
class Psv < Base
|
|
6
|
+
LINE_BREAK = /\r\n|\r|\n/
|
|
6
7
|
# Returns [Array] the parsed PSV line
|
|
7
8
|
def parse(row)
|
|
8
9
|
return row if row.is_a?(::Array)
|
|
@@ -12,11 +13,14 @@ module IOStreams
|
|
|
12
13
|
row.split("|")
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
# Return the supplied array as a single line
|
|
16
|
+
# Return the supplied array as a single line PSV string.
|
|
17
|
+
#
|
|
18
|
+
# Since PSV has no escaping, any `|` within a value is replaced with `:`,
|
|
19
|
+
# and any line break with a space, so that a value cannot add columns or records.
|
|
16
20
|
def render(row, header)
|
|
17
21
|
array = header.to_array(row)
|
|
18
22
|
cleansed_array = array.collect do |i|
|
|
19
|
-
i.is_a?(String) ? i.tr("|", ":") : i
|
|
23
|
+
i.is_a?(String) ? i.tr("|", ":").gsub(LINE_BREAK, " ") : i
|
|
20
24
|
end
|
|
21
25
|
cleansed_array.join("|")
|
|
22
26
|
end
|
data/lib/io_streams/utils.rb
CHANGED
|
@@ -12,6 +12,17 @@ module IOStreams
|
|
|
12
12
|
raise(LoadError, "Please install the gem '#{gem_name}' to support #{stream_type}. #{e.message}")
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
# Log a warning for options that a stream ignores, until they raise `ArgumentError` in v3.0.
|
|
16
|
+
def self.warn_unknown_options(unknown, stream, direction, valid)
|
|
17
|
+
return if unknown.empty?
|
|
18
|
+
|
|
19
|
+
names = unknown.keys.map(&:inspect).join(", ")
|
|
20
|
+
IOStreams.logger&.warn(
|
|
21
|
+
"Ignoring unknown #{unknown.size == 1 ? 'option' : 'options'} #{names} when #{direction} a #{stream.inspect} " \
|
|
22
|
+
"stream. Valid options: #{valid.map(&:inspect).join(', ')}. In v3.0 this will raise ArgumentError."
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
15
26
|
# Helper method: Returns [true|false] if a value is blank?
|
|
16
27
|
def self.blank?(value)
|
|
17
28
|
return true if value.nil?
|
|
@@ -33,6 +44,26 @@ module IOStreams
|
|
|
33
44
|
result
|
|
34
45
|
end
|
|
35
46
|
|
|
47
|
+
# Yields the name of a new, empty temporary file that only the current user can read or write.
|
|
48
|
+
#
|
|
49
|
+
# The file is created exclusively, so that an existing file, or a link planted in a shared
|
|
50
|
+
# temp directory, is never written to. Only a name collision when creating the file is retried,
|
|
51
|
+
# and the file is only deleted once it was created here, so that another process's file is never removed.
|
|
52
|
+
#
|
|
53
|
+
# Returns the value from the block.
|
|
54
|
+
def self.private_temp_file(basename, extension = "")
|
|
55
|
+
file_name = ::Dir::Tmpname.create([basename, extension], IOStreams.temp_dir,
|
|
56
|
+
max_try: MAX_TEMP_FILE_NAME_ATTEMPTS) do |tmpname|
|
|
57
|
+
::File.open(tmpname, ::File::WRONLY | ::File::CREAT | ::File::EXCL, 0o600, &:close)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
begin
|
|
61
|
+
yield(file_name)
|
|
62
|
+
ensure
|
|
63
|
+
::FileUtils.rm_f(file_name)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
36
67
|
class URI
|
|
37
68
|
attr_reader :scheme, :hostname, :path, :user, :password, :port, :query
|
|
38
69
|
|
data/lib/io_streams/version.rb
CHANGED
data/lib/io_streams/writer.rb
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
module IOStreams
|
|
2
2
|
class Writer
|
|
3
|
+
# Returns [Array<Symbol>] the names of the options this writer accepts,
|
|
4
|
+
# or [nil] when the writer does not declare them.
|
|
5
|
+
#
|
|
6
|
+
# When declared, `IOStreams::Builder` rejects any other option before the writer is opened,
|
|
7
|
+
# naming the direction an option belongs to when it is only valid for the other direction.
|
|
8
|
+
def self.option_names
|
|
9
|
+
nil
|
|
10
|
+
end
|
|
11
|
+
|
|
3
12
|
# When a Writer does not support streams, we copy the stream to a local temp file
|
|
4
13
|
# and then pass that filename in for this reader.
|
|
5
14
|
def self.stream(output_stream, **args, &block)
|
|
6
|
-
Utils.
|
|
15
|
+
Utils.private_temp_file("iostreams_writer") do |file_name|
|
|
7
16
|
count = file(file_name, **args, &block)
|
|
8
17
|
::File.open(file_name, "rb") { |source| ::IO.copy_stream(source, output_stream) }
|
|
9
18
|
count
|
|
@@ -3,10 +3,14 @@ require "csv"
|
|
|
3
3
|
module IOStreams
|
|
4
4
|
module Xlsx
|
|
5
5
|
class Reader < IOStreams::Reader
|
|
6
|
+
def self.option_names
|
|
7
|
+
[]
|
|
8
|
+
end
|
|
9
|
+
|
|
6
10
|
# Convert a xlsx, or xlsm file into CSV format.
|
|
7
11
|
def self.file(file_name, &block)
|
|
8
12
|
# Stream into a temp file as csv
|
|
9
|
-
Utils.
|
|
13
|
+
Utils.private_temp_file("iostreams_csv") do |temp_file_name|
|
|
10
14
|
::File.open(temp_file_name, "wb") { |io| new(file_name).each { |lines| io << lines.to_csv } }
|
|
11
15
|
::File.open(temp_file_name, "rb", &block)
|
|
12
16
|
end
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
module IOStreams
|
|
2
2
|
module Zip
|
|
3
3
|
class Reader < IOStreams::Reader
|
|
4
|
+
def self.option_names
|
|
5
|
+
%i[entry_file_name]
|
|
6
|
+
end
|
|
7
|
+
|
|
4
8
|
# Read from a zip file or stream, decompressing the contents as it is read
|
|
5
9
|
# The input stream from the first file found in the zip file is passed
|
|
6
10
|
# to the supplied block.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
module IOStreams
|
|
2
2
|
module Zip
|
|
3
3
|
class Writer < IOStreams::Writer
|
|
4
|
+
def self.option_names
|
|
5
|
+
%i[zip_file_name entry_file_name]
|
|
6
|
+
end
|
|
7
|
+
|
|
4
8
|
# When writing to a file, default the entry name within the zip to the file name
|
|
5
9
|
# without the `.zip` extension, unless an entry name was explicitly supplied.
|
|
6
10
|
def self.file(file_name, zip_file_name: nil, entry_file_name: zip_file_name, &)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: iostreams
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Reid Morrison
|
|
@@ -23,6 +23,10 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0'
|
|
26
|
+
description: IOStreams makes file formats, compression (gzip, zip, bzip2), encryption
|
|
27
|
+
(PGP, symmetric), and storage location (local file, S3, SFTP, HTTP) transparent
|
|
28
|
+
to your application code. Files of any size are read and written one block at a
|
|
29
|
+
time, without loading the entire file into memory.
|
|
26
30
|
executables: []
|
|
27
31
|
extensions: []
|
|
28
32
|
extra_rdoc_files: []
|
|
@@ -30,6 +34,17 @@ files:
|
|
|
30
34
|
- LICENSE
|
|
31
35
|
- README.md
|
|
32
36
|
- Rakefile
|
|
37
|
+
- docs/CLAUDE.md
|
|
38
|
+
- docs/config.md
|
|
39
|
+
- docs/copy_files.md
|
|
40
|
+
- docs/extensions.md
|
|
41
|
+
- docs/formats.md
|
|
42
|
+
- docs/index.md
|
|
43
|
+
- docs/path.md
|
|
44
|
+
- docs/pgp.md
|
|
45
|
+
- docs/streams.md
|
|
46
|
+
- docs/tutorial.md
|
|
47
|
+
- docs/upgrading.md
|
|
33
48
|
- lib/io_streams/builder.rb
|
|
34
49
|
- lib/io_streams/bzip2/reader.rb
|
|
35
50
|
- lib/io_streams/bzip2/writer.rb
|
|
@@ -47,6 +62,7 @@ files:
|
|
|
47
62
|
- lib/io_streams/paths/matcher.rb
|
|
48
63
|
- lib/io_streams/paths/s3.rb
|
|
49
64
|
- lib/io_streams/paths/sftp.rb
|
|
65
|
+
- lib/io_streams/paths/sftp/net_ssh.rb
|
|
50
66
|
- lib/io_streams/pgp.rb
|
|
51
67
|
- lib/io_streams/pgp/reader.rb
|
|
52
68
|
- lib/io_streams/pgp/writer.rb
|
|
@@ -74,14 +90,15 @@ files:
|
|
|
74
90
|
- lib/io_streams/zip/reader.rb
|
|
75
91
|
- lib/io_streams/zip/writer.rb
|
|
76
92
|
- lib/iostreams.rb
|
|
77
|
-
homepage: https://iostreams.
|
|
93
|
+
homepage: https://iostreams.reidmorrison.com
|
|
78
94
|
licenses:
|
|
79
95
|
- Apache-2.0
|
|
80
96
|
metadata:
|
|
81
97
|
bug_tracker_uri: https://github.com/reidmorrison/iostreams/issues
|
|
82
|
-
changelog_uri: https://github.com/reidmorrison/iostreams/blob/
|
|
83
|
-
documentation_uri: https://iostreams.
|
|
84
|
-
|
|
98
|
+
changelog_uri: https://github.com/reidmorrison/iostreams/blob/main/CHANGELOG.md
|
|
99
|
+
documentation_uri: https://iostreams.reidmorrison.com
|
|
100
|
+
homepage_uri: https://iostreams.reidmorrison.com
|
|
101
|
+
source_code_uri: https://github.com/reidmorrison/iostreams/tree/v2.1.0
|
|
85
102
|
rubygems_mfa_required: 'true'
|
|
86
103
|
rdoc_options: []
|
|
87
104
|
require_paths:
|
|
@@ -99,6 +116,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
99
116
|
requirements: []
|
|
100
117
|
rubygems_version: 3.6.9
|
|
101
118
|
specification_version: 4
|
|
102
|
-
summary: 'Streaming I/O for Ruby: compression, encryption, format, and storage
|
|
103
|
-
to your code.'
|
|
119
|
+
summary: 'Streaming I/O for Ruby: compression, encryption, file format, and storage
|
|
120
|
+
location transparent to your code.'
|
|
104
121
|
test_files: []
|