zopen 1.0.1 → 1.0.2
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/zopen.rb +235 -224
- data/tests/zopen_spec.rb +47 -47
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad1a11d193d3b241eb3736978a001ffb27419f02
|
4
|
+
data.tar.gz: 4ca599acb3c0f0c2dde0adeada8c18a08fff2bc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a26b37e0874abeafadbafb86fa25b639160e3fc4001bb2fbaa5692fd2665132f5ed7cd1f2f3aee75846c9edf4d98305c337f0a3adbcd42ccf5bb17067afcb60d
|
7
|
+
data.tar.gz: a2ff651afd0f673d06eb4b189f222feed60d96dd947bf06ec60673ac3fab13ad725d22c0e6ec8fcbefff7e69167c24246069caa4452b03ad6067bb52e54c2d88
|
data/lib/zopen.rb
CHANGED
@@ -18,228 +18,239 @@ require 'delegate'
|
|
18
18
|
# extensions and use different packers.
|
19
19
|
module ZOpen
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
21
|
+
# Handler for a plain file.
|
22
|
+
#
|
23
|
+
# This just opens a File
|
24
|
+
Plain = lambda do |filename, mode|
|
25
|
+
File.new(filename, mode)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Handler for gzip compressed files.
|
29
|
+
#
|
30
|
+
# This handler uses either *zlib* module or the external *gzip*
|
31
|
+
# program.
|
32
|
+
Gzip = lambda do |filename, mode|
|
33
|
+
begin
|
34
|
+
require 'zlib'
|
35
|
+
case mode
|
36
|
+
when /r/, nil then Zlib::GzipReader.open(filename)
|
37
|
+
when /w/ then Zlib::GzipWriter.open(filename)
|
38
|
+
else fail "Unsupported open mode: #{mode}"
|
39
|
+
end
|
40
|
+
rescue LoadError
|
41
|
+
case mode
|
42
|
+
when /r/, nil then IO.popen("gzip -d -c '#{filename}'", mode)
|
43
|
+
when /w/ then IO.popen("gzip -c - > '#{filename}'", mode)
|
44
|
+
else fail "Unsupported open mode: #{mode}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Handler for bzip2 compressed files.
|
50
|
+
#
|
51
|
+
# This handler uses either *bzip2* module provided by the
|
52
|
+
# *bzip2-ruby* gem or the external *bzip2* program.
|
53
|
+
Bzip2 = lambda do |filename, mode|
|
54
|
+
begin
|
55
|
+
require 'bzip2'
|
56
|
+
case mode
|
57
|
+
when /r/, nil then Bzip2::Reader.open(filename)
|
58
|
+
when /w/ then Bzip2::Writer.open(filename)
|
59
|
+
else fail "Unsupported open mode: #{mode}"
|
60
|
+
end
|
61
|
+
rescue LoadError
|
62
|
+
case mode
|
63
|
+
when /r/, nil then IO.popen("bzip2 -d -c '#{filename}'", mode)
|
64
|
+
when /w/ then IO.popen("bzip2 -c - > '#{filename}'", mode)
|
65
|
+
else fail "Unsupported open mode: #{mode}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Handler for xz compressed files.
|
71
|
+
#
|
72
|
+
# This handler uses either *XZ* module provided by the
|
73
|
+
# *ruby-xz* gem or the external *xz* program.
|
74
|
+
XZ = lambda do |filename, mode|
|
75
|
+
begin
|
76
|
+
require 'xz'
|
77
|
+
case mode
|
78
|
+
when /r/, nil then ::XZ::StreamReader.open(filename)
|
79
|
+
when /w/ then ::XZ::StreamWriter.open(filename)
|
80
|
+
else fail "Unsupported open mode: #{mode}"
|
81
|
+
end
|
82
|
+
rescue LoadError
|
83
|
+
case mode
|
84
|
+
when /r/, nil then IO.popen("xz -d -c '#{filename}'", mode)
|
85
|
+
when /w/ then IO.popen("xz -c - > '#{filename}'", mode)
|
86
|
+
else fail "Unsupported open mode: #{mode}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# A possible compressed file.
|
92
|
+
#
|
93
|
+
# This class delegates all functions to its underlying IO-like
|
94
|
+
# object, which should provide the typical read/write
|
95
|
+
# methods. However, many compressed files to not allow random
|
96
|
+
# access, so methods like *seek* might not be available.
|
97
|
+
class File < SimpleDelegator
|
98
|
+
class << self
|
99
|
+
# Open file.
|
100
|
+
#
|
101
|
+
# The only two open modes that are guaranteed to be supported
|
102
|
+
# are 'r' and 'w' for reading and writing, respectively.
|
103
|
+
#
|
104
|
+
# If a code block is given the block is called with the new
|
105
|
+
# file as parameter and the file is closed when the block
|
106
|
+
# returns.
|
107
|
+
#
|
108
|
+
# @param filename [String] the name of the file to be opened
|
109
|
+
# @param mode [String,nil] the mode to open the file
|
110
|
+
# @return [File] the opened file
|
111
|
+
# @yield [File] this file
|
112
|
+
def new(filename, mode = nil)
|
113
|
+
file = allocate
|
114
|
+
file.send(:initialize, filename, mode)
|
115
|
+
if block_given?
|
116
|
+
begin
|
117
|
+
yield file
|
118
|
+
ensure
|
119
|
+
file.close
|
120
|
+
end
|
121
|
+
else
|
122
|
+
file
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
alias_method :open, :new
|
127
|
+
end
|
128
|
+
|
129
|
+
# Constructor
|
130
|
+
def initialize(filename, mode=nil)
|
131
|
+
super(openfile(filename, mode))
|
132
|
+
end
|
133
|
+
|
134
|
+
# Return the content of a file.
|
135
|
+
#
|
136
|
+
# @param filename [String] the name of the file
|
137
|
+
# @return [String] the content of the file
|
138
|
+
def self.read(filename)
|
139
|
+
new(filename, 'r') { |f| return f.read }
|
140
|
+
end
|
141
|
+
|
142
|
+
# Write a string to a file.
|
143
|
+
#
|
144
|
+
# @param filename [String] the name of the file
|
145
|
+
# @param text [String] the string to be written to the file
|
146
|
+
def self.write(filename, text)
|
147
|
+
new(filename, 'w') { |f| f.write text }
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
# Open a file with a certain mode.
|
152
|
+
#
|
153
|
+
# This method tests all registered handlers until it finds
|
154
|
+
# some whose pattern matches the filename. Then the
|
155
|
+
# corresponding handler is called.
|
156
|
+
#
|
157
|
+
# If no matching handler is found the file is opened as plain
|
158
|
+
# file.
|
159
|
+
#
|
160
|
+
# @param filename [String] the name of the file
|
161
|
+
# @param mode [String] the mode to open the file in
|
162
|
+
def openfile(filename, mode)
|
163
|
+
h = handlers
|
164
|
+
h.find do |pat, open|
|
165
|
+
return open.call(filename, mode) if pat =~ filename
|
166
|
+
end if h
|
167
|
+
::File.new(filename, mode)
|
168
|
+
end
|
169
|
+
|
170
|
+
protected
|
171
|
+
# Returns a hash of handlers.
|
172
|
+
#
|
173
|
+
# This function returns a hash of handlers. Each key should be
|
174
|
+
# a regexp to test the file name. The key should be a callable
|
175
|
+
# object (i.e. an object that has a *call* method, e.g. a
|
176
|
+
# *Proc*). The callable object resembles the *open* function
|
177
|
+
# *of a File object, i.e., it is called with two parameters
|
178
|
+
# **filename* and *mode* and should return a corresponding
|
179
|
+
# *opened *IO* object.
|
180
|
+
#
|
181
|
+
# This function may be overwritten in subclasses in order to
|
182
|
+
# provide custom handlers.
|
183
|
+
def handlers
|
184
|
+
@@handlers
|
185
|
+
end
|
186
|
+
|
187
|
+
@@handlers = {
|
188
|
+
/\.gz$/ => Gzip,
|
189
|
+
/\.bz2$/ => Bzip2,
|
190
|
+
/\.xz$/ => XZ
|
191
|
+
}
|
192
|
+
end
|
193
|
+
|
194
|
+
# Create a new File-like class with handlers.
|
195
|
+
#
|
196
|
+
# This *handlers* parameter should be a hash whose keys are a
|
197
|
+
# regular expression and the values are open-like callable
|
198
|
+
# objects. If a name of a file to be opened matches a regular
|
199
|
+
# expression, the corresponding callable object is called with the
|
200
|
+
# file name and the open mode, and it should return an appropriate
|
201
|
+
# IO object.
|
202
|
+
#
|
203
|
+
# @param handlers [Hash<Regexp,Proc>,nil] a hash of file handlers
|
204
|
+
# @return [Class] a new file class
|
205
|
+
def self.newfile(handlers = nil)
|
206
|
+
if handlers then
|
207
|
+
zFile = Class.new(File)
|
208
|
+
zFile.send :define_method, :handlers do
|
209
|
+
handlers
|
210
|
+
end
|
211
|
+
zFile
|
212
|
+
else
|
213
|
+
File
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Opens a file with standard handlers.
|
218
|
+
#
|
219
|
+
# This opens a file that recognized gzip, bzip2 and xz compressed
|
220
|
+
# files.
|
221
|
+
#
|
222
|
+
# Like File.open this method may be passed a code block which is
|
223
|
+
# called with the new File as parameter.
|
224
|
+
#
|
225
|
+
# @param filename [String] the name of the file
|
226
|
+
# @param mode [String,nil] the open mode
|
227
|
+
# @return [File] the opened file
|
228
|
+
# @yield [File] this file
|
229
|
+
def self.open(filename, mode=nil)
|
230
|
+
if block_given? then
|
231
|
+
File.open(filename, mode) { |f| yield f }
|
232
|
+
else
|
233
|
+
File.open(filename, mode)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Writes text to a file with standard handlers.
|
238
|
+
#
|
239
|
+
# This method recognizes gzip, bzip2 and xz compressed files.
|
240
|
+
#
|
241
|
+
# @param [String] filename the name of the file
|
242
|
+
# @param [String] text the text to be written to the file
|
243
|
+
def self.write(filename, text)
|
244
|
+
File.write(filename, text)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Reads text from a file with standard handlers.
|
248
|
+
#
|
249
|
+
# This method recognizes gzip, bzip2 and xz compressed files.
|
250
|
+
#
|
251
|
+
# @param [String] filename the name of the file
|
252
|
+
# @return [String] the content of the file
|
253
|
+
def self.read(filename)
|
254
|
+
File.read(filename)
|
255
|
+
end
|
245
256
|
end
|
data/tests/zopen_spec.rb
CHANGED
@@ -4,63 +4,63 @@ require 'tempfile'
|
|
4
4
|
require 'zopen'
|
5
5
|
|
6
6
|
describe ZOpen do
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
before do
|
8
|
+
@fhandler = ZOpen.newfile
|
9
|
+
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
it 'should read plain files' do
|
12
|
+
t = Tempfile.new('foo')
|
13
|
+
t.write "Hallo Welt\n"
|
14
|
+
t.close
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
f = @fhandler.open(t.path)
|
17
|
+
f.read.must_equal "Hallo Welt\n"
|
18
|
+
f.close
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
@fhandler.open(t.path) do |f2|
|
21
|
+
f2.read.must_equal "Hallo Welt\n"
|
22
|
+
end
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
@fhandler.read(t.path).must_equal "Hallo Welt\n"
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
it 'should fail on non existing files' do
|
28
|
+
assert_raises Errno::ENOENT do
|
29
|
+
@fhandler.open('nonexistingfile')
|
30
|
+
end
|
31
|
+
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
it 'should write plain files' do
|
34
|
+
t = Tempfile.new('foo')
|
35
|
+
t.close
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
f = @fhandler.open(t.path, 'w')
|
38
|
+
f.write "Hallo Welt\n"
|
39
|
+
f.close
|
40
|
+
File.read(t.path).must_equal "Hallo Welt\n"
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
@fhandler.open(t.path, 'w') do |fout|
|
43
|
+
fout.write "Hello world\n"
|
44
|
+
end
|
45
|
+
File.read(t.path).must_equal "Hello world\n"
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
@fhandler.write t.path, "Hello world\n"
|
48
|
+
File.read(t.path).must_equal "Hello world\n"
|
49
|
+
end
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
describe 'File with patterns' do
|
52
|
+
it 'should call the correct handler' do
|
53
|
+
file = Minitest::Mock.new
|
54
|
+
file.expect :write, nil, ["Hallo Welt\n"]
|
55
|
+
file.expect :close, nil, []
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
open = Minitest::Mock.new
|
58
|
+
open.expect :call, file, ['foo.txt', nil]
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
@fhandler = ZOpen.newfile({%r/\.txt$/ => open})
|
61
|
+
f = @fhandler.open('foo.txt')
|
62
|
+
f.write "Hallo Welt\n"
|
63
|
+
f.close
|
64
|
+
end
|
65
|
+
end
|
66
66
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zopen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frank Fischer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yard
|
@@ -38,7 +38,7 @@ files:
|
|
38
38
|
- tests/zopen_spec.rb
|
39
39
|
homepage: http://bitbucket.org/lyro/zopen
|
40
40
|
licenses:
|
41
|
-
- GPL-3
|
41
|
+
- GPL-3.0
|
42
42
|
metadata: {}
|
43
43
|
post_install_message:
|
44
44
|
rdoc_options: []
|
@@ -56,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
56
|
version: '0'
|
57
57
|
requirements: []
|
58
58
|
rubyforge_project:
|
59
|
-
rubygems_version: 2.
|
59
|
+
rubygems_version: 2.5.1
|
60
60
|
signing_key:
|
61
61
|
specification_version: 4
|
62
62
|
summary: Automatically open compressed files
|