iostreams 1.11.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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -13
  3. data/Rakefile +52 -0
  4. data/docs/CLAUDE.md +9 -0
  5. data/docs/config.md +157 -0
  6. data/docs/copy_files.md +75 -0
  7. data/docs/extensions.md +111 -0
  8. data/docs/formats.md +188 -0
  9. data/docs/index.md +388 -0
  10. data/docs/path.md +652 -0
  11. data/docs/pgp.md +436 -0
  12. data/docs/streams.md +337 -0
  13. data/docs/tutorial.md +483 -0
  14. data/docs/upgrading.md +217 -0
  15. data/lib/io_streams/builder.rb +71 -11
  16. data/lib/io_streams/bzip2/reader.rb +25 -2
  17. data/lib/io_streams/bzip2/writer.rb +26 -2
  18. data/lib/io_streams/encode/reader.rb +6 -2
  19. data/lib/io_streams/encode/writer.rb +9 -5
  20. data/lib/io_streams/errors.rb +4 -0
  21. data/lib/io_streams/gzip/reader.rb +5 -1
  22. data/lib/io_streams/gzip/writer.rb +11 -2
  23. data/lib/io_streams/io_streams.rb +156 -20
  24. data/lib/io_streams/line/reader.rb +9 -4
  25. data/lib/io_streams/line/writer.rb +1 -1
  26. data/lib/io_streams/path.rb +117 -8
  27. data/lib/io_streams/paths/file.rb +57 -11
  28. data/lib/io_streams/paths/http.rb +123 -9
  29. data/lib/io_streams/paths/matcher.rb +3 -3
  30. data/lib/io_streams/paths/s3.rb +69 -18
  31. data/lib/io_streams/paths/sftp/net_ssh.rb +104 -0
  32. data/lib/io_streams/paths/sftp.rb +103 -64
  33. data/lib/io_streams/pgp/reader.rb +63 -10
  34. data/lib/io_streams/pgp/writer.rb +111 -30
  35. data/lib/io_streams/pgp.rb +256 -71
  36. data/lib/io_streams/reader.rb +14 -5
  37. data/lib/io_streams/record/reader.rb +75 -6
  38. data/lib/io_streams/record/writer.rb +3 -4
  39. data/lib/io_streams/row/reader.rb +1 -1
  40. data/lib/io_streams/row/writer.rb +1 -1
  41. data/lib/io_streams/stream.rb +48 -37
  42. data/lib/io_streams/symmetric_encryption/reader.rb +6 -2
  43. data/lib/io_streams/symmetric_encryption/writer.rb +8 -4
  44. data/lib/io_streams/tabular/header.rb +49 -10
  45. data/lib/io_streams/tabular/parser/array.rb +0 -10
  46. data/lib/io_streams/tabular/parser/base.rb +10 -0
  47. data/lib/io_streams/tabular/parser/csv.rb +9 -36
  48. data/lib/io_streams/tabular/parser/fixed.rb +8 -6
  49. data/lib/io_streams/tabular/parser/psv.rb +6 -14
  50. data/lib/io_streams/tabular.rb +5 -10
  51. data/lib/io_streams/utils.rb +34 -2
  52. data/lib/io_streams/version.rb +1 -1
  53. data/lib/io_streams/writer.rb +16 -7
  54. data/lib/io_streams/xlsx/reader.rb +6 -2
  55. data/lib/io_streams/zip/reader.rb +4 -0
  56. data/lib/io_streams/zip/writer.rb +26 -10
  57. data/lib/iostreams.rb +0 -1
  58. metadata +46 -112
  59. data/lib/io_streams/deprecated.rb +0 -216
  60. data/lib/io_streams/tabular/utility/csv_row.rb +0 -105
  61. data/test/builder_test.rb +0 -311
  62. data/test/bzip2_reader_test.rb +0 -27
  63. data/test/bzip2_writer_test.rb +0 -56
  64. data/test/deprecated_test.rb +0 -121
  65. data/test/encode_reader_test.rb +0 -51
  66. data/test/encode_writer_test.rb +0 -90
  67. data/test/files/embedded_lines_test.csv +0 -7
  68. data/test/files/multiple_files.zip +0 -0
  69. data/test/files/spreadsheet.xlsx +0 -0
  70. data/test/files/test.csv +0 -4
  71. data/test/files/test.json +0 -3
  72. data/test/files/test.psv +0 -4
  73. data/test/files/text file.txt +0 -3
  74. data/test/files/text.txt +0 -3
  75. data/test/files/text.txt.bz2 +0 -0
  76. data/test/files/text.txt.gz +0 -0
  77. data/test/files/text.txt.gz.zip +0 -0
  78. data/test/files/text.zip +0 -0
  79. data/test/files/text.zip.gz +0 -0
  80. data/test/files/unclosed_quote_large_test.csv +0 -1658
  81. data/test/files/unclosed_quote_test.csv +0 -4
  82. data/test/files/unclosed_quote_test2.csv +0 -3
  83. data/test/gzip_reader_test.rb +0 -27
  84. data/test/gzip_writer_test.rb +0 -52
  85. data/test/io_streams_test.rb +0 -132
  86. data/test/line_reader_test.rb +0 -325
  87. data/test/line_writer_test.rb +0 -59
  88. data/test/minimal_file_reader.rb +0 -25
  89. data/test/path_test.rb +0 -55
  90. data/test/paths/file_test.rb +0 -213
  91. data/test/paths/http_test.rb +0 -34
  92. data/test/paths/matcher_test.rb +0 -120
  93. data/test/paths/s3_test.rb +0 -220
  94. data/test/paths/sftp_test.rb +0 -106
  95. data/test/pgp_reader_test.rb +0 -46
  96. data/test/pgp_test.rb +0 -267
  97. data/test/pgp_writer_test.rb +0 -130
  98. data/test/record_reader_test.rb +0 -60
  99. data/test/record_writer_test.rb +0 -82
  100. data/test/row_reader_test.rb +0 -35
  101. data/test/row_writer_test.rb +0 -56
  102. data/test/stream_test.rb +0 -577
  103. data/test/tabular_test.rb +0 -338
  104. data/test/test_helper.rb +0 -40
  105. data/test/utils_test.rb +0 -20
  106. data/test/xlsx_reader_test.rb +0 -37
  107. data/test/zip_reader_test.rb +0 -53
  108. data/test/zip_writer_test.rb +0 -48
