iostreams 0.20.3 → 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/lib/io_streams/bzip2/reader.rb +9 -21
  3. data/lib/io_streams/bzip2/writer.rb +9 -21
  4. data/lib/io_streams/deprecated.rb +217 -0
  5. data/lib/io_streams/encode/reader.rb +12 -16
  6. data/lib/io_streams/encode/writer.rb +9 -13
  7. data/lib/io_streams/errors.rb +6 -6
  8. data/lib/io_streams/gzip/reader.rb +7 -14
  9. data/lib/io_streams/gzip/writer.rb +7 -15
  10. data/lib/io_streams/io_streams.rb +182 -524
  11. data/lib/io_streams/line/reader.rb +9 -9
  12. data/lib/io_streams/line/writer.rb +10 -11
  13. data/lib/io_streams/path.rb +190 -0
  14. data/lib/io_streams/paths/file.rb +176 -0
  15. data/lib/io_streams/paths/http.rb +92 -0
  16. data/lib/io_streams/paths/matcher.rb +61 -0
  17. data/lib/io_streams/paths/s3.rb +269 -0
  18. data/lib/io_streams/paths/sftp.rb +99 -0
  19. data/lib/io_streams/pgp.rb +47 -19
  20. data/lib/io_streams/pgp/reader.rb +20 -28
  21. data/lib/io_streams/pgp/writer.rb +24 -46
  22. data/lib/io_streams/reader.rb +28 -0
  23. data/lib/io_streams/record/reader.rb +20 -16
  24. data/lib/io_streams/record/writer.rb +28 -28
  25. data/lib/io_streams/row/reader.rb +22 -26
  26. data/lib/io_streams/row/writer.rb +29 -28
  27. data/lib/io_streams/stream.rb +400 -0
  28. data/lib/io_streams/streams.rb +125 -0
  29. data/lib/io_streams/symmetric_encryption/reader.rb +5 -13
  30. data/lib/io_streams/symmetric_encryption/writer.rb +16 -15
  31. data/lib/io_streams/tabular/header.rb +9 -3
  32. data/lib/io_streams/tabular/parser/array.rb +8 -3
  33. data/lib/io_streams/tabular/parser/csv.rb +6 -2
  34. data/lib/io_streams/tabular/parser/hash.rb +4 -1
  35. data/lib/io_streams/tabular/parser/json.rb +3 -1
  36. data/lib/io_streams/tabular/parser/psv.rb +3 -1
  37. data/lib/io_streams/tabular/utility/csv_row.rb +9 -8
  38. data/lib/io_streams/utils.rb +22 -0
  39. data/lib/io_streams/version.rb +1 -1
  40. data/lib/io_streams/writer.rb +28 -0
  41. data/lib/io_streams/xlsx/reader.rb +7 -19
  42. data/lib/io_streams/zip/reader.rb +7 -26
  43. data/lib/io_streams/zip/writer.rb +21 -38
  44. data/lib/iostreams.rb +15 -15
  45. data/test/bzip2_reader_test.rb +3 -3
  46. data/test/bzip2_writer_test.rb +3 -3
  47. data/test/deprecated_test.rb +123 -0
  48. data/test/encode_reader_test.rb +3 -3
  49. data/test/encode_writer_test.rb +6 -6
  50. data/test/gzip_reader_test.rb +2 -2
  51. data/test/gzip_writer_test.rb +3 -3
  52. data/test/io_streams_test.rb +43 -136
  53. data/test/line_reader_test.rb +20 -20
  54. data/test/line_writer_test.rb +3 -3
  55. data/test/path_test.rb +30 -28
  56. data/test/paths/file_test.rb +206 -0
  57. data/test/paths/http_test.rb +34 -0
  58. data/test/paths/matcher_test.rb +111 -0
  59. data/test/paths/s3_test.rb +207 -0
  60. data/test/pgp_reader_test.rb +8 -8
  61. data/test/pgp_writer_test.rb +13 -13
  62. data/test/record_reader_test.rb +5 -5
  63. data/test/record_writer_test.rb +4 -4
  64. data/test/row_reader_test.rb +5 -5
  65. data/test/row_writer_test.rb +6 -6
  66. data/test/stream_test.rb +116 -0
  67. data/test/streams_test.rb +255 -0
  68. data/test/utils_test.rb +20 -0
  69. data/test/xlsx_reader_test.rb +3 -3
  70. data/test/zip_reader_test.rb +12 -12
  71. data/test/zip_writer_test.rb +5 -5
  72. metadata +33 -45
  73. data/lib/io_streams/base_path.rb +0 -72
  74. data/lib/io_streams/file/path.rb +0 -58
  75. data/lib/io_streams/file/reader.rb +0 -12
  76. data/lib/io_streams/file/writer.rb +0 -22
  77. data/lib/io_streams/http/reader.rb +0 -71
  78. data/lib/io_streams/s3.rb +0 -26
  79. data/lib/io_streams/s3/path.rb +0 -40
  80. data/lib/io_streams/s3/reader.rb +0 -28
  81. data/lib/io_streams/s3/writer.rb +0 -85
  82. data/lib/io_streams/sftp/reader.rb +0 -67
  83. data/lib/io_streams/sftp/writer.rb +0 -68
  84. data/test/base_path_test.rb +0 -35
  85. data/test/file_path_test.rb +0 -97
  86. data/test/file_reader_test.rb +0 -33
  87. data/test/file_writer_test.rb +0 -50
  88. data/test/http_reader_test.rb +0 -38
  89. data/test/s3_reader_test.rb +0 -41
  90. data/test/s3_writer_test.rb +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92d4f1b2dd506273b8e9cde6990775d416cfe8ab9fd6f0dd03811b134bacec73
