iop 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +7 -0
- data/CHANGES.md +7 -0
- data/README.md +6 -6
- data/lib/iop.rb +67 -6
- data/lib/iop/digest.rb +1 -1
- data/lib/iop/file.rb +10 -35
- data/lib/iop/net/ftp.rb +5 -4
- data/lib/iop/net/sftp.rb +176 -0
- data/lib/iop/securerandom.rb +1 -1
- metadata +14 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e00c4ba2a50b1aa72e48cfb31653ee740059b737d9ca6139fc4ba3bf4f1ebbbd
|
4
|
+
data.tar.gz: 643526a878056882bdaf5c840e36cfa2068912850692a53878a70c3e612727a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 336b3d9df782302ea3d4391683ccddcf662da77b59a324971158b7f1404eaf08547f552394e2a055f842c02176ace16b37f62a37950cbd6fcb4eca8f0fa11b25
|
7
|
+
data.tar.gz: 752c73de778d5ef811a2874ff80b755b8172c78f07f5be7ad5ab4df1a97a6ab94643625b08ea7fcec375144083f7823d540b786efdfb5ed1c7f27e8b95f8bcec
|
data/.yardopts
ADDED
data/CHANGES.md
CHANGED
data/README.md
CHANGED
@@ -13,9 +13,9 @@ Consider the example:
|
|
13
13
|
(FileReader.new('input.dat') | GzipCompressor.new | DigestComputer.new(MD5.new) | FileWriter.new('output.dat.gz')).process!
|
14
14
|
```
|
15
15
|
|
16
|
-
The above snippet reads input file and compresses it into the
|
16
|
+
The above snippet reads input file and compresses it into the Gzip-compatible output file simultaneously computing the MD5 hash of compressed data being written.
|
17
17
|
|
18
|
-
The next snippet presents the incremental pipeline construction capability - a feature not easily implementable with the standard Ruby I/O
|
18
|
+
The next snippet presents the incremental pipeline construction capability - a feature not easily implementable with the standard Ruby I/O block nesting.
|
19
19
|
|
20
20
|
```ruby
|
21
21
|
# Incremental pipeline construction example
|
@@ -25,7 +25,7 @@ pipe |= FileWriter.new('output')
|
|
25
25
|
pipe.process!
|
26
26
|
```
|
27
27
|
|
28
|
-
Here the
|
28
|
+
Here the Gzip compression is made optional and is thrown in depending on external condition.
|
29
29
|
|
30
30
|
## Features
|
31
31
|
|
@@ -35,7 +35,7 @@ The following capabilities are currently implemented:
|
|
35
35
|
- IO or local file reading/writing
|
36
36
|
- FTP file reading/writing
|
37
37
|
- Digest computing
|
38
|
-
-
|
38
|
+
- Gzip/Zlib (de)compression
|
39
39
|
- Zstd (de)compression
|
40
40
|
- Symmetric cipher (de,en)cryption
|
41
41
|
- Random data generation
|
@@ -61,7 +61,7 @@ include IOP
|
|
61
61
|
|
62
62
|
```ruby
|
63
63
|
pipe = StringSplitter.new('Greetings from IOP', 10)
|
64
|
-
pipe |= GzipCompressor.new | (
|
64
|
+
pipe |= GzipCompressor.new | (d = DigestComputer.new(MD5.new))
|
65
65
|
pipe |= FileWriter.new('output.gz')
|
66
66
|
```
|
67
67
|
|
@@ -78,7 +78,7 @@ The IOP instances do normally perform self-cleanup operations, such as closing f
|
|
78
78
|
- The variable-bound instances can be then examined.
|
79
79
|
|
80
80
|
```ruby
|
81
|
-
puts digest.hexdigest
|
81
|
+
puts d.digest.hexdigest
|
82
82
|
```
|
83
83
|
|
84
84
|
For further information refer to IOP documentation.
|
data/lib/iop.rb
CHANGED
@@ -74,7 +74,7 @@
|
|
74
74
|
module IOP
|
75
75
|
|
76
76
|
|
77
|
-
VERSION = '0.
|
77
|
+
VERSION = '0.2.0'
|
78
78
|
|
79
79
|
|
80
80
|
# Default read block size in bytes for adapters which don't have this parameter externally imposed.
|
@@ -191,9 +191,71 @@ module IOP
|
|
191
191
|
end
|
192
192
|
|
193
193
|
|
194
|
+
#
|
195
|
+
# Abstract reader class for seekable streams which can read with blocks of specified size.
|
196
|
+
#
|
197
|
+
# Sequentially reads specified number of bytes starting at specified byte offset.
|
198
|
+
#
|
199
|
+
# @since 0.2
|
200
|
+
#
|
201
|
+
class RandomAccessReader
|
202
|
+
|
203
|
+
include Feed
|
204
|
+
|
205
|
+
# Sets up the reader parameters.
|
206
|
+
#
|
207
|
+
# @param size [Integer] total number of bytes to read; +nil+ value instructs to read until end-of-data is reached
|
208
|
+
#
|
209
|
+
# @param offset [Integer] offset in bytes from the stream start to seek to; +nil+ value means no seeking is performed
|
210
|
+
#
|
211
|
+
# @param block_size [Integer] size of blocks to read data with
|
212
|
+
def initialize(size: nil, offset: nil, block_size: DEFAULT_BLOCK_SIZE)
|
213
|
+
@block_size = size.nil? ? block_size : IOP.min(size, block_size)
|
214
|
+
@left = @size = size
|
215
|
+
@offset = offset
|
216
|
+
end
|
217
|
+
|
218
|
+
def process!
|
219
|
+
seek! unless @offset.nil?
|
220
|
+
buffer = IOP.allocate_string(@block_size)
|
221
|
+
loop do
|
222
|
+
read_size = @size.nil? ? @block_size : IOP.min(@left, @block_size)
|
223
|
+
break if read_size.zero?
|
224
|
+
if (data = read!(read_size, buffer)).nil?
|
225
|
+
if @size.nil?
|
226
|
+
break
|
227
|
+
else
|
228
|
+
raise EOFError, INSUFFICIENT_DATA
|
229
|
+
end
|
230
|
+
else
|
231
|
+
unless @left.nil?
|
232
|
+
@left -= data.size
|
233
|
+
raise IOError, EXTRA_DATA if @left < 0
|
234
|
+
end
|
235
|
+
end
|
236
|
+
process(data) unless data.size.zero?
|
237
|
+
end
|
238
|
+
process
|
239
|
+
end
|
240
|
+
|
241
|
+
protected
|
242
|
+
|
243
|
+
# @abstract
|
244
|
+
def seek!() end
|
245
|
+
remove_method :seek!
|
246
|
+
|
247
|
+
# @abstract
|
248
|
+
def read!(read_size, buffer) nil end
|
249
|
+
remove_method :read!
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
|
194
254
|
#
|
195
255
|
# @private
|
196
256
|
#
|
257
|
+
# Feed implementation for sequential streams which can not seek or request for the block size to read.
|
258
|
+
#
|
197
259
|
# @note a class including this module must implement the {#next_data} method.
|
198
260
|
#
|
199
261
|
# @since 0.1
|
@@ -234,14 +296,13 @@ module IOP
|
|
234
296
|
process
|
235
297
|
end
|
236
298
|
|
237
|
-
|
238
|
-
|
299
|
+
protected
|
300
|
+
|
239
301
|
# Returns the data portion of non-zero size or +nil+ on EOF.
|
240
302
|
#
|
303
|
+
# @abstract
|
241
304
|
# @return [String] data chunk recently read or +nil+
|
242
|
-
def next_data
|
243
|
-
raise
|
244
|
-
end
|
305
|
+
def next_data; nil end
|
245
306
|
remove_method :next_data
|
246
307
|
|
247
308
|
end
|
data/lib/iop/digest.rb
CHANGED
@@ -7,7 +7,7 @@ module IOP
|
|
7
7
|
|
8
8
|
#
|
9
9
|
# Filter class to compute digest of the data being passed through.
|
10
|
-
# It can be used with digest computing classes from +
|
10
|
+
# It can be used with digest computing classes from the standard Ruby +Digest::+ and +OpenSSL::Digest::+ modules.
|
11
11
|
#
|
12
12
|
# ### Use case: generate 1024 bytes of random data and compute and print MD5 hash sum of it.
|
13
13
|
#
|
data/lib/iop/file.rb
CHANGED
@@ -26,48 +26,23 @@ module IOP
|
|
26
26
|
#
|
27
27
|
# @since 0.1
|
28
28
|
#
|
29
|
-
class IOReader
|
30
|
-
|
31
|
-
include Feed
|
29
|
+
class IOReader < RandomAccessReader
|
32
30
|
|
33
31
|
# Creates class instance.
|
34
32
|
#
|
35
33
|
# @param io [IO] +IO+ instance to read data from
|
36
34
|
#
|
37
|
-
# @param
|
38
|
-
|
39
|
-
|
40
|
-
#
|
41
|
-
# @param block_size [Integer] size of blocks to read data with
|
42
|
-
def initialize(io, size: nil, offset: nil, block_size: DEFAULT_BLOCK_SIZE)
|
43
|
-
@block_size = size.nil? ? block_size : IOP.min(size, block_size)
|
44
|
-
@left = @size = size
|
45
|
-
@offset = offset
|
35
|
+
# @param options [Hash] keyword arguments passed to {RandomAccessReader} constructor
|
36
|
+
def initialize(io, **options)
|
37
|
+
super(**options)
|
46
38
|
@io = io
|
47
39
|
end
|
48
40
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
break if read_size.zero?
|
55
|
-
if @io.read(read_size, data).nil?
|
56
|
-
if @size.nil?
|
57
|
-
break
|
58
|
-
else
|
59
|
-
raise EOFError, INSUFFICIENT_DATA
|
60
|
-
end
|
61
|
-
else
|
62
|
-
unless @left.nil?
|
63
|
-
@left -= data.size
|
64
|
-
raise IOError, EXTRA_DATA if @left < 0
|
65
|
-
end
|
66
|
-
end
|
67
|
-
process(data) unless data.size.zero?
|
68
|
-
end
|
69
|
-
process
|
70
|
-
end
|
41
|
+
private
|
42
|
+
|
43
|
+
def seek!() @io.seek(@offset) end
|
44
|
+
|
45
|
+
def read!(read_size, data) @io.read(read_size, data) end
|
71
46
|
|
72
47
|
end
|
73
48
|
|
@@ -94,7 +69,7 @@ module IOP
|
|
94
69
|
#
|
95
70
|
# @param mode [String] open mode for the file; refer to {File} for details
|
96
71
|
#
|
97
|
-
# @param options [Hash]
|
72
|
+
# @param options [Hash] keyword parameters passed to {IOReader} constructor
|
98
73
|
def initialize(file, mode: 'rb', **options)
|
99
74
|
super(nil, **options)
|
100
75
|
@file = file
|
data/lib/iop/net/ftp.rb
CHANGED
@@ -12,7 +12,7 @@ module IOP
|
|
12
12
|
|
13
13
|
|
14
14
|
# @private
|
15
|
-
module
|
15
|
+
module FTPCommons
|
16
16
|
|
17
17
|
private
|
18
18
|
|
@@ -45,6 +45,7 @@ module IOP
|
|
45
45
|
|
46
46
|
end
|
47
47
|
|
48
|
+
|
48
49
|
#
|
49
50
|
# Feed class to read file from FTP server.
|
50
51
|
#
|
@@ -52,6 +53,7 @@ module IOP
|
|
52
53
|
#
|
53
54
|
# ### Use case: retrieve file from FTP server and store it locally.
|
54
55
|
#
|
56
|
+
# require 'iop/file'
|
55
57
|
# require 'iop/net/ftp'
|
56
58
|
# ( IOP::FTPFileReader.new('ftp.gnu.org', '/pub/README') | IOP::FileWriter.new('README') ).process!
|
57
59
|
#
|
@@ -60,7 +62,7 @@ module IOP
|
|
60
62
|
class FTPFileReader
|
61
63
|
|
62
64
|
include Feed
|
63
|
-
include
|
65
|
+
include FTPCommons
|
64
66
|
|
65
67
|
# Creates class instance.
|
66
68
|
#
|
@@ -133,7 +135,6 @@ module IOP
|
|
133
135
|
end
|
134
136
|
|
135
137
|
|
136
|
-
|
137
138
|
#
|
138
139
|
# Sink class to write file to FTP server.
|
139
140
|
#
|
@@ -158,7 +159,7 @@ module IOP
|
|
158
159
|
class FTPFileWriter
|
159
160
|
|
160
161
|
include Sink
|
161
|
-
include
|
162
|
+
include FTPCommons
|
162
163
|
|
163
164
|
# Creates class instance.
|
164
165
|
#
|
data/lib/iop/net/sftp.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'iop'
|
2
|
+
require 'net/sftp'
|
3
|
+
|
4
|
+
|
5
|
+
module IOP
|
6
|
+
|
7
|
+
|
8
|
+
# @private
|
9
|
+
module SFTPCommons
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def setup
|
14
|
+
if @sftp.is_a?(String)
|
15
|
+
@sftp = Net::SFTP.start(@sftp, @options.delete(:username), **@options)
|
16
|
+
@managed = true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def cleanup
|
21
|
+
if @managed
|
22
|
+
ssh = @sftp.session
|
23
|
+
@sftp.close_channel
|
24
|
+
ssh.close
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
#
|
32
|
+
# Feed class to read file from SFTP server.
|
33
|
+
#
|
34
|
+
# This class an adapter for +Net::SFTP::Session+ class.
|
35
|
+
#
|
36
|
+
# ### Use case: retrieve current user's _~/.profile_ file from SFTP server running on local machine and and compute its MD5 hash sum.
|
37
|
+
#
|
38
|
+
# require 'iop/digest'
|
39
|
+
# require 'iop/net/sftp'
|
40
|
+
# ( IOP::SFTPFileReader.new('localhost', '.profile') | (d = IOP::DigestComputer.new(Digest::MD5.new)) ).process!
|
41
|
+
# puts d.digest.hexdigest
|
42
|
+
#
|
43
|
+
# @note this class depends on external +net-sftp+ gem.
|
44
|
+
# @since 0.2
|
45
|
+
#
|
46
|
+
class SFTPFileReader < RandomAccessReader
|
47
|
+
|
48
|
+
include Feed
|
49
|
+
include SFTPCommons
|
50
|
+
|
51
|
+
# Creates class instance.
|
52
|
+
#
|
53
|
+
# @param sftp [String, Net::SFTP::Session] SFTP server to connect to
|
54
|
+
#
|
55
|
+
# @param file [String] file name to process
|
56
|
+
#
|
57
|
+
# @param size [Integer] total number of bytes to read; +nil+ value instructs to read until end-of-data is reached
|
58
|
+
#
|
59
|
+
# @param offset [Integer] offset in bytes from the stream start to seek to; +nil+ value means no seeking is performed
|
60
|
+
#
|
61
|
+
# @param block_size [Integer] size of blocks to process data with
|
62
|
+
#
|
63
|
+
# @param options [Hash] extra keyword parameters passed to +Net::SFTP::Session+ constructor, such as username, password etc.
|
64
|
+
#
|
65
|
+
# _sftp_ can be either a +String+ of +Net::SFTP::Session+ instance.
|
66
|
+
# If it is a string a corresponding +Net::SFTP::Session+ instance will be created with _options_ passed to its constructor.
|
67
|
+
#
|
68
|
+
# If _sftp_ is a string, a created SFTP session is managed, e.g. it is closed after the process is complete,
|
69
|
+
# otherwise supplied object is left as is and no closing is performed.
|
70
|
+
# This allows to reuse SFTP session for a sequence of operations.
|
71
|
+
#
|
72
|
+
# Refer to +Net::SFTP+ documentation for available options.
|
73
|
+
def initialize(sftp, file, size: nil, offset: nil, block_size: DEFAULT_BLOCK_SIZE, **options)
|
74
|
+
super(size: size, offset: offset, block_size: block_size)
|
75
|
+
@options = options
|
76
|
+
@file = file
|
77
|
+
@sftp = sftp
|
78
|
+
end
|
79
|
+
|
80
|
+
def process!
|
81
|
+
setup
|
82
|
+
begin
|
83
|
+
@io = @sftp.open!(@file, 'r')
|
84
|
+
begin
|
85
|
+
super
|
86
|
+
ensure
|
87
|
+
@sftp.close(@io)
|
88
|
+
end
|
89
|
+
ensure
|
90
|
+
cleanup
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def read!(read_size, buffer)
|
97
|
+
data = @sftp.read!(@io, @offset ||= 0, read_size)
|
98
|
+
@offset += data.size unless data.nil?
|
99
|
+
data
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
#
|
106
|
+
# Sink class to write file to SFTP server.
|
107
|
+
#
|
108
|
+
# This class an adapter for +Net::SFTP::Session+ class.
|
109
|
+
#
|
110
|
+
# ### Use case: store a number of files filled with random data to remote SFTP server reusing session.
|
111
|
+
#
|
112
|
+
# require 'iop/net/sftp'
|
113
|
+
# require 'iop/securerandom'
|
114
|
+
# sftp = Net::SFTP.start('sftp.server', username: 'user', password: '123')
|
115
|
+
# begin
|
116
|
+
# (1..3).each do |i|
|
117
|
+
# ( IOP::SecureRandomGenerator.new(1024) | IOP::SFTPFileWriter.new(sftp, "random#{i}.dat") ).process!
|
118
|
+
# end
|
119
|
+
# ensure
|
120
|
+
# sftp.session.close
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
# @note this class depends on external +net-sftp+ gem.
|
124
|
+
# @since 0.2
|
125
|
+
#
|
126
|
+
class SFTPFileWriter
|
127
|
+
|
128
|
+
include Sink
|
129
|
+
include SFTPCommons
|
130
|
+
|
131
|
+
# Creates class instance.
|
132
|
+
#
|
133
|
+
# @param sftp [String, Net::SFTP::Session] SFTP server to connect to
|
134
|
+
#
|
135
|
+
# @param file [String] file name to process
|
136
|
+
#
|
137
|
+
# @param options [Hash] extra keyword parameters passed to +Net::SFTP::Session+ constructor
|
138
|
+
#
|
139
|
+
# _sftp_ can be either a +String+ of +Net::SFTP::Session+ instance.
|
140
|
+
# If it is a string a corresponding +Net::SFTP::Session+ instance will be created with _options_ passed to its constructor.
|
141
|
+
#
|
142
|
+
# If _sftp_ is a string, a created SFTP session is managed, e.g. it is closed after the process is complete,
|
143
|
+
# otherwise supplied object is left as is and no closing is performed.
|
144
|
+
# This allows to reuse SFTP session for a sequence of operations.
|
145
|
+
def initialize(sftp, file, **options)
|
146
|
+
@options = options
|
147
|
+
@file = file
|
148
|
+
@sftp = sftp
|
149
|
+
end
|
150
|
+
|
151
|
+
def process!
|
152
|
+
setup
|
153
|
+
begin
|
154
|
+
@io = @sftp.open!(@file, 'w')
|
155
|
+
@offset = 0
|
156
|
+
begin
|
157
|
+
super
|
158
|
+
ensure
|
159
|
+
@sftp.close(@io)
|
160
|
+
end
|
161
|
+
ensure
|
162
|
+
cleanup
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def process(data = nil)
|
167
|
+
unless data.nil?
|
168
|
+
@sftp.write!(@io, @offset, data)
|
169
|
+
@offset += data.size
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
end
|
data/lib/iop/securerandom.rb
CHANGED
@@ -8,7 +8,7 @@ module IOP
|
|
8
8
|
#
|
9
9
|
# Feed class to generate and send a random sequence of bytes of specified size.
|
10
10
|
#
|
11
|
-
# This is the adapter for standard
|
11
|
+
# This is the adapter for the standard Ruby +SecureRandom+ module.
|
12
12
|
#
|
13
13
|
# ### Use case: generate 1024 bytes of random data and compute MD5 hash sum of it.
|
14
14
|
#
|
metadata
CHANGED
@@ -1,38 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleg A. Khlybov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
|
-
|
14
|
+
I/O pipeline construction framework.
|
15
|
+
Allows to construct data processing pipelines in a manner of UNIX shell pipes.
|
15
16
|
Implemented features:
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
string splitting/merging,
|
18
|
+
IO or local file reading/writing,
|
19
|
+
FTP/SFTP file reading/writing,
|
20
|
+
digest computing,
|
21
|
+
Gzip/Zlib (de)compression,
|
22
|
+
Zstd (de)compression,
|
23
|
+
symmetric cipher (de,en)cryption,
|
24
|
+
random data generation.
|
24
25
|
email:
|
25
26
|
- fougas@mail.ru
|
26
27
|
executables: []
|
27
28
|
extensions: []
|
28
29
|
extra_rdoc_files: []
|
29
30
|
files:
|
31
|
+
- ".yardopts"
|
30
32
|
- CHANGES.md
|
31
33
|
- README.md
|
32
34
|
- lib/iop.rb
|
33
35
|
- lib/iop/digest.rb
|
34
36
|
- lib/iop/file.rb
|
35
37
|
- lib/iop/net/ftp.rb
|
38
|
+
- lib/iop/net/sftp.rb
|
36
39
|
- lib/iop/openssl.rb
|
37
40
|
- lib/iop/securerandom.rb
|
38
41
|
- lib/iop/string.rb
|