iostreams 0.18.0 → 0.19.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/lib/io_streams/errors.rb +3 -0
- data/lib/io_streams/http/reader.rb +71 -0
- data/lib/io_streams/io_streams.rb +2 -2
- data/lib/io_streams/path.rb +85 -0
- data/lib/io_streams/s3/reader.rb +6 -8
- data/lib/io_streams/version.rb +1 -1
- data/lib/io_streams/xlsx/reader.rb +16 -16
- data/lib/io_streams/zip/reader.rb +5 -16
- data/lib/io_streams/zip/writer.rb +4 -11
- data/lib/iostreams.rb +4 -0
- data/test/http_reader_test.rb +38 -0
- data/test/path_test.rb +74 -0
- data/test/test_helper.rb +5 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 161967be051ed1b82c87f30afd32b760a2e6627cf8e090e978578c7c35aab278
|
4
|
+
data.tar.gz: abb7aab7f5aca8cc0d043ce3820603c86b3227c9db41d07420f3117010bf68af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2172e682359bfe1240669fee5da16f807b5a04b940529c5a7046166d5343e7c80bd20c52f05243b59c72f7cfe57ac288603ac6475e75f413f8f99031f3e1cbd0
|
7
|
+
data.tar.gz: 76923520dfda93c00b4209424496c5324ae7975b59f0f8653578652b540c07a9dd6866890b72c147ab5c968e48879210e3aaa85ab8c8ffbe4b4921524352eb32
|
data/lib/io_streams/errors.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
module IOStreams
|
4
|
+
module HTTP
|
5
|
+
# Read a file using an http get.
|
6
|
+
#
|
7
|
+
# For example:
|
8
|
+
# IOStreams.reader('https://www5.fdic.gov/idasp/Offices2.zip') {|file| puts file.read}
|
9
|
+
#
|
10
|
+
# Direct example without unzipping the above file:
|
11
|
+
# IOStreams::HTTP::Reader.new('https://www5.fdic.gov/idasp/Offices2.zip') {|file| puts file.read}
|
12
|
+
#
|
13
|
+
# Parameters:
|
14
|
+
# uri: [String|URI]
|
15
|
+
# URI of the file to download.
|
16
|
+
# Example:
|
17
|
+
# https://www5.fdic.gov/idasp/Offices2.zip
|
18
|
+
#
|
19
|
+
# :username
|
20
|
+
# When supplied, basic authentication is used with the username and password.
|
21
|
+
# Default: nil
|
22
|
+
#
|
23
|
+
# :password
|
24
|
+
# Password to use use with basic authentication when the username is supplied.
|
25
|
+
#
|
26
|
+
# Notes:
|
27
|
+
# * Since Net::HTTP download only supports a push stream, the data is streamed into a tempfile first.
|
28
|
+
class Reader
|
29
|
+
def self.open(uri, username: nil, password: nil, **args, &block)
|
30
|
+
raise(ArgumentError, 'file_name must be a URI string') unless uri.is_a?(String) || uri.is_a?(URI)
|
31
|
+
handle_redirects(uri, username: username, password: password, **args, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.handle_redirects(uri, username: nil, password: nil, http_redirect_count: 10, **args, &block)
|
35
|
+
uri = URI.parse(uri) unless uri.is_a?(URI)
|
36
|
+
result = nil
|
37
|
+
raise(IOStreams::Errors::CommunicationsFailure, "Too many redirects") if http_redirect_count < 1
|
38
|
+
|
39
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
40
|
+
request = Net::HTTP::Get.new(uri)
|
41
|
+
request.basic_auth(username, password) if username
|
42
|
+
|
43
|
+
http.request(request) do |response|
|
44
|
+
if response.is_a?(Net::HTTPNotFound)
|
45
|
+
raise(IOStreams::Errors::CommunicationsFailure, "Invalid URL: #{uri}")
|
46
|
+
end
|
47
|
+
if response.is_a?(Net::HTTPUnauthorized)
|
48
|
+
raise(IOStreams::Errors::CommunicationsFailure, "Authorization Required: Invalid :username or :password.")
|
49
|
+
end
|
50
|
+
if response.is_a?(Net::HTTPRedirection)
|
51
|
+
new_uri = response['location']
|
52
|
+
return handle_redirects(new_uri, username: username, password: password, http_redirect_count: http_redirect_count - 1, **args, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
raise(IOStreams::Errors::CommunicationsFailure, "Invalid response code: #{response.code}") unless response.is_a?(Net::HTTPSuccess)
|
56
|
+
|
57
|
+
# Since Net::HTTP download only supports a push stream, write it to a tempfile first.
|
58
|
+
IOStreams::Path.temp_file_name('iostreams_http') do |file_name|
|
59
|
+
IOStreams::File::Writer.open(file_name) do |io|
|
60
|
+
response.read_body { |chunk| io.write(chunk) }
|
61
|
+
end
|
62
|
+
# Return a read stream
|
63
|
+
result = IOStreams::File::Reader.open(file_name, &block)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
result
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -585,8 +585,8 @@ module IOStreams
|
|
585
585
|
# sftp://hostname/path/file_name
|
586
586
|
# s3://bucket/key
|
587
587
|
register_scheme(nil, IOStreams::File::Reader, IOStreams::File::Writer)
|
588
|
-
|
589
|
-
|
588
|
+
register_scheme(:http, IOStreams::HTTP::Reader, nil)
|
589
|
+
register_scheme(:https, IOStreams::HTTP::Reader, nil)
|
590
590
|
# register_scheme(:sftp, IOStreams::SFTP::Reader, IOStreams::SFTP::Writer)
|
591
591
|
register_scheme(:s3, IOStreams::S3::Reader, IOStreams::S3::Writer)
|
592
592
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module IOStreams
|
5
|
+
#
|
6
|
+
# NOTE: This is a proof of concept class and will change significantly.
|
7
|
+
# I.e. Dont use it yet.
|
8
|
+
#
|
9
|
+
class Path
|
10
|
+
attr_reader :root, :relative
|
11
|
+
|
12
|
+
# Return named root path
|
13
|
+
def self.[](root)
|
14
|
+
@roots[root.to_sym] || raise(ArgumentError, "Unknown root: #{root.inspect}")
|
15
|
+
end
|
16
|
+
|
17
|
+
# Add a named root path
|
18
|
+
def self.add_root(root, path)
|
19
|
+
@roots[root.to_sym] = path.dup.freeze
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.roots
|
23
|
+
@roots.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
# Yields the path to a temporary file_name.
|
27
|
+
#
|
28
|
+
# File is deleted upon completion if present.
|
29
|
+
def self.temp_file_name(basename, extension = '')
|
30
|
+
result = nil
|
31
|
+
::Dir::Tmpname.create([basename, extension]) do |tmpname|
|
32
|
+
begin
|
33
|
+
result = yield(tmpname)
|
34
|
+
ensure
|
35
|
+
::File.unlink(tmpname) if ::File.exist?(tmpname)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
result
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(*elements, root: :default)
|
42
|
+
@root = root.to_sym
|
43
|
+
root_path = self.class[@root]
|
44
|
+
if elements.empty?
|
45
|
+
@relative = ''
|
46
|
+
@path = root_path
|
47
|
+
else
|
48
|
+
@relative = ::File.join(*elements).freeze
|
49
|
+
if @relative.start_with?(root_path)
|
50
|
+
@path = @relative
|
51
|
+
@relative = @path[root_path.size + 1..-1].freeze
|
52
|
+
else
|
53
|
+
@path = ::File.join(root_path, @relative).freeze
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_s
|
59
|
+
@path
|
60
|
+
end
|
61
|
+
|
62
|
+
# Creates the entire path excluding the file_name.
|
63
|
+
def mkpath
|
64
|
+
path = ::File.dirname(@path)
|
65
|
+
FileUtils.mkdir_p(path) unless ::File.exist?(path)
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def exist?
|
70
|
+
::File.exist?(@path)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Delete the file.
|
74
|
+
#
|
75
|
+
# Note: Only the file is removed, not any of the parent paths.
|
76
|
+
def delete
|
77
|
+
::File.unlink(@path)
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
@roots = {}
|
84
|
+
end
|
85
|
+
end
|
data/lib/io_streams/s3/reader.rb
CHANGED
@@ -13,15 +13,13 @@ module IOStreams
|
|
13
13
|
|
14
14
|
begin
|
15
15
|
# Since S3 download only supports a push stream, write it to a tempfile first.
|
16
|
-
|
17
|
-
|
16
|
+
IOStreams::Path.temp_file_name('iostreams_s3') do |file_name|
|
17
|
+
args[:response_target] = file_name
|
18
|
+
object.get(args)
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
block.call(temp_file)
|
23
|
-
ensure
|
24
|
-
temp_file.delete if temp_file
|
20
|
+
# Return a read stream
|
21
|
+
IOStreams::File::Reader.open(file_name, &block)
|
22
|
+
end
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
data/lib/io_streams/version.rb
CHANGED
@@ -4,24 +4,24 @@ module IOStreams
|
|
4
4
|
module Xlsx
|
5
5
|
class Reader
|
6
6
|
# Convert a xlsx, or xlsm file or stream into CSV format.
|
7
|
-
def self.open(file_name_or_io, _ = nil)
|
8
|
-
if file_name_or_io.is_a?(String)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
file_name = temp_file.to_path
|
7
|
+
def self.open(file_name_or_io, _ = nil, &block)
|
8
|
+
return extract_csv(file_name_or_io, &block) if file_name_or_io.is_a?(String)
|
9
|
+
|
10
|
+
# Creek gem can only work against a file, not a stream, so create temp file.
|
11
|
+
IOStreams::Path.temp_file_name('iostreams_xlsx') do |temp_file_name|
|
12
|
+
IOStreams.copy(file_name_or_io, temp_file_name, target_options: {streams: []})
|
13
|
+
extract_csv(temp_file_name, &block)
|
15
14
|
end
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
# Convert the spreadsheet to csv in a tempfile
|
18
|
+
def self.extract_csv(file_name, &block)
|
19
|
+
IOStreams::Path.temp_file_name('iostreams_csv') do |temp_file_name|
|
20
|
+
IOStreams::File::Writer.open(temp_file_name) do |io|
|
21
|
+
new(file_name).each { |lines| io << lines.to_csv }
|
22
|
+
end
|
23
|
+
IOStreams::File::Reader.open(temp_file_name, &block)
|
24
|
+
end
|
25
25
|
end
|
26
26
|
|
27
27
|
def initialize(file_name)
|
@@ -12,7 +12,7 @@ module IOStreams
|
|
12
12
|
# puts data
|
13
13
|
# end
|
14
14
|
# end
|
15
|
-
def self.open(file_name_or_io,
|
15
|
+
def self.open(file_name_or_io, _ = nil, &block)
|
16
16
|
if !defined?(JRuby) && !defined?(::Zip)
|
17
17
|
# MRI needs Ruby Zip, since it only has native support for GZip
|
18
18
|
begin
|
@@ -25,21 +25,10 @@ module IOStreams
|
|
25
25
|
# File name supplied
|
26
26
|
return read_file(file_name_or_io, &block) unless IOStreams.reader_stream?(file_name_or_io)
|
27
27
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
temp_file.binmode
|
33
|
-
file_name = temp_file.to_path
|
34
|
-
|
35
|
-
# Stream zip stream into temp file
|
36
|
-
::File.open(file_name, 'wb') do |file|
|
37
|
-
IOStreams.copy(file_name_or_io, file, buffer_size: buffer_size)
|
38
|
-
end
|
39
|
-
|
40
|
-
read_file(file_name, &block)
|
41
|
-
ensure
|
42
|
-
temp_file.delete if temp_file
|
28
|
+
# ZIP can only work against a file, not a stream, so create temp file.
|
29
|
+
IOStreams::Path.temp_file_name('iostreams_zip') do |temp_file_name|
|
30
|
+
IOStreams.copy(file_name_or_io, temp_file_name, target_options: {streams: []})
|
31
|
+
read_file(temp_file_name, &block)
|
43
32
|
end
|
44
33
|
end
|
45
34
|
|
@@ -38,17 +38,10 @@ module IOStreams
|
|
38
38
|
# File name supplied
|
39
39
|
return write_file(file_name_or_io, zip_file_name, &block) unless IOStreams.writer_stream?(file_name_or_io)
|
40
40
|
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
temp_file.binmode
|
46
|
-
write_file(temp_file.to_path, zip_file_name, &block)
|
47
|
-
|
48
|
-
# Stream temp file into output stream
|
49
|
-
IOStreams.copy(temp_file, file_name_or_io, buffer_size: buffer_size)
|
50
|
-
ensure
|
51
|
-
temp_file.delete if temp_file
|
41
|
+
# ZIP can only work against a file, not a stream, so create temp file.
|
42
|
+
IOStreams::Path.temp_file_name('iostreams_zip') do |temp_file_name|
|
43
|
+
write_file(temp_file_name, zip_file_name, &block)
|
44
|
+
IOStreams.copy(temp_file_name, file_name_or_io, source_options: {streams: []})
|
52
45
|
end
|
53
46
|
end
|
54
47
|
|
data/lib/iostreams.rb
CHANGED
@@ -15,6 +15,10 @@ module IOStreams
|
|
15
15
|
autoload :Reader, 'io_streams/gzip/reader'
|
16
16
|
autoload :Writer, 'io_streams/gzip/writer'
|
17
17
|
end
|
18
|
+
module HTTP
|
19
|
+
autoload :Reader, 'io_streams/http/reader'
|
20
|
+
end
|
21
|
+
autoload :Path, 'io_streams/path'
|
18
22
|
autoload :Pgp, 'io_streams/pgp'
|
19
23
|
autoload :S3, 'io_streams/s3'
|
20
24
|
module SFTP
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class HTTPReaderTest < Minitest::Test
|
4
|
+
describe IOStreams::HTTP::Reader do
|
5
|
+
let :uri do
|
6
|
+
"http://example.com/index.html?count=10"
|
7
|
+
end
|
8
|
+
|
9
|
+
let :ssl_uri do
|
10
|
+
"https://example.com/index.html?count=10"
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '.open' do
|
14
|
+
it 'reads http' do
|
15
|
+
result = IOStreams::HTTP::Reader.open(uri) do |io|
|
16
|
+
io.read
|
17
|
+
end
|
18
|
+
assert_includes result, "<html>"
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'reads https' do
|
22
|
+
result = IOStreams::HTTP::Reader.open(ssl_uri) do |io|
|
23
|
+
io.read
|
24
|
+
end
|
25
|
+
assert_includes result, "<html>"
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'does not support streams' do
|
29
|
+
assert_raises ArgumentError do
|
30
|
+
io = StringIO.new
|
31
|
+
IOStreams::HTTP::Reader.open(io) do |http_io|
|
32
|
+
http_io.read
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/test/path_test.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
module IOStreams
|
4
|
+
class PathTest < Minitest::Test
|
5
|
+
describe IOStreams::Path do
|
6
|
+
describe '.root' do
|
7
|
+
it 'return default path' do
|
8
|
+
path = ::File.expand_path(::File.join(__dir__, '../tmp/default'))
|
9
|
+
assert_equal path, IOStreams::Path[:default]
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'return downloads path' do
|
13
|
+
path = ::File.expand_path(::File.join(__dir__, '../tmp/downloads'))
|
14
|
+
assert_equal path, IOStreams::Path[:downloads]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '.to_s' do
|
19
|
+
it 'returns path' do
|
20
|
+
assert_equal IOStreams::Path[:default], IOStreams::Path.new.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'adds path to root' do
|
24
|
+
assert_equal ::File.join(IOStreams::Path[:default], 'test'), IOStreams::Path.new('test').to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'adds paths to root' do
|
28
|
+
assert_equal ::File.join(IOStreams::Path[:default], 'test', 'second', 'third'), IOStreams::Path.new('test', 'second', 'third').to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns path and filename' do
|
32
|
+
path = ::File.join(IOStreams::Path[:default], 'file.xls')
|
33
|
+
assert_equal path, IOStreams::Path.new('file.xls').to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'adds path to root and filename' do
|
37
|
+
path = ::File.join(IOStreams::Path[:default], 'test', 'file.xls')
|
38
|
+
assert_equal path, IOStreams::Path.new('test', 'file.xls').to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'adds paths to root' do
|
42
|
+
path = ::File.join(IOStreams::Path[:default], 'test', 'second', 'third', 'file.xls')
|
43
|
+
assert_equal path, IOStreams::Path.new('test', 'second', 'third', 'file.xls').to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'return path as sent in when full path' do
|
47
|
+
path = ::File.join(IOStreams::Path[:default], 'file.xls')
|
48
|
+
assert_equal path, IOStreams::Path.new(path).to_s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '.mkpath' do
|
53
|
+
it 'makes root' do
|
54
|
+
path = IOStreams::Path.new('test.xls')
|
55
|
+
assert_equal path, path.mkpath
|
56
|
+
assert ::File.exist?(IOStreams::Path.new.to_s)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'makes root with path' do
|
60
|
+
path = IOStreams::Path.new('test', 'test.xls')
|
61
|
+
assert_equal path, path.mkpath
|
62
|
+
assert ::File.exist?(IOStreams::Path.new('test').to_s)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'makes root with paths' do
|
66
|
+
path = IOStreams::Path.new('test', 'second', 'third', 'test.xls')
|
67
|
+
assert_equal path, path.mkpath
|
68
|
+
assert ::File.exist?(IOStreams::Path.new('test', 'second', 'third').to_s)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -32,3 +32,8 @@ unless IOStreams::Pgp.has_key?(email: 'receiver@example.org')
|
|
32
32
|
puts 'Generating test PGP key: receiver@example.org'
|
33
33
|
IOStreams::Pgp.generate_key(name: 'Receiver', email: 'receiver@example.org', passphrase: 'receiver_passphrase', key_length: 2048)
|
34
34
|
end
|
35
|
+
|
36
|
+
# Test paths
|
37
|
+
root = File.expand_path(File.join(__dir__, '../tmp'))
|
38
|
+
IOStreams::Path.add_root(:default, File.join(root, 'default'))
|
39
|
+
IOStreams::Path.add_root(:downloads, File.join(root, 'downloads'))
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iostreams
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.19.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reid Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-08-
|
11
|
+
date: 2019-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -43,9 +43,11 @@ files:
|
|
43
43
|
- lib/io_streams/file/writer.rb
|
44
44
|
- lib/io_streams/gzip/reader.rb
|
45
45
|
- lib/io_streams/gzip/writer.rb
|
46
|
+
- lib/io_streams/http/reader.rb
|
46
47
|
- lib/io_streams/io_streams.rb
|
47
48
|
- lib/io_streams/line/reader.rb
|
48
49
|
- lib/io_streams/line/writer.rb
|
50
|
+
- lib/io_streams/path.rb
|
49
51
|
- lib/io_streams/pgp.rb
|
50
52
|
- lib/io_streams/pgp/reader.rb
|
51
53
|
- lib/io_streams/pgp/writer.rb
|
@@ -93,9 +95,11 @@ files:
|
|
93
95
|
- test/files/unclosed_quote_test.csv
|
94
96
|
- test/gzip_reader_test.rb
|
95
97
|
- test/gzip_writer_test.rb
|
98
|
+
- test/http_reader_test.rb
|
96
99
|
- test/io_streams_test.rb
|
97
100
|
- test/line_reader_test.rb
|
98
101
|
- test/line_writer_test.rb
|
102
|
+
- test/path_test.rb
|
99
103
|
- test/pgp_reader_test.rb
|
100
104
|
- test/pgp_test.rb
|
101
105
|
- test/pgp_writer_test.rb
|
@@ -145,6 +149,7 @@ test_files:
|
|
145
149
|
- test/file_reader_test.rb
|
146
150
|
- test/record_reader_test.rb
|
147
151
|
- test/s3_writer_test.rb
|
152
|
+
- test/http_reader_test.rb
|
148
153
|
- test/pgp_writer_test.rb
|
149
154
|
- test/line_writer_test.rb
|
150
155
|
- test/row_reader_test.rb
|
@@ -165,6 +170,7 @@ test_files:
|
|
165
170
|
- test/test_helper.rb
|
166
171
|
- test/file_writer_test.rb
|
167
172
|
- test/tabular_test.rb
|
173
|
+
- test/path_test.rb
|
168
174
|
- test/pgp_test.rb
|
169
175
|
- test/io_streams_test.rb
|
170
176
|
- test/record_writer_test.rb
|