@@ -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..-1]) if column.key
96
+ hash[column.key] = column.parse(line[index..]) if column.key
97
97
  break
98
98
  end
99
99
 
@@ -143,12 +143,13 @@ module IOStreams
143
143
 
144
144
  class Column
145
145
  TYPES = %i[string integer float].freeze
146
+ LINE_BREAK = /\r\n|\r|\n/
146
147
 
147
148
  attr_reader :key, :size, :type, :decimals
148
149
 
149
150
  def initialize(size:, key: nil, type: :string, decimals: 2)
150
151
  @key = key
151
- @size = (size == :remainder || size == "remainder") ? -1 : size.to_i
152
+ @size = [:remainder, "remainder"].include?(size) ? -1 : size.to_i
152
153
  @type = type.to_sym
153
154
  @decimals = decimals
154
155
 
@@ -167,9 +168,9 @@ module IOStreams
167
168
  when :string
168
169
  stripped_value
169
170
  when :integer
170
- stripped_value.length.zero? ? nil : value.to_i
171
+ stripped_value.empty? ? nil : value.to_i
171
172
  when :float
172
- stripped_value.length.zero? ? nil : value.to_f
173
+ stripped_value.empty? ? nil : value.to_f
173
174
  else
174
175
  raise(Errors::InvalidLayout, "Unsupported type: #{type.inspect}")
175
176
  end
@@ -179,7 +180,8 @@ module IOStreams
179
180
  formatted =
180
181
  case type
181
182
  when :string
182
- value = value.to_s
183
+ # Replace line breaks with a space so that a value cannot add records.
184
+ value = value.to_s.gsub(LINE_BREAK, " ")
183
185
  return value if size == -1
184
186
 
185
187
  format(truncate ? "%-#{size}.#{size}s" : "%-#{size}s", value)
@@ -3,18 +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
- # 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
-
6
+ LINE_BREAK = /\r\n|\r|\n/
18
7
  # Returns [Array] the parsed PSV line
19
8
  def parse(row)
20
9
  return row if row.is_a?(::Array)
@@ -24,11 +13,14 @@ module IOStreams
24
13
  row.split("|")
25
14
  end
26
15
 
27
- # Return the supplied array as a single line JSON string.
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.
28
20
  def render(row, header)
29
21
  array = header.to_array(row)
30
22
  cleansed_array = array.collect do |i|
31
- i.is_a?(String) ? i.tr("|", ":") : i
23
+ i.is_a?(String) ? i.tr("|", ":").gsub(LINE_BREAK, " ") : i
32
24
  end
33
25
  cleansed_array.join("|")
34
26
  end
@@ -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
- # It is recommended to keep all columns as strings to avoid any issues when persistence
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
- # register_extension(:xls)
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.nil? ? nil : format.to_sym] ||
198
+ @formats[format&.to_sym] ||
204
199
  raise(ArgumentError, "Unknown Tabular Format: #{format.inspect}")
205
200
  end
206
201
 
@@ -1,3 +1,4 @@
1
+ require "cgi"
1
2
  require "uri"