4
- data.tar.gz: 30f4b7dd513c9a6b806df6b478c9fc1997b30436f6ceff99788178d1972cae31
3
+ metadata.gz: 158fef0e14167719cd27b7b1cb0445bfb08403a3afc4490fad74a0e0fc9ab67b
4
+ data.tar.gz: b1f3db75a4773591507706befa66122204ffda1642136c79427671a4bf240605
5
5
  SHA512:
6
- metadata.gz: 81709e604218a4d2d764e3d237a48293bc35beffc50c17a1a2ba524f7b4ac8311d94b605f476f9e958eb259f87c2d4b16cc734b71ed7b6f66276ca4f262ccbcd
7
- data.tar.gz: 2d3a4e9e9bd11018d6eee4baecdd80bede728f4aca4c0e9b050c6045cda7e4e75f6a6dc6595021bc30a6419bfbb39cbe020ec0885d913c2c8531f731e9e87f4e
6
+ metadata.gz: 556a898a859c9447822cb0d3aeea58ce6d839536d43fe3ef46fdf94fb1794d50d596da713fd6eef4203ef84ed94790ad8d69581d54c6a167bc9cea57e4d6b976
7
+ data.tar.gz: 7c38374f8ec37252a3b5428472235cf44a3a6379b5190776d766f447f339f16f3f85b69713c77592601466f82eac998c227de8136cecc64f82081e00f540314b
@@ -1,28 +1,16 @@
1
1
  module IOStreams
2
2
  module Bzip2
3
- class Reader
4
- # Read from a Bzip2 file or stream, decompressing the contents as it is read
5
- def self.open(file_name_or_io, **args, &block)
6
- begin
7
- require 'rbzip2' unless defined?(RBzip2)
8
- rescue LoadError => e
9
- raise(LoadError, "Please install the 'rbzip2' gem for Bzip2 streaming support. #{e.message}")
10
- end
3
+ class Reader < IOStreams::Reader
4
+ # Read from a Bzip2 stream, decompressing the contents as it is read
5
+ def self.stream(input_stream, **_args)
6
+ Utils.load_dependency('rbzip2', 'Bzip2') unless defined?(RBzip2)
11
7
 
