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.
- checksums.yaml +4 -4
- data/README.md +20 -2
- data/Rakefile +7 -0
- data/lib/io_streams/builder.rb +9 -9
- data/lib/io_streams/bzip2/writer.rb +1 -1
- data/lib/io_streams/encode/reader.rb +2 -2
- data/lib/io_streams/encode/writer.rb +5 -5
- data/lib/io_streams/gzip/reader.rb +1 -1
- data/lib/io_streams/gzip/writer.rb +1 -1
- data/lib/io_streams/io_streams.rb +45 -19
- data/lib/io_streams/line/reader.rb +2 -2
- data/lib/io_streams/line/writer.rb +1 -1
- data/lib/io_streams/path.rb +2 -2
- data/lib/io_streams/paths/file.rb +10 -10
- data/lib/io_streams/paths/http.rb +80 -7
- data/lib/io_streams/paths/matcher.rb +3 -3
- data/lib/io_streams/paths/s3.rb +3 -3
- data/lib/io_streams/paths/sftp.rb +7 -8
- data/lib/io_streams/pgp/reader.rb +23 -10
- data/lib/io_streams/pgp/writer.rb +93 -32
- data/lib/io_streams/pgp.rb +188 -60
- data/lib/io_streams/reader.rb +4 -4
- data/lib/io_streams/record/reader.rb +3 -4
- data/lib/io_streams/record/writer.rb +3 -4
- data/lib/io_streams/row/reader.rb +1 -1
- data/lib/io_streams/row/writer.rb +1 -1
- data/lib/io_streams/stream.rb +36 -30
- data/lib/io_streams/symmetric_encryption/reader.rb +2 -2
- data/lib/io_streams/symmetric_encryption/writer.rb +4 -4
- data/lib/io_streams/tabular/header.rb +18 -6
- data/lib/io_streams/tabular/parser/array.rb +0 -10
- data/lib/io_streams/tabular/parser/csv.rb +6 -38
- data/lib/io_streams/tabular/parser/fixed.rb +5 -5
- data/lib/io_streams/tabular/parser/psv.rb +0 -12
- data/lib/io_streams/tabular.rb +5 -10
- data/lib/io_streams/utils.rb +3 -2
- data/lib/io_streams/version.rb +1 -1
- data/lib/io_streams/writer.rb +6 -6
- data/lib/io_streams/xlsx/reader.rb +1 -1
- data/lib/io_streams/zip/writer.rb +22 -10
- data/lib/iostreams.rb +0 -1
- metadata +28 -111
- data/lib/io_streams/deprecated.rb +0 -216
- data/lib/io_streams/tabular/utility/csv_row.rb +0 -105
- data/test/builder_test.rb +0 -311
- data/test/bzip2_reader_test.rb +0 -27
- data/test/bzip2_writer_test.rb +0 -56
- data/test/deprecated_test.rb +0 -121
- data/test/encode_reader_test.rb +0 -51
- data/test/encode_writer_test.rb +0 -90
- data/test/files/embedded_lines_test.csv +0 -7
- data/test/files/multiple_files.zip +0 -0
- data/test/files/spreadsheet.xlsx +0 -0
- data/test/files/test.csv +0 -4
- data/test/files/test.json +0 -3
- data/test/files/test.psv +0 -4
- data/test/files/text file.txt +0 -3
- data/test/files/text.txt +0 -3
- data/test/files/text.txt.bz2 +0 -0
- data/test/files/text.txt.gz +0 -0
- data/test/files/text.txt.gz.zip +0 -0
- data/test/files/text.zip +0 -0
- data/test/files/text.zip.gz +0 -0
- data/test/files/unclosed_quote_large_test.csv +0 -1658
- data/test/files/unclosed_quote_test.csv +0 -4
- data/test/files/unclosed_quote_test2.csv +0 -3
- data/test/gzip_reader_test.rb +0 -27
- data/test/gzip_writer_test.rb +0 -52
- data/test/io_streams_test.rb +0 -132
- data/test/line_reader_test.rb +0 -325
- data/test/line_writer_test.rb +0 -59
- data/test/minimal_file_reader.rb +0 -25
- data/test/path_test.rb +0 -55
- data/test/paths/file_test.rb +0 -213
- data/test/paths/http_test.rb +0 -34
- data/test/paths/matcher_test.rb +0 -120
- data/test/paths/s3_test.rb +0 -220
- data/test/paths/sftp_test.rb +0 -106
- data/test/pgp_reader_test.rb +0 -46
- data/test/pgp_test.rb +0 -267
- data/test/pgp_writer_test.rb +0 -130
- data/test/record_reader_test.rb +0 -60
- data/test/record_writer_test.rb +0 -82
- data/test/row_reader_test.rb +0 -35
- data/test/row_writer_test.rb +0 -56
- data/test/stream_test.rb +0 -577
- data/test/tabular_test.rb +0 -338
- data/test/test_helper.rb +0 -40
- data/test/utils_test.rb +0 -20
- data/test/xlsx_reader_test.rb +0 -37
- data/test/zip_reader_test.rb +0 -53
- data/test/zip_writer_test.rb +0 -48
|
@@ -4,18 +4,18 @@ module IOStreams
|
|
|
4
4
|
# Write to stream using Symmetric Encryption
|
|
5
5
|
# By default the output stream is compressed.
|
|
6
6
|
# If the input_stream is already compressed consider setting compress: false.
|
|
7
|
-
def self.stream(input_stream, compress: true, **args, &
|
|
7
|
+
def self.stream(input_stream, compress: true, **args, &)
|
|
8
8
|
Utils.load_soft_dependency("symmetric-encryption", ".enc streaming") unless defined?(SymmetricEncryption)
|
|
9
9
|
|
|
10
|
-
::SymmetricEncryption::Writer.open(input_stream, compress: compress, **args, &
|
|
10
|
+
::SymmetricEncryption::Writer.open(input_stream, compress: compress, **args, &)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
# Write to stream using Symmetric Encryption
|
|
14
14
|
# By default the output stream is compressed unless the file_name extension indicates the file is already compressed.
|
|
15
|
-
def self.file(file_name, compress: nil, **args, &
|
|
15
|
+
def self.file(file_name, compress: nil, **args, &)
|
|
16
16
|
Utils.load_soft_dependency("symmetric-encryption", ".enc streaming") unless defined?(SymmetricEncryption)
|
|
17
17
|
|
|
18
|
-
::SymmetricEncryption::Writer.open(file_name, compress: compress, **args, &
|
|
18
|
+
::SymmetricEncryption::Writer.open(file_name, compress: compress, **args, &)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -5,16 +5,16 @@ module IOStreams
|
|
|
5
5
|
# Column names that begin with this prefix have been rejected and should be ignored.
|
|
6
6
|
IGNORE_PREFIX = "__rejected__".freeze
|
|
7
7
|
|
|
8
|
-
attr_accessor :
|
|
8
|
+
attr_accessor :allowed_columns, :required_columns, :skip_unknown
|
|
9
|
+
attr_reader :columns
|
|
9
10
|
|
|
10
11
|
# Header
|
|
11
12
|
#
|
|
12
13
|
# Parameters
|
|
13
|
-
# columns [Array<String>]
|
|
14
|
+
# columns [Array<String|Symbol>]
|
|
14
15
|
# Columns in this header.
|
|
15
16
|
# Note:
|
|
16
|
-
#
|
|
17
|
-
# with MongoDB when it converts symbol keys to strings.
|
|
17
|
+
# Column names are converted to strings.
|
|
18
18
|
#
|
|
19
19
|
# allowed_columns [Array<String>]
|
|
20
20
|
# List of columns to allow.
|
|
@@ -33,12 +33,17 @@ module IOStreams
|
|
|
33
33
|
# false:
|
|
34
34
|
# Raises Tabular::InvalidHeader when a column is supplied that is not in the whitelist.
|
|
35
35
|
def initialize(columns: nil, allowed_columns: nil, required_columns: nil, skip_unknown: true)
|
|
36
|
-
@columns = columns
|
|
36
|
+
@columns = stringify(columns)
|
|
37
37
|
@required_columns = required_columns
|
|
38
38
|
@allowed_columns = allowed_columns
|
|
39
39
|
@skip_unknown = skip_unknown
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
# Set the columns in this header, converting the column names to strings.
|
|
43
|
+
def columns=(columns)
|
|
44
|
+
@columns = stringify(columns)
|
|
45
|
+
end
|
|
46
|
+
|
|
42
47
|
# Returns [Array<String>] list columns that were ignored during cleansing.
|
|
43
48
|
#
|
|
44
49
|
# Each column is cleansed as follows:
|
|
@@ -127,13 +132,16 @@ module IOStreams
|
|
|
127
132
|
|
|
128
133
|
def array_to_hash(row)
|
|
129
134
|
h = {}
|
|
130
|
-
columns.each_with_index
|
|
135
|
+
columns.each_with_index do |col, i|
|
|
136
|
+
h[col] = row[i] unless IOStreams::Utils.blank?(col) || col.start_with?(IGNORE_PREFIX)
|
|
137
|
+
end
|
|
131
138
|
h
|
|
132
139
|
end
|
|
133
140
|
|
|
134
141
|
# Perform cleansing on returned Hash keys during the narrowing process.
|
|
135
142
|
# For example, avoids issues with case etc.
|
|
136
143
|
def cleanse_hash(hash)
|
|
144
|
+
hash = hash.transform_keys(&:to_s) unless hash.keys.all?(String)
|
|
137
145
|
unmatched = columns - hash.keys
|
|
138
146
|
unless unmatched.empty?
|
|
139
147
|
hash = hash.dup
|
|
@@ -149,6 +157,10 @@ module IOStreams
|
|
|
149
157
|
cleansed.gsub!(/\W+/, "")
|
|
150
158
|
cleansed
|
|
151
159
|
end
|
|
160
|
+
|
|
161
|
+
def stringify(columns)
|
|
162
|
+
columns&.collect { |column| column&.to_s }
|
|
163
|
+
end
|
|
152
164
|
end
|
|
153
165
|
end
|
|
154
166
|
end
|
|
@@ -3,16 +3,6 @@ module IOStreams
|
|
|
3
3
|
class Tabular
|
|
4
4
|
module Parser
|
|
5
5
|
class Array < Base
|
|
6
|
-
# Returns [Array<String>] the header row.
|
|
7
|
-
# Returns nil if the row is blank.
|
|
8
|
-
def parse_header(row)
|
|
9
|
-
unless row.is_a?(::Array)
|
|
10
|
-
raise(IOStreams::Errors::InvalidHeader, "Format is :array. Invalid input header: #{row.class.name}")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
row
|
|
14
|
-
end
|
|
15
|
-
|
|
16
6
|
# Returns Array
|
|
17
7
|
def parse(row)
|
|
18
8
|
raise(IOStreams::Errors::TypeMismatch, "Format is :array. Invalid input: #{row.class.name}") unless row.is_a?(::Array)
|
|
@@ -3,26 +3,6 @@ module IOStreams
|
|
|
3
3
|
class Tabular
|
|
4
4
|
module Parser
|
|
5
5
|
class Csv < Base
|
|
6
|
-
attr_reader :csv_parser
|
|
7
|
-
|
|
8
|
-
unless RUBY_VERSION.to_f >= 2.6
|
|
9
|
-
def initialize
|
|
10
|
-
@csv_parser = Utility::CSVRow.new
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# Returns [Array<String>] the header row.
|
|
15
|
-
# Returns nil if the row is blank.
|
|
16
|
-
def parse_header(row)
|
|
17
|
-
return row if row.is_a?(::Array)
|
|
18
|
-
|
|
19
|
-
unless row.is_a?(String)
|
|
20
|
-
raise(IOStreams::Errors::InvalidHeader, "Format is :csv. Invalid input header: #{row.class.name}")
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
parse_line(row)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
6
|
# Returns [Array] the parsed CSV line
|
|
27
7
|
def parse(row)
|
|
28
8
|
return row if row.is_a?(::Array)
|
|
@@ -40,26 +20,14 @@ module IOStreams
|
|
|
40
20
|
|
|
41
21
|
private
|
|
42
22
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# but at least it works on Ruby 2.6 and above.
|
|
46
|
-
def parse_line(line)
|
|
47
|
-
return if IOStreams::Utils.blank?(line)
|
|
23
|
+
def parse_line(line)
|
|
24
|
+
return if IOStreams::Utils.blank?(line)
|
|
48
25
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def render_array(array)
|
|
53
|
-
CSV.generate_line(array, encoding: "UTF-8", row_sep: "")
|
|
54
|
-
end
|
|
55
|
-
else
|
|
56
|
-
def parse_line(line)
|
|
57
|
-
csv_parser.parse(line)
|
|
58
|
-
end
|
|
26
|
+
CSV.parse_line(line)
|
|
27
|
+
end
|
|
59
28
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
end
|
|
29
|
+
def render_array(array)
|
|
30
|
+
CSV.generate_line(array, encoding: "UTF-8", row_sep: "")
|
|
63
31
|
end
|
|
64
32
|
end
|
|
65
33
|
end
|
|
@@ -71,7 +71,7 @@ module IOStreams
|
|
|
71
71
|
def render(row, header)
|
|
72
72
|
hash = header.to_hash(row)
|
|
73
73
|
|
|
74
|
-
result = ""
|
|
74
|
+
result = +""
|
|
75
75
|
layout.columns.each do |column|
|
|
76
76
|
result << column.render(hash[column.key], truncate)
|
|
77
77
|
end
|
|
@@ -93,7 +93,7 @@ module IOStreams
|
|
|
93
93
|
index = 0
|
|
94
94
|
layout.columns.each do |column|
|
|
95
95
|
if column.size == -1
|
|
96
|
-
hash[column.key] = column.parse(line[index
|
|
96
|
+
hash[column.key] = column.parse(line[index..]) if column.key
|
|
97
97
|
break
|
|
98
98
|
end
|
|
99
99
|
|
|
@@ -148,7 +148,7 @@ module IOStreams
|
|
|
148
148
|
|
|
149
149
|
def initialize(size:, key: nil, type: :string, decimals: 2)
|
|
150
150
|
@key = key
|
|
151
|
-
@size =
|
|
151
|
+
@size = [:remainder, "remainder"].include?(size) ? -1 : size.to_i
|
|
152
152
|
@type = type.to_sym
|
|
153
153
|
@decimals = decimals
|
|
154
154
|
|
|
@@ -167,9 +167,9 @@ module IOStreams
|
|
|
167
167
|
when :string
|
|
168
168
|
stripped_value
|
|
169
169
|
when :integer
|
|
170
|
-
stripped_value.
|
|
170
|
+
stripped_value.empty? ? nil : value.to_i
|
|
171
171
|
when :float
|
|
172
|
-
stripped_value.
|
|
172
|
+
stripped_value.empty? ? nil : value.to_f
|
|
173
173
|
else
|
|
174
174
|
raise(Errors::InvalidLayout, "Unsupported type: #{type.inspect}")
|
|
175
175
|
end
|
|
@@ -3,18 +3,6 @@ module IOStreams
|
|
|
3
3
|
module Parser
|
|
4
4
|
# For parsing a single line of Pipe-separated values
|
|
5
5
|
class Psv < Base
|
|
6
|
-
# Returns [Array<String>] the header row.
|
|
7
|
-
# Returns nil if the row is blank.
|
|
8
|
-
def parse_header(row)
|
|
9
|
-
return row if row.is_a?(::Array)
|
|
10
|
-
|
|
11
|
-
unless row.is_a?(String)
|
|
12
|
-
raise(IOStreams::Errors::InvalidHeader, "Format is :psv. Invalid input header: #{row.class.name}")
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
row.split("|")
|
|
16
|
-
end
|
|
17
|
-
|
|
18
6
|
# Returns [Array] the parsed PSV line
|
|
19
7
|
def parse(row)
|
|
20
8
|
return row if row.is_a?(::Array)
|
data/lib/io_streams/tabular.rb
CHANGED
|
@@ -40,10 +40,6 @@ module IOStreams
|
|
|
40
40
|
autoload :Psv, "io_streams/tabular/parser/psv"
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
module Utility
|
|
44
|
-
autoload :CSVRow, "io_streams/tabular/utility/csv_row"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
43
|
attr_reader :format, :header, :parser
|
|
48
44
|
|
|
49
45
|
# Parse a delimited data source.
|
|
@@ -59,11 +55,10 @@ module IOStreams
|
|
|
59
55
|
# format_options: [Hash]
|
|
60
56
|
# Any specialized format specific options. For example, `:fixed` format requires the file definition.
|
|
61
57
|
#
|
|
62
|
-
# columns [Array<String>]
|
|
58
|
+
# columns [Array<String|Symbol>]
|
|
63
59
|
# The header columns when the file does not include a header row.
|
|
64
60
|
# Note:
|
|
65
|
-
#
|
|
66
|
-
# with MongoDB when it converts symbol keys to strings.
|
|
61
|
+
# Column names are converted to strings.
|
|
67
62
|
#
|
|
68
63
|
# allowed_columns [Array<String>]
|
|
69
64
|
# List of columns to allow.
|
|
@@ -91,7 +86,7 @@ module IOStreams
|
|
|
91
86
|
@header = Header.new(**args)
|
|
92
87
|
@format = file_name && format.nil? ? self.class.format_from_file_name(file_name) : format
|
|
93
88
|
@format ||= default_format
|
|
94
|
-
raise(UnknownFormat, "The format cannot be inferred from the file name: #{file_name}") unless @format
|
|
89
|
+
raise(Errors::UnknownFormat, "The format cannot be inferred from the file name: #{file_name}") unless @format
|
|
95
90
|
|
|
96
91
|
klass = self.class.parser_class(@format)
|
|
97
92
|
@parser = format_options ? klass.new(**format_options) : klass.new
|
|
@@ -177,7 +172,7 @@ module IOStreams
|
|
|
177
172
|
# Returns [Symbol] the format removed, or nil if the format was not registered
|
|
178
173
|
#
|
|
179
174
|
# Example:
|
|
180
|
-
#
|
|
175
|
+
# deregister_format(:psv)
|
|
181
176
|
def self.deregister_format(format)
|
|
182
177
|
raise(ArgumentError, "Invalid format #{format.inspect}") unless format.to_s =~ /\A\w+\Z/
|
|
183
178
|
|
|
@@ -200,7 +195,7 @@ module IOStreams
|
|
|
200
195
|
|
|
201
196
|
# Returns the parser class for the registered format.
|
|
202
197
|
def self.parser_class(format)
|
|
203
|
-
@formats[format
|
|
198
|
+
@formats[format&.to_sym] ||
|
|
204
199
|
raise(ArgumentError, "Unknown Tabular Format: #{format.inspect}")
|
|
205
200
|
end
|
|
206
201
|
|
data/lib/io_streams/utils.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "cgi"
|
|
1
2
|
require "uri"
|
|
2
3
|
require "tmpdir"
|
|
3
4
|
module IOStreams
|
|
@@ -15,7 +16,7 @@ module IOStreams
|
|
|
15
16
|
def self.blank?(value)
|
|
16
17
|
return true if value.nil?
|
|
17
18
|
return value !~ /\S/ if value.is_a?(String)
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
value.respond_to?(:empty?) ? value.empty? : !value
|
|
20
21
|
end
|
|
21
22
|
|
|
@@ -27,7 +28,7 @@ module IOStreams
|
|
|
27
28
|
::Dir::Tmpname.create([basename, extension], IOStreams.temp_dir, max_try: MAX_TEMP_FILE_NAME_ATTEMPTS) do |tmpname|
|
|
28
29
|
result = yield(tmpname)
|
|
29
30
|
ensure
|
|
30
|
-
::
|
|
31
|
+
::FileUtils.rm_f(tmpname)
|
|
31
32
|
end
|
|
32
33
|
result
|
|
33
34
|
end
|
data/lib/io_streams/version.rb
CHANGED
data/lib/io_streams/writer.rb
CHANGED
|
@@ -2,22 +2,22 @@ module IOStreams
|
|
|
2
2
|
class Writer
|
|
3
3
|
# When a Writer does not support streams, we copy the stream to a local temp file
|
|
4
4
|
# and then pass that filename in for this reader.
|
|
5
|
-
def self.stream(output_stream,
|
|
5
|
+
def self.stream(output_stream, **args, &block)
|
|
6
6
|
Utils.temp_file_name("iostreams_writer") do |file_name|
|
|
7
|
-
count = file(file_name,
|
|
7
|
+
count = file(file_name, **args, &block)
|
|
8
8
|
::File.open(file_name, "rb") { |source| ::IO.copy_stream(source, output_stream) }
|
|
9
9
|
count
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
# When a Writer supports streams, also allow it to simply support a file
|
|
14
|
-
def self.file(file_name,
|
|
15
|
-
::File.open(file_name, "wb") { |file| stream(file,
|
|
14
|
+
def self.file(file_name, **args, &block)
|
|
15
|
+
::File.open(file_name, "wb") { |file| stream(file, **args, &block) }
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
# For processing by either a file name or an open IO stream.
|
|
19
|
-
def self.open(file_name_or_io, **args, &
|
|
20
|
-
file_name_or_io.is_a?(String) ? file(file_name_or_io, **args, &
|
|
19
|
+
def self.open(file_name_or_io, **args, &)
|
|
20
|
+
file_name_or_io.is_a?(String) ? file(file_name_or_io, **args, &) : stream(file_name_or_io, **args, &)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
attr_reader :output_stream
|
|
@@ -4,7 +4,7 @@ module IOStreams
|
|
|
4
4
|
module Xlsx
|
|
5
5
|
class Reader < IOStreams::Reader
|
|
6
6
|
# Convert a xlsx, or xlsm file into CSV format.
|
|
7
|
-
def self.file(file_name,
|
|
7
|
+
def self.file(file_name, &block)
|
|
8
8
|
# Stream into a temp file as csv
|
|
9
9
|
Utils.temp_file_name("iostreams_csv") do |temp_file_name|
|
|
10
10
|
::File.open(temp_file_name, "wb") { |io| new(file_name).each { |lines| io << lines.to_csv } }
|
|
@@ -1,30 +1,42 @@
|
|
|
1
1
|
module IOStreams
|
|
2
2
|
module Zip
|
|
3
3
|
class Writer < IOStreams::Writer
|
|
4
|
+
# When writing to a file, default the entry name within the zip to the file name
|
|
5
|
+
# without the `.zip` extension, unless an entry name was explicitly supplied.
|
|
6
|
+
def self.file(file_name, zip_file_name: nil, entry_file_name: zip_file_name, &)
|
|
7
|
+
entry_file_name = file_name.to_s[0..-5] if entry_file_name.nil? && file_name.to_s =~ /\.zip\z/i
|
|
8
|
+
|
|
9
|
+
super(file_name, entry_file_name: entry_file_name, &)
|
|
10
|
+
end
|
|
11
|
+
|
|
4
12
|
# Write a single file in Zip format to the supplied output stream
|
|
5
13
|
#
|
|
6
14
|
# Parameters
|
|
7
15
|
# output_stream [IO]
|
|
8
16
|
# Output stream to write to
|
|
9
17
|
#
|
|
10
|
-
# original_file_name [String]
|
|
11
|
-
# Since this is a stream the original file name is used to create the entry_file_name if not supplied
|
|
12
|
-
#
|
|
13
18
|
# entry_file_name: [String]
|
|
14
19
|
# Name of the file entry within the Zip file.
|
|
20
|
+
# Default: "file"
|
|
15
21
|
#
|
|
16
22
|
# The stream supplied to the block only responds to #write
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
#
|
|
24
|
+
# Note:
|
|
25
|
+
# This writer uses `zip_kit` rather than `rubyzip` on purpose. `rubyzip`'s
|
|
26
|
+
# `Zip::OutputStream` requires a seekable output: it seeks back to rewrite each
|
|
27
|
+
# entry's local header with the CRC and sizes once the entry is finished. That
|
|
28
|
+
# means it cannot write directly to a non-seekable destination (S3, SFTP, HTTP,
|
|
29
|
+
# a socket); the output would first have to be spooled to a temporary file and
|
|
30
|
+
# then copied across. `zip_kit` streams to non-seekable outputs by emitting
|
|
31
|
+
# data descriptors instead, so we can write straight to the output stream and
|
|
32
|
+
# avoid the temp file round-trip.
|
|
33
|
+
def self.stream(output_stream, zip_file_name: nil, entry_file_name: zip_file_name)
|
|
22
34
|
entry_file_name ||= "file"
|
|
23
35
|
|
|
24
|
-
Utils.load_soft_dependency("
|
|
36
|
+
Utils.load_soft_dependency("zip_kit", "Zip") unless defined?(ZipKit::Streamer)
|
|
25
37
|
|
|
26
38
|
result = nil
|
|
27
|
-
|
|
39
|
+
ZipKit::Streamer.open(output_stream) do |zip|
|
|
28
40
|
zip.write_deflated_file(entry_file_name) { |io| result = yield(io) }
|
|
29
41
|
end
|
|
30
42
|
result
|
data/lib/iostreams.rb
CHANGED
metadata
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: iostreams
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Reid Morrison
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: csv
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
15
26
|
executables: []
|
|
16
27
|
extensions: []
|
|
17
28
|
extra_rdoc_files: []
|
|
@@ -22,7 +33,6 @@ files:
|
|
|
22
33
|
- lib/io_streams/builder.rb
|
|
23
34
|
- lib/io_streams/bzip2/reader.rb
|
|
24
35
|
- lib/io_streams/bzip2/writer.rb
|
|
25
|
-
- lib/io_streams/deprecated.rb
|
|
26
36
|
- lib/io_streams/encode/reader.rb
|
|
27
37
|
- lib/io_streams/encode/writer.rb
|
|
28
38
|
- lib/io_streams/errors.rb
|
|
@@ -57,7 +67,6 @@ files:
|
|
|
57
67
|
- lib/io_streams/tabular/parser/hash.rb
|
|
58
68
|
- lib/io_streams/tabular/parser/json.rb
|
|
59
69
|
- lib/io_streams/tabular/parser/psv.rb
|
|
60
|
-
- lib/io_streams/tabular/utility/csv_row.rb
|
|
61
70
|
- lib/io_streams/utils.rb
|
|
62
71
|
- lib/io_streams/version.rb
|
|
63
72
|
- lib/io_streams/writer.rb
|
|
@@ -65,59 +74,15 @@ files:
|
|
|
65
74
|
- lib/io_streams/zip/reader.rb
|
|
66
75
|
- lib/io_streams/zip/writer.rb
|
|
67
76
|
- lib/iostreams.rb
|
|
68
|
-
- test/builder_test.rb
|
|
69
|
-
- test/bzip2_reader_test.rb
|
|
70
|
-
- test/bzip2_writer_test.rb
|
|
71
|
-
- test/deprecated_test.rb
|
|
72
|
-
- test/encode_reader_test.rb
|
|
73
|
-
- test/encode_writer_test.rb
|
|
74
|
-
- test/files/embedded_lines_test.csv
|
|
75
|
-
- test/files/multiple_files.zip
|
|
76
|
-
- test/files/spreadsheet.xlsx
|
|
77
|
-
- test/files/test.csv
|
|
78
|
-
- test/files/test.json
|
|
79
|
-
- test/files/test.psv
|
|
80
|
-
- test/files/text file.txt
|
|
81
|
-
- test/files/text.txt
|
|
82
|
-
- test/files/text.txt.bz2
|
|
83
|
-
- test/files/text.txt.gz
|
|
84
|
-
- test/files/text.txt.gz.zip
|
|
85
|
-
- test/files/text.zip
|
|
86
|
-
- test/files/text.zip.gz
|
|
87
|
-
- test/files/unclosed_quote_large_test.csv
|
|
88
|
-
- test/files/unclosed_quote_test.csv
|
|
89
|
-
- test/files/unclosed_quote_test2.csv
|
|
90
|
-
- test/gzip_reader_test.rb
|
|
91
|
-
- test/gzip_writer_test.rb
|
|
92
|
-
- test/io_streams_test.rb
|
|
93
|
-
- test/line_reader_test.rb
|
|
94
|
-
- test/line_writer_test.rb
|
|
95
|
-
- test/minimal_file_reader.rb
|
|
96
|
-
- test/path_test.rb
|
|
97
|
-
- test/paths/file_test.rb
|
|
98
|
-
- test/paths/http_test.rb
|
|
99
|
-
- test/paths/matcher_test.rb
|
|
100
|
-
- test/paths/s3_test.rb
|
|
101
|
-
- test/paths/sftp_test.rb
|
|
102
|
-
- test/pgp_reader_test.rb
|
|
103
|
-
- test/pgp_test.rb
|
|
104
|
-
- test/pgp_writer_test.rb
|
|
105
|
-
- test/record_reader_test.rb
|
|
106
|
-
- test/record_writer_test.rb
|
|
107
|
-
- test/row_reader_test.rb
|
|
108
|
-
- test/row_writer_test.rb
|
|
109
|
-
- test/stream_test.rb
|
|
110
|
-
- test/tabular_test.rb
|
|
111
|
-
- test/test_helper.rb
|
|
112
|
-
- test/utils_test.rb
|
|
113
|
-
- test/xlsx_reader_test.rb
|
|
114
|
-
- test/zip_reader_test.rb
|
|
115
|
-
- test/zip_writer_test.rb
|
|
116
77
|
homepage: https://iostreams.rocketjob.io
|
|
117
78
|
licenses:
|
|
118
79
|
- Apache-2.0
|
|
119
|
-
metadata:
|
|
120
|
-
|
|
80
|
+
metadata:
|
|
81
|
+
bug_tracker_uri: https://github.com/reidmorrison/iostreams/issues
|
|
82
|
+
changelog_uri: https://github.com/reidmorrison/iostreams/blob/v2.0.0/CHANGELOG.md
|
|
83
|
+
documentation_uri: https://iostreams.rocketjob.io
|
|
84
|
+
source_code_uri: https://github.com/reidmorrison/iostreams/tree/v2.0.0
|
|
85
|
+
rubygems_mfa_required: 'true'
|
|
121
86
|
rdoc_options: []
|
|
122
87
|
require_paths:
|
|
123
88
|
- lib
|
|
@@ -125,63 +90,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
125
90
|
requirements:
|
|
126
91
|
- - ">="
|
|
127
92
|
- !ruby/object:Gem::Version
|
|
128
|
-
version: '2
|
|
93
|
+
version: '3.2'
|
|
129
94
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
95
|
requirements:
|
|
131
96
|
- - ">="
|
|
132
97
|
- !ruby/object:Gem::Version
|
|
133
98
|
version: '0'
|
|
134
99
|
requirements: []
|
|
135
|
-
rubygems_version: 3.
|
|
136
|
-
signing_key:
|
|
100
|
+
rubygems_version: 3.6.9
|
|
137
101
|
specification_version: 4
|
|
138
|
-
summary:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
- test/bzip2_reader_test.rb
|
|
142
|
-
- test/bzip2_writer_test.rb
|
|
143
|
-
- test/deprecated_test.rb
|
|
144
|
-
- test/encode_reader_test.rb
|
|
145
|
-
- test/encode_writer_test.rb
|
|
146
|
-
- test/files/embedded_lines_test.csv
|
|
147
|
-
- test/files/multiple_files.zip
|
|
148
|
-
- test/files/spreadsheet.xlsx
|
|
149
|
-
- test/files/test.csv
|
|
150
|
-
- test/files/test.json
|
|
151
|
-
- test/files/test.psv
|
|
152
|
-
- test/files/text file.txt
|
|
153
|
-
- test/files/text.txt
|
|
154
|
-
- test/files/text.txt.bz2
|
|
155
|
-
- test/files/text.txt.gz
|
|
156
|
-
- test/files/text.txt.gz.zip
|
|
157
|
-
- test/files/text.zip
|
|
158
|
-
- test/files/text.zip.gz
|
|
159
|
-
- test/files/unclosed_quote_large_test.csv
|
|
160
|
-
- test/files/unclosed_quote_test.csv
|
|
161
|
-
- test/files/unclosed_quote_test2.csv
|
|
162
|
-
- test/gzip_reader_test.rb
|
|
163
|
-
- test/gzip_writer_test.rb
|
|
164
|
-
- test/io_streams_test.rb
|
|
165
|
-
- test/line_reader_test.rb
|
|
166
|
-
- test/line_writer_test.rb
|
|
167
|
-
- test/minimal_file_reader.rb
|
|
168
|
-
- test/path_test.rb
|
|
169
|
-
- test/paths/file_test.rb
|
|
170
|
-
- test/paths/http_test.rb
|
|
171
|
-
- test/paths/matcher_test.rb
|
|
172
|
-
- test/paths/s3_test.rb
|
|
173
|
-
- test/paths/sftp_test.rb
|
|
174
|
-
- test/pgp_reader_test.rb
|
|
175
|
-
- test/pgp_test.rb
|
|
176
|
-
- test/pgp_writer_test.rb
|
|
177
|
-
- test/record_reader_test.rb
|
|
178
|
-
- test/record_writer_test.rb
|
|
179
|
-
- test/row_reader_test.rb
|
|
180
|
-
- test/row_writer_test.rb
|
|
181
|
-
- test/stream_test.rb
|
|
182
|
-
- test/tabular_test.rb
|
|
183
|
-
- test/test_helper.rb
|
|
184
|
-
- test/utils_test.rb
|
|
185
|
-
- test/xlsx_reader_test.rb
|
|
186
|
-
- test/zip_reader_test.rb
|
|
187
|
-
- test/zip_writer_test.rb
|
|
102
|
+
summary: 'Streaming I/O for Ruby: compression, encryption, format, and storage transparent
|
|
103
|
+
to your code.'
|
|
104
|
+
test_files: []
|