2
3
  require "tmpdir"
3
4
  module IOStreams
@@ -11,11 +12,22 @@ module IOStreams
11
12
  raise(LoadError, "Please install the gem '#{gem_name}' to support #{stream_type}. #{e.message}")
12
13
  end
13
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
+
14
26
  # Helper method: Returns [true|false] if a value is blank?
15
27
  def self.blank?(value)
16
28
  return true if value.nil?
17
29
  return value !~ /\S/ if value.is_a?(String)
18
-
30
+
19
31
  value.respond_to?(:empty?) ? value.empty? : !value
20
32
  end
21
33
 
@@ -27,11 +39,31 @@ module IOStreams
27
39
  ::Dir::Tmpname.create([basename, extension], IOStreams.temp_dir, max_try: MAX_TEMP_FILE_NAME_ATTEMPTS) do |tmpname|
28
40
  result = yield(tmpname)
29
41
  ensure
30
- ::File.unlink(tmpname) if ::File.exist?(tmpname)
42
+ ::FileUtils.rm_f(tmpname)
31
43
  end
32
44
  result
33
45
  end
34
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
+
35
67
  class URI
36
68
  attr_reader :scheme, :hostname, :path, :user, :password, :port, :query
37
69
 
@@ -1,3 +1,3 @@
1
1
  module IOStreams
2
- VERSION = "1.11.0".freeze
2
+ VERSION = "2.1.0".freeze
3
3
  end
@@ -1,23 +1,32 @@
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
- def self.stream(output_stream, original_file_name: nil, **args, &block)
6
- Utils.temp_file_name("iostreams_writer") do |file_name|
7
- count = file(file_name, original_file_name: original_file_name, **args, &block)
14
+ def self.stream(output_stream, **args, &block)
15
+ Utils.private_temp_file("iostreams_writer") do |file_name|
16
+ count = file(file_name, **args, &block)
8
17
  ::File.open(file_name, "rb") { |source| ::IO.copy_stream(source, output_stream) }
9
18
  count
10
19
  end
11
20
  end
12
21
 
13
22
  # When a Writer supports streams, also allow it to simply support a file
14
- def self.file(file_name, original_file_name: file_name, **args, &block)
15
- ::File.open(file_name, "wb") { |file| stream(file, original_file_name: original_file_name, **args, &block) }
23
+ def self.file(file_name, **args, &block)
24
+ ::File.open(file_name, "wb") { |file| stream(file, **args, &block) }
16
25
  end
17
26
 
18
27
  # For processing by either a file name or an open IO stream.
19
- def self.open(file_name_or_io, **args, &block)
20
- file_name_or_io.is_a?(String) ? file(file_name_or_io, **args, &block) : stream(file_name_or_io, **args, &block)
28
+ def self.open(file_name_or_io, **args, &)
29
+ file_name_or_io.is_a?(String) ? file(file_name_or_io, **args, &) : stream(file_name_or_io, **args, &)
21
30
  end
22
31
 
23
32
  attr_reader :output_stream
@@ -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
- def self.file(file_name, original_file_name: file_name, &block)
11
+ def self.file(file_name, &block)
8
12
  # Stream into a temp file as csv
9
- Utils.temp_file_name("iostreams_csv") do |temp_file_name|
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,30 +1,46 @@
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
+
8
+ # When writing to a file, default the entry name within the zip to the file name
9
+ # without the `.zip` extension, unless an entry name was explicitly supplied.
10
+ def self.file(file_name, zip_file_name: nil, entry_file_name: zip_file_name, &)
11
+ entry_file_name = file_name.to_s[0..-5] if entry_file_name.nil? && file_name.to_s =~ /\.zip\z/i
12
+
13
+ super(file_name, entry_file_name: entry_file_name, &)
14
+ end
15
+
4
16
  # Write a single file in Zip format to the supplied output stream
5
17
  #
6
18
  # Parameters
7
19
  # output_stream [IO]
8
20
  # Output stream to write to
9
21
  #
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
22
  # entry_file_name: [String]
14
23
  # Name of the file entry within the Zip file.
24
+ # Default: "file"
15
25
  #
16
26
  # The stream supplied to the block only responds to #write