12
- if IOStreams.reader_stream?(file_name_or_io)
13
- begin
14
- io = RBzip2.default_adapter::Decompressor.new(file_name_or_io)
15
- block.call(io)
16
- ensure
17
- io.close if io && (io.respond_to?(:closed?) && !io.closed?)
18
- end
19
- else
20
- ::File.open(file_name_or_io, 'rb') do |file|
21
- io = RBzip2.default_adapter::Decompressor.new(file)
22
- block.call(io)
23
- end
8
+ begin
9
+ io = RBzip2.default_adapter::Decompressor.new(input_stream)
10
+ yield io
11
+ ensure
12
+ io&.close
24
13
  end
25
-
26
14
  end
27
15
  end
28
16
  end
@@ -1,27 +1,15 @@
1
1
  module IOStreams
2
2
  module Bzip2
3
- class Writer
4
- # Write to a file / stream, compressing with Bzip2
5
- def self.open(file_name_or_io, **args, &block)
6
- begin
7
- require 'rbzip2' unless defined?(RBzip2)
8
- rescue LoadError => e
9
- raise(LoadError, "Please install the 'rbzip2' gem for Bzip2 streaming support. #{e.message}")
10
- end
3
+ class Writer < IOStreams::Writer
4
+ # Write to a stream, compressing with Bzip2
5
+ def self.stream(input_stream, original_file_name: nil, **_args)
6
+ Utils.load_dependency('rbzip2', 'Bzip2') unless defined?(RBzip2)
11
7
 
12
- if IOStreams.writer_stream?(file_name_or_io)
13
- begin
14
- io = RBzip2.default_adapter::Compressor.new(file_name_or_io)
15
- block.call(io)
16
- ensure
17
- io.close
18
- end
19
- else
20
- IOStreams::File::Writer.open(file_name_or_io) do |file|
21
- io = RBzip2.default_adapter::Compressor.new(file)
22
- block.call(io)
23
- io.close
24
- end
8
+ begin
9
+ io = RBzip2.default_adapter::Compressor.new(input_stream)
10
+ yield io
11
+ ensure
12
+ io&.close
25
13
  end
26
14
  end
27
15
  end