17
- def self.stream(output_stream, original_file_name: nil, zip_file_name: nil, entry_file_name: zip_file_name)
18
- # Default the name of the file within the zip to the supplied file_name without the zip extension
19
- if entry_file_name.nil? && original_file_name && (original_file_name =~ /\.(zip)\z/i)
20
- entry_file_name = original_file_name.to_s[0..-5]
21
- end
27
+ #
28
+ # Note:
29
+ # This writer uses `zip_kit` rather than `rubyzip` on purpose. `rubyzip`'s
30
+ # `Zip::OutputStream` requires a seekable output: it seeks back to rewrite each
31
+ # entry's local header with the CRC and sizes once the entry is finished. That
32
+ # means it cannot write directly to a non-seekable destination (S3, SFTP, HTTP,
33
+ # a socket); the output would first have to be spooled to a temporary file and
34
+ # then copied across. `zip_kit` streams to non-seekable outputs by emitting
35
+ # data descriptors instead, so we can write straight to the output stream and
36
+ # avoid the temp file round-trip.
37
+ def self.stream(output_stream, zip_file_name: nil, entry_file_name: zip_file_name)
22
38
  entry_file_name ||= "file"
23
39
 
24
- Utils.load_soft_dependency("zip_tricks", "Zip") unless defined?(ZipTricks::Streamer)
40
+ Utils.load_soft_dependency("zip_kit", "Zip") unless defined?(ZipKit::Streamer)
25
41
 
26
42
  result = nil
27
- ZipTricks::Streamer.open(output_stream) do |zip|
43
+ ZipKit::Streamer.open(output_stream) do |zip|
28
44
  zip.write_deflated_file(entry_file_name) { |io| result = yield(io) }
29
45
  end
30
46
  result
data/lib/iostreams.rb CHANGED
@@ -63,5 +63,4 @@ module IOStreams
63
63
  autoload :Writer, "io_streams/zip/writer"
64
64
  end
65
65
  end
66
- require "io_streams/deprecated"
67
66
  require "io_streams/io_streams"
metadata CHANGED
@@ -1,17 +1,32 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iostreams
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.11.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-09-30 00:00:00.000000000 Z
12
- dependencies: []
13
- description:
14
- email:
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'
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.
15
30
  executables: []
16
31
  extensions: []
17
32
  extra_rdoc_files: []
@@ -19,10 +34,20 @@ files:
19
34
  - LICENSE
20
35
  - README.md
21
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
22
48
  - lib/io_streams/builder.rb
23
49
  - lib/io_streams/bzip2/reader.rb
24
50
  - lib/io_streams/bzip2/writer.rb
25
- - lib/io_streams/deprecated.rb
26
51
  - lib/io_streams/encode/reader.rb
27
52
  - lib/io_streams/encode/writer.rb
28
53
  - lib/io_streams/errors.rb
@@ -37,6 +62,7 @@ files:
37
62
  - lib/io_streams/paths/matcher.rb
38
63
  - lib/io_streams/paths/s3.rb
39
64
  - lib/io_streams/paths/sftp.rb
65
+ - lib/io_streams/paths/sftp/net_ssh.rb
40
66
  - lib/io_streams/pgp.rb
41
67
  - lib/io_streams/pgp/reader.rb
42
68
  - lib/io_streams/pgp/writer.rb
@@ -57,7 +83,6 @@ files:
57
83
  - lib/io_streams/tabular/parser/hash.rb
58
84
  - lib/io_streams/tabular/parser/json.rb
59
85
  - lib/io_streams/tabular/parser/psv.rb
60
- - lib/io_streams/tabular/utility/csv_row.rb
61
86
  - lib/io_streams/utils.rb
62
87
  - lib/io_streams/version.rb
63
88
  - lib/io_streams/writer.rb
@@ -65,59 +90,16 @@ files:
65
90
  - lib/io_streams/zip/reader.rb
66
91
  - lib/io_streams/zip/writer.rb
67
92
  - 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
- homepage: https://iostreams.rocketjob.io
93
+ homepage: https://iostreams.reidmorrison.com
117
94
  licenses:
118
95
  - Apache-2.0
119
- metadata: {}
120
- post_install_message:
96
+ metadata:
97
+ bug_tracker_uri: https://github.com/reidmorrison/iostreams/issues
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
102
+ rubygems_mfa_required: 'true'
121
103
  rdoc_options: []
122
104
  require_paths:
123
105
  - lib
@@ -125,63 +107,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
107
  requirements:
126
108
  - - ">="
127
109
  - !ruby/object:Gem::Version
128
- version: '2.5'
110
+ version: '3.2'
129
111
  required_rubygems_version: !ruby/object:Gem::Requirement
130
112
  requirements:
131
113
  - - ">="
132
114
  - !ruby/object:Gem::Version
133
115
  version: '0'
134
116
  requirements: []
135
- rubygems_version: 3.4.19
136
- signing_key:
117
+ rubygems_version: 3.6.9
137
118
  specification_version: 4
138
- summary: Input and Output streaming for Ruby.
139
- test_files:
140
- - test/builder_test.rb
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
119
+ summary: 'Streaming I/O for Ruby: compression, encryption, file format, and storage
120
+ location transparent to your code.'
121
+ test_files: []