@@ -0,0 +1,217 @@
1
+ module IOStreams
2
+ UTF8_ENCODING = Encoding.find('UTF-8').freeze
3
+ BINARY_ENCODING = Encoding.find('BINARY').freeze
4
+
5
+ # Deprecated IOStreams from v0.x. Do not use, will be removed soon.
6
+ module Deprecated
7
+ def self.included(base)
8
+ base.extend ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ # DEPRECATED. Use `#path` or `#io`
14
+ # Examples:
15
+ # IOStreams.path("data.zip").reader { |f| f.read(100) }
16
+ #
17
+ # IOStreams.path(file_name).option(:encode, encoding: "BINARY").reader { |f| f.read(100) }
18
+ #
19
+ # io_stream = StringIO.new("Hello World")
20
+ # IOStreams.stream(io_stream).reader { |f| f.read(100) }
21
+ def reader(file_name_or_io, streams: nil, file_name: nil, encoding: nil, encode_cleaner: nil, encode_replace: nil, &block)
22
+ path = build_path(file_name_or_io, streams: streams, file_name: file_name, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
23
+ path.reader(&block)
24
+ end
25
+
26
+ # DEPRECATED
27
+ def each_line(file_name_or_io, encoding: nil, encode_cleaner: nil, encode_replace: nil, **args, &block)
28
+ path = build_path(file_name_or_io, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
29
+ path.each_line(**args, &block)
30
+ end
31
+
32
+ # DEPRECATED
33
+ def each_row(file_name_or_io, encoding: nil, encode_cleaner: nil, encode_replace: nil, **args, &block)
34
+ path = build_path(file_name_or_io, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
35
+ path.each_row(**args, &block)
36
+ end
37
+
38
+ # DEPRECATED
39
+ def each_record(file_name_or_io, encoding: nil, encode_cleaner: nil, encode_replace: nil, **args, &block)
40
+ path = build_path(file_name_or_io, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
41
+ path.each_record(**args, &block)
42
+ end
43
+
44
+ # DEPRECATED. Use `#path` or `#io`
45
+ # Examples:
46
+ # IOStreams.path("data.zip").writer { |f| f.write("Hello World") }
47
+ #
48
+ # IOStreams.path(file_name).option(:encode, encoding: "BINARY").writer { |f| f.write("Hello World") }
49
+ #
50
+ # io_stream = StringIO.new("Hello World")
51
+ # IOStreams.stream(io_stream).writer { |f| f.write("Hello World") }
52
+ def writer(file_name_or_io, streams: nil, file_name: nil, encoding: nil, encode_cleaner: nil, encode_replace: nil, &block)
53
+ path = build_path(file_name_or_io, streams: streams, file_name: file_name, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
54
+ path.writer(&block)
55
+ end
56
+
57
+ # DEPRECATED
58
+ def line_writer(file_name_or_io, streams: nil, file_name: nil, encoding: nil, encode_cleaner: nil, encode_replace: nil, **args, &block)
59
+ path = build_path(file_name_or_io, streams: streams, file_name: file_name, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
60
+ path.line_writer(**args, &block)
61
+ end
62
+
63
+ # DEPRECATED
64
+ def row_writer(file_name_or_io, streams: nil, file_name: nil, encoding: nil, encode_cleaner: nil, encode_replace: nil, **args, &block)
65
+ path = build_path(file_name_or_io, streams: streams, file_name: file_name, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
66
+ path.row_writer(**args, &block)
67
+ end
68
+
69
+ # DEPRECATED
70
+ def record_writer(file_name_or_io, streams: nil, file_name: nil, encoding: nil, encode_cleaner: nil, encode_replace: nil, **args, &block)
71
+ path = build_path(file_name_or_io, streams: streams, file_name: file_name, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
72
+ path.record_writer(**args, &block)
73
+ end
74
+
75
+ # Copies the source file/stream to the target file/stream.
76
+ # Returns [Integer] the number of bytes copied
77
+ #
78
+ # Example: Copy between 2 files
79
+ # IOStreams.copy('a.csv', 'b.csv')
80
+ #
81
+ # Example: Read content from a Xlsx file and write it out in CSV form.
82
+ # IOStreams.copy('a.xlsx', 'b.csv')
83
+ #
84
+ # Example:
85
+ # # Read content from a JSON file and write it out in CSV form.
86
+ # #
87
+ # # The output header for the CSV file is extracted from the first row in the JSON file.
88
+ # # If the first JSON row does not contain all the column names then they will be ignored
89
+ # # for the rest of the file.
90
+ # IOStreams.copy('a.json', 'b.csv')
91
+ #
92
+ # Example:
93
+ # # Read a PSV file and write out a CSV file from it.
94
+ # IOStreams.copy('a.psv', 'b.csv')
95
+ #
96
+ # Example:
97
+ # # Copy between 2 files, encrypting the target file with Symmetric Encryption
98
+ # # Since the target file_name already includes `.enc` in the filename, it is automatically
99
+ # # encrypted.
100
+ # IOStreams.copy('a.csv', 'b.csv.enc')
101
+ #
102
+ # Example:
103
+ # # Copy between 2 files, encrypting the target file with Symmetric Encryption
104
+ # # Since the target file_name does not include `.enc` in the filename, to encrypt it
105
+ # # the encryption stream is added.
106
+ # IOStreams.copy('a.csv', 'b', target_options: [:enc])
107
+ #
108
+ # Example:
109
+ # # Copy between 2 files, encrypting the target file with Symmetric Encryption
110
+ # # Since the target file_name does not include `.enc` in the filename, to encrypt it
111
+ # # the encryption stream is added, along with the optional compression option.
112
+ # IOStreams.copy('a.csv', 'b', target_options: [enc: { compress: true }])
113
+ #
114
+ # Example:
115
+ # # Create a pgp encrypted file.
116
+ # # For PGP Encryption the recipients email address is required.
117
+ # IOStreams.copy('a.xlsx', 'b.csv.pgp', target_options: [:csv, pgp: { recipient_email: 'user@nospam.org' }])
118
+ #
119
+ # Example: Copy between 2 existing streams
120
+ # IOStreams.reader('a.csv') do |source_stream|
121
+ # IOStreams.writer('b.csv.enc') do |target_stream|
122
+ # IOStreams.copy(source_stream, target_stream)
123
+ # end
124
+ # end
125
+ #
126
+ # Example:
127
+ # # Copy between 2 csv files, reducing the number of columns present and encrypting the
128
+ # # target file with Symmetric Encryption
129
+ # output_headers = %w[name address]
130
+ # IOStreams.copy(
131
+ # 'a.csv',
132
+ # 'b.csv.enc',
133
+ # target_options: [csv:{headers: output_headers}, enc: {compress: true}]
134
+ # )
135
+ #
136
+ # Example:
137
+ # # Copy a locally encrypted file to AWS S3.
138
+ # # Decrypts the file, then compresses it with gzip as it is being streamed into S3.
139
+ # # Useful for when the entire bucket is encrypted on S3.
140
+ # IOStreams.copy('a.csv.enc', 's3://my_bucket/b.csv.gz')
141
+ def copy(source_file_name_or_io, target_file_name_or_io, buffer_size: nil, source_options: {}, target_options: {})
142
+ # TODO: prevent stream conversions when reader and writer streams are the same!
143
+ reader(source_file_name_or_io, **source_options) do |source_stream|
144
+ writer(target_file_name_or_io, **target_options) do |target_stream|
145
+ IO.copy_stream(source_stream, target_stream)
146
+ end
147
+ end
148
+ end
149
+
150
+ # DEPRECATED
151
+ def reader_stream?(file_name_or_io)
152
+ file_name_or_io.respond_to?(:read)
153
+ end
154
+
155
+ # DEPRECATED
156
+ def writer_stream?(file_name_or_io)
157
+ file_name_or_io.respond_to?(:write)
158
+ end
159
+
160
+ # DEPRECATED. Use Path#compressed?
161
+ def compressed?(file_name)
162
+ Path.new(file_name).compressed?
163
+ end
164
+
165
+ # DEPRECATED. Use Path#encrypted?
166
+ def encrypted?(file_name)
167
+ Path.new(file_name).encrypted?
168
+ end
169
+
170
+ # DEPRECATED
171
+ def line_reader(file_name_or_io, streams: nil, file_name: nil, encoding: nil, encode_cleaner: nil, encode_replace: nil, **args, &block)
172
+ path = build_path(file_name_or_io, streams: streams, file_name: file_name, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
173
+ path.line_reader(**args, &block)
174
+ end
175
+
176
+ # DEPRECATED
177
+ def row_reader(file_name_or_io, streams: nil, file_name: nil, encoding: nil, encode_cleaner: nil, encode_replace: nil, **args, &block)
178
+ path = build_path(file_name_or_io, streams: streams, file_name: file_name, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
179
+ path.line_reader(**args, &block)
180
+ end
181
+
182
+ # DEPRECATED
183
+ def record_reader(file_name_or_io, streams: nil, file_name: nil, encoding: nil, encode_cleaner: nil, encode_replace: nil, **args, &block)
184
+ path = build_path(file_name_or_io, streams: streams, file_name: file_name, encoding: encoding, encode_cleaner: encode_cleaner, encode_replace: encode_replace)
185
+ path.record_reader(**args, &block)
186
+ end
187
+
188
+ private
189
+
190
+ def build_path(file_name_or_io, streams: nil, file_name: nil, encoding: nil, encode_cleaner: nil, encode_replace: nil)
191
+ path = new(file_name_or_io)
192
+ path.file_name(file_name) if file_name
193
+
194
+ apply_old_style_streams(path, streams) if streams
195
+
196
+ if encoding || encode_cleaner || encode_replace
197
+ path.option_or_stream(:encode, encoding: encoding, cleaner: encode_cleaner, replace: encode_replace)
198
+ end
199
+
200
+ path
201
+ end
202
+
203
+ # Applies old form streams to the path
204
+ def apply_old_style_streams(path, streams)
205
+ if streams.is_a?(Symbol)
206
+ path.stream(streams)
207
+ elsif streams.is_a?(Array)
208
+ streams.each { |stream| apply_old_style_streams(path, stream) }
209
+ elsif streams.is_a?(Hash)
210
+ streams.each_pair { |stream, options| path.stream(stream, options) }
211
+ else
212
+ raise ArgumentError, "Invalid old style stream supplied: #{params.inspect}"
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -1,22 +1,18 @@
1
1
  module IOStreams
2
2
  module Encode
3
- class Reader
3
+ class Reader < IOStreams::Reader
4
4
  attr_reader :encoding, :cleaner
5
5
 
6
6
  NOT_PRINTABLE = Regexp.compile(/[^[:print:]|\r|\n]/).freeze
7
7
  # Builtin strip options to apply after encoding the read data.
8
8
  CLEANSE_RULES = {
9
9
  # Strips all non printable characters
10
- printable: -> (data) { data.gsub!(NOT_PRINTABLE, '') || data }
11
- }
10
+ printable: ->(data) { data.gsub!(NOT_PRINTABLE, '') || data }
11
+ }.freeze
12
12
 
13
13
  # Read a line at a time from a file or stream
14
- def self.open(file_name_or_io, **args)
15
- if file_name_or_io.is_a?(String)
16
- IOStreams::File::Reader.open(file_name_or_io) { |io| yield new(io, **args) }
17
- else
18
- yield new(file_name_or_io, **args)
19
- end
14
+ def self.stream(input_stream, original_file_name: nil, **args)
15
+ yield new(input_stream, **args)
20
16
  end
21
17
 
22
18
  # Apply encoding conversion when reading a stream.
@@ -33,26 +29,26 @@ module IOStreams
33
29
  # Etc.
34
30
  # Default: 'UTF-8'
35
31
  #
36
- # encode_replace: [String]
32
+ # replace: [String]
37
33
  # The character to replace with when a character cannot be converted to the target encoding.
38
34
  # nil: Don't replace any invalid characters. Encoding::UndefinedConversionError is raised.
39
35
  # Default: nil
40
36
  #
41
- # encode_cleaner: [nil|symbol|Proc]
37
+ # cleaner: [nil|symbol|Proc]
42
38
  # Cleanse data read from the input stream.
43
39
  # nil: No cleansing
44
40
  # :printable Cleanse all non-printable characters except \r and \n
45
41
  # Proc/lambda Proc to call after every read to cleanse the data
46
42
  # Default: nil
47
- def initialize(input_stream, encoding: 'UTF-8', encode_cleaner: nil, encode_replace: nil)
48
- @input_stream = input_stream
49
- @cleaner = self.class.extract_cleaner(encode_cleaner)
43
+ def initialize(input_stream, encoding: 'UTF-8', cleaner: nil, replace: nil)
44
+ super(input_stream)
50
45
 
46
+ @cleaner = self.class.extract_cleaner(cleaner)
51
47
  @encoding = encoding.nil? || encoding.is_a?(Encoding) ? encoding : Encoding.find(encoding)
52
- @encoding_options = encode_replace.nil? ? {} : {invalid: :replace, undef: :replace, replace: encode_replace}
48
+ @encoding_options = replace.nil? ? {} : {invalid: :replace, undef: :replace, replace: replace}
53
49
 
54
50
  # More efficient read buffering only supported when the input stream `#read` method supports it.
55
- if encode_replace.nil? && !@input_stream.method(:read).arity.between?(0, 1)
51
+ if replace.nil? && !@input_stream.method(:read).arity.between?(0, 1)
56
52
  @read_cache_buffer = ''.encode(@encoding)
57
53
  else
58
54
  @read_cache_buffer = nil
@@ -1,15 +1,11 @@
1
1
  module IOStreams
2
2
  module Encode
3
- class Writer
3
+ class Writer < IOStreams::Writer
4
4
  attr_reader :encoding, :cleaner
5
5
 
6
6
  # Write a line at a time to a file or stream
7
- def self.open(file_name_or_io, **args)
8
- if file_name_or_io.is_a?(String)
9
- IOStreams::File::Writer.open(file_name_or_io) { |io| yield new(io, **args) }
10
- else
11
- yield new(file_name_or_io, **args)
12
- end
7
+ def self.stream(input_stream, original_file_name: nil, **args)
8
+ yield new(input_stream, **args)
13
9
  end
14
10
 
15
11
  # A delimited stream writer that will write to the supplied output stream
@@ -27,23 +23,23 @@ module IOStreams
27
23
  # Etc.
28
24
  # Default: 'UTF-8'
29
25
  #
30
- # encode_replace: [String]
26
+ # replace: [String]
31
27
  # The character to replace with when a character cannot be converted to the target encoding.
32
28
  # nil: Don't replace any invalid characters. Encoding::UndefinedConversionError is raised.
33
29
  # Default: nil
34
30
  #
35
- # encode_cleaner: [nil|symbol|Proc]
31
+ # cleaner: [nil|symbol|Proc]
36
32
  # Cleanse data read from the input stream.
37
33
  # nil: No cleansing
38
34
  # :printable Cleanse all non-printable characters except \r and \n
39
35
  # Proc/lambda Proc to call after every read to cleanse the data
40
36
  # Default: nil
41
- def initialize(output_stream, encoding: 'UTF-8', encode_cleaner: nil, encode_replace: nil)
42
- @output_stream = output_stream
43
- @cleaner = ::IOStreams::Encode::Reader.send(:extract_cleaner, encode_cleaner)
37
+ def initialize(output_stream, encoding: 'UTF-8', cleaner: nil, replace: nil)
38
+ super(output_stream)
44
39
 
40
+ @cleaner = ::IOStreams::Encode::Reader.send(:extract_cleaner, cleaner)
45
41
  @encoding = encoding.nil? || encoding.is_a?(Encoding) ? encoding : Encoding.find(encoding)
46
- @encoding_options = encode_replace.nil? ? {} : {invalid: :replace, undef: :replace, replace: encode_replace}
42
+ @encoding_options = replace.nil? ? {} : {invalid: :replace, undef: :replace, replace: replace}
47
43
  end
48
44
 
49
45
  # Write a line to the output stream
@@ -1,22 +1,22 @@
1
1
  module IOStreams
2
2
  module Errors
3
- class Error < StandardError;
3
+ class Error < StandardError
4
4
  end
5
5
 
6
- class InvalidHeader < Error;
6
+ class InvalidHeader < Error
7
7
  end
8
8
 
9
- class MissingHeader < Error;
9
+ class MissingHeader < Error
10
10
  end
11
11
 
12
- class TypeMismatch < Error;
12
+ class TypeMismatch < Error
13
13
  end
14
14
 
15
- class CommunicationsFailure < Error;
15
+ class CommunicationsFailure < Error
16
16
  end
17
17
 
18
18
  # When the specified delimiter is not found in the supplied stream / file
19
- class DelimiterNotFound < Error;
19
+ class DelimiterNotFound < Error
20
20
  end
21
21
  end
22
22
  end
@@ -1,20 +1,13 @@
1
1
  module IOStreams
2
2
  module Gzip
3
- class Reader
4
- # Read from a gzip file or stream, decompressing the contents as it is read
5
- def self.open(file_name_or_io, **args, &block)
6
- unless IOStreams.reader_stream?(file_name_or_io)
7
- ::Zlib::GzipReader.open(file_name_or_io, &block)
8
- else
9
- begin
10
- io = ::Zlib::GzipReader.new(file_name_or_io)
11
- block.call(io)
12
- ensure
13
- io.close if io && (io.respond_to?(:closed?) && !io.closed?)
14
- end
15
- end
3
+ class Reader < IOStreams::Reader
4
+ # Read from a gzip stream, decompressing the contents as it is read
5
+ def self.stream(input_stream, original_file_name: nil, &block)
6
+ io = ::Zlib::GzipReader.new(input_stream)
7
+ block.call(io)
8
+ ensure
9
+ io&.close
16
10
  end
17
-
18
11
  end
19
12
  end
20
13
  end