zipping 0.2.1
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 +7 -0
- data/.gitignore +51 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.txt +22 -0
- data/README.md +71 -0
- data/Rakefile +1 -0
- data/VERSION +1 -0
- data/lib/zipping/version.rb +3 -0
- data/lib/zipping.rb +731 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/zipping_spec.rb +7 -0
- data/zipping.gemspec +26 -0
- metadata +117 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: c6d26ef58bcb6f2cf5e72b4979157edcacfc2b15
|
|
4
|
+
data.tar.gz: 934f22728e3df8c6aebb2cb5233512a693267e84
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 91db69bf6bb30b3573d4ac116b17e3c53d3f1559c504aa67a96236b2687fdf860592d4b150c6aa5339fd28df2dbd463c1cacb0b229889ade0802b0403ad71408
|
|
7
|
+
data.tar.gz: 24796b591dc42fa83ab0cff4afe6646b1cc355ddaa78fbe0bc38c319a619c65a571256a8db3395ad17284a41a08f6682ea3306343a0eeb78ba09d9ff527ed0ae
|
data/.gitignore
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# rcov generated
|
|
2
|
+
coverage
|
|
3
|
+
coverage.data
|
|
4
|
+
|
|
5
|
+
# rdoc generated
|
|
6
|
+
rdoc
|
|
7
|
+
|
|
8
|
+
# yard generated
|
|
9
|
+
doc
|
|
10
|
+
.yardoc
|
|
11
|
+
|
|
12
|
+
# bundler
|
|
13
|
+
.bundle
|
|
14
|
+
|
|
15
|
+
# jeweler generated
|
|
16
|
+
pkg
|
|
17
|
+
|
|
18
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
|
19
|
+
#
|
|
20
|
+
# * Create a file at ~/.gitignore
|
|
21
|
+
# * Include files you want ignored
|
|
22
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
|
23
|
+
#
|
|
24
|
+
# After doing this, these files will be ignored in all your git projects,
|
|
25
|
+
# saving you from having to 'pollute' every project you touch with them
|
|
26
|
+
#
|
|
27
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
|
28
|
+
#
|
|
29
|
+
# For MacOS:
|
|
30
|
+
#
|
|
31
|
+
#.DS_Store
|
|
32
|
+
|
|
33
|
+
# For TextMate
|
|
34
|
+
#*.tmproj
|
|
35
|
+
#tmtags
|
|
36
|
+
|
|
37
|
+
# For emacs:
|
|
38
|
+
#*~
|
|
39
|
+
#\#*
|
|
40
|
+
#.\#*
|
|
41
|
+
|
|
42
|
+
# For vim:
|
|
43
|
+
#*.swp
|
|
44
|
+
|
|
45
|
+
# For redcar:
|
|
46
|
+
#.redcar
|
|
47
|
+
|
|
48
|
+
# For rubinius:
|
|
49
|
+
#*.rbc
|
|
50
|
+
|
|
51
|
+
/.DS_Store
|
data/.rspec
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
zipping (0.2.1)
|
|
5
|
+
rubyzip (>= 1.0.0)
|
|
6
|
+
zip-zip (~> 0.2)
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
rake (10.0.3)
|
|
12
|
+
rubyzip (1.1.0)
|
|
13
|
+
zip-zip (0.2)
|
|
14
|
+
rubyzip (>= 1.0.0)
|
|
15
|
+
|
|
16
|
+
PLATFORMS
|
|
17
|
+
ruby
|
|
18
|
+
|
|
19
|
+
DEPENDENCIES
|
|
20
|
+
bundler (~> 1.3)
|
|
21
|
+
rake
|
|
22
|
+
zipping!
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 Misaki Kawamura
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
zipping
|
|
2
|
+
=======
|
|
3
|
+
|
|
4
|
+
This gem is for compressing files as a zip and outputting to a stream (or a stream-like interface object). The output to a stream proceeds little by little, as files are compressed.
|
|
5
|
+
|
|
6
|
+
Getting Started
|
|
7
|
+
--
|
|
8
|
+
Add the following line to your Gemfile:
|
|
9
|
+
|
|
10
|
+
gem 'zipping'
|
|
11
|
+
|
|
12
|
+
Usage
|
|
13
|
+
--
|
|
14
|
+
simple:
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
require 'zipping'
|
|
18
|
+
|
|
19
|
+
Zipping.files_to_zip my_stream, '/path/to/file'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
You can pass multiple files.
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
Zipping.files_to_zip my_stream2, ['/path/to/file', '/another/path']
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If you pass a folder, zipping compresses all files in the folder.
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
Zipping.files_to_zip my_stream3, ['/path/to/folder', '/path/to/other/file']
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
For example, you have files below:
|
|
35
|
+
|
|
36
|
+
/text/foo.txt
|
|
37
|
+
/text/bar/baz.txt
|
|
38
|
+
/images/abc.png
|
|
39
|
+
|
|
40
|
+
and you run command:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
file = File.open '/my.zip', 'wb'
|
|
44
|
+
Zipping.files_to_zip file, ['/text', '/images/abc.png']
|
|
45
|
+
file.close
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then, you get a zip file, and you find entries below in it.
|
|
49
|
+
|
|
50
|
+
text/
|
|
51
|
+
text/foo.txt
|
|
52
|
+
text/bar/
|
|
53
|
+
text/bar/baz.txt
|
|
54
|
+
abc.png
|
|
55
|
+
|
|
56
|
+
To get binary data of zip instead of saving as a file, prepare an 'ASCII-8bit'-encoded empty String object.
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
zip_data = ''.force_encoding('ASCII-8bit')
|
|
60
|
+
Zipping.files_to_zip zip_data, ['/text', '/images/abc.png']
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then, you get zip binary data in `zip_data`.
|
|
64
|
+
|
|
65
|
+
Notice
|
|
66
|
+
--
|
|
67
|
+
With older(<1.0.0) rubyzip, use 0.2.0.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
Copyright (c) 2013 [Nekojarashi Inc.](http://www.nekojarashi.com)
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.2.1
|
data/lib/zipping.rb
ADDED
|
@@ -0,0 +1,731 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require "zipping/version"
|
|
3
|
+
require 'zip'
|
|
4
|
+
|
|
5
|
+
module Zipping
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# Constants
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
ZS_c_pk0102 = 0x02014b50
|
|
13
|
+
ZS_c_pk0304 = 0x04034b50
|
|
14
|
+
ZS_c_pk0506 = 0x06054b50
|
|
15
|
+
ZS_c_pk0708 = 0x08074b50
|
|
16
|
+
ZS_c_ver_dir = 0x000a
|
|
17
|
+
ZS_c_ver_file = 0x0014
|
|
18
|
+
ZS_c_ver_made = 0x0315
|
|
19
|
+
ZS_c_opt_none = 0x0000
|
|
20
|
+
ZS_c_opt_nosize = 0x0008
|
|
21
|
+
ZS_c_comp_deflate = 0x0008
|
|
22
|
+
ZS_c_int2_zero = 0x0000
|
|
23
|
+
ZS_c_int4_zero = 0x00000000
|
|
24
|
+
|
|
25
|
+
ZS_c_oattr_dir = 0x41ed4000
|
|
26
|
+
ZS_c_oattr_file = 0x81a44000
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# API methods
|
|
32
|
+
#
|
|
33
|
+
|
|
34
|
+
def self.files_to_zip(output_stream, files, encoding = :utf8, file_division_size = 1048576)
|
|
35
|
+
builder = ZipBuilder.new output_stream, files, encoding, file_division_size
|
|
36
|
+
builder.pack
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Deprecated.
|
|
40
|
+
# Recommended to use 'files_to_zip' instead.
|
|
41
|
+
def self.directory_to_zip(output_stream, target_path, usesjis = true, file_division_size = 1048576)
|
|
42
|
+
self.create_zip_file_with_files_and_directories(output_stream, target_path, usesjis, file_division_size)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Deprecated.
|
|
46
|
+
# Recommended to use 'files_to_zip' instead.
|
|
47
|
+
def self.file_to_zip(output_stream, target_path, usesjis = false, file_division_size = 1048576)
|
|
48
|
+
self.create_zip_file_with_files_and_directories(output_stream, target_path, usesjis, file_division_size)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
#
|
|
54
|
+
# Internal Classes
|
|
55
|
+
#
|
|
56
|
+
|
|
57
|
+
# Output stream wrapper that measures size of stream passing through.
|
|
58
|
+
class StreamMeter
|
|
59
|
+
def initialize(output_stream)
|
|
60
|
+
@output_stream = output_stream
|
|
61
|
+
@size = 0
|
|
62
|
+
end
|
|
63
|
+
def << (data)
|
|
64
|
+
@size += data.length
|
|
65
|
+
@output_stream << data
|
|
66
|
+
end
|
|
67
|
+
attr_reader :size
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class ZipBuilder
|
|
71
|
+
|
|
72
|
+
# Initialize ZipBuilder.
|
|
73
|
+
# 'files' must be a String(file or directory path), a Hash(entity), or an Array of Strings and/or Hashes.
|
|
74
|
+
def initialize(output_stream, files, encoding = :utf8, file_division_size = 1048576)
|
|
75
|
+
@o = output_stream
|
|
76
|
+
@f = ZipBuilder.to_entities files
|
|
77
|
+
@e = encoding
|
|
78
|
+
@s = file_division_size
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Create an Array of entity Hashes.
|
|
82
|
+
def self.to_entities(files)
|
|
83
|
+
if files.is_a? Hash
|
|
84
|
+
ret = [files]
|
|
85
|
+
elsif files.is_a? String
|
|
86
|
+
entity = ZipBuilder.to_entity(files)
|
|
87
|
+
ret = entity.nil? ? [] : [entity]
|
|
88
|
+
elsif files.is_a? Array
|
|
89
|
+
ret = []
|
|
90
|
+
files.each do |f|
|
|
91
|
+
entity = ZipBuilder.to_entity(f)
|
|
92
|
+
ret << entity unless entity.nil?
|
|
93
|
+
end
|
|
94
|
+
else
|
|
95
|
+
ret = []
|
|
96
|
+
end
|
|
97
|
+
ret
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Create an entity Hash with a path String
|
|
101
|
+
def self.to_entity(path)
|
|
102
|
+
return path if path.is_a?(Hash)
|
|
103
|
+
return nil unless path.is_a?(String) && File.exists?(path)
|
|
104
|
+
ret = {
|
|
105
|
+
:path => path,
|
|
106
|
+
:name => File.basename(path)
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Create ASCII-8bits string. Also convert encoding if needed.
|
|
111
|
+
def self.to_bytes(str, encoding = :utf8)
|
|
112
|
+
unless encoding.nil? || encoding == :utf8
|
|
113
|
+
case encoding
|
|
114
|
+
when :shift_jis
|
|
115
|
+
begin
|
|
116
|
+
str = str.encode 'Shift_JIS', :invalid => :replace, :undef => :replace, :replace => '??'
|
|
117
|
+
rescue => e
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
[str].pack('a*')
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Pack file and directory entities and output to stream.
|
|
125
|
+
def pack
|
|
126
|
+
return if @f.empty?
|
|
127
|
+
|
|
128
|
+
# directory entities found but not packed
|
|
129
|
+
@pending_dirs = []
|
|
130
|
+
|
|
131
|
+
# current directory
|
|
132
|
+
@current_dir = ''
|
|
133
|
+
@current_dir_created_at = Time.now
|
|
134
|
+
|
|
135
|
+
# data of positions necessary to create headers
|
|
136
|
+
@dp = []
|
|
137
|
+
|
|
138
|
+
o = StreamMeter.new @o
|
|
139
|
+
|
|
140
|
+
# pack file entities, store directory entities into @pending_dirs
|
|
141
|
+
pack_file_entities o
|
|
142
|
+
|
|
143
|
+
# retrieve and pack stored directories
|
|
144
|
+
until @pending_dirs.empty? do
|
|
145
|
+
|
|
146
|
+
current_dir = @pending_dirs.shift
|
|
147
|
+
@current_dir = current_dir[:name] << '/'
|
|
148
|
+
@current_dir_created_at = current_dir[:time]
|
|
149
|
+
|
|
150
|
+
# write directory entry
|
|
151
|
+
pack_directory o, current_dir[:time]
|
|
152
|
+
|
|
153
|
+
begin
|
|
154
|
+
# get files in the directory
|
|
155
|
+
files = Dir.glob(current_dir[:path] + '/*')
|
|
156
|
+
|
|
157
|
+
# pack files, store directories as entities into @pending_dirs
|
|
158
|
+
pack_files o, files, current_dir
|
|
159
|
+
rescue => e
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# prepare to create headers
|
|
164
|
+
@header_offset = o.size
|
|
165
|
+
o = StreamMeter.new(@o)
|
|
166
|
+
|
|
167
|
+
# write headers
|
|
168
|
+
write_central_dir_headers o
|
|
169
|
+
@header_size = o.size
|
|
170
|
+
write_end_central_dir_header
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Pack file entities and output to stream. Directory entities are not packed but stored.
|
|
174
|
+
def pack_file_entities(o = @o, files = @f, dir = @current_dir, dirs = @pending_dirs, data_positions = @dp, encoding = @e, file_division_size = @s)
|
|
175
|
+
files.each do |file|
|
|
176
|
+
next unless file.is_a?(Hash) && file[:path].present?
|
|
177
|
+
|
|
178
|
+
f = file[:path]
|
|
179
|
+
if File.directory? f
|
|
180
|
+
dirs << file
|
|
181
|
+
next
|
|
182
|
+
end
|
|
183
|
+
next unless File.file? f
|
|
184
|
+
data_offset = o.size
|
|
185
|
+
file_path = f
|
|
186
|
+
fname = dir.clone << (file[:name] || File.basename(file_path))
|
|
187
|
+
bfname = ZipBuilder.to_bytes(fname, encoding)
|
|
188
|
+
filetime = Zip::DOSTime.at(file[:time] || File.mtime(file_path))
|
|
189
|
+
filesize = File.size(file_path)
|
|
190
|
+
pk = [
|
|
191
|
+
ZS_c_pk0304,
|
|
192
|
+
ZS_c_ver_file,
|
|
193
|
+
ZS_c_opt_nosize,
|
|
194
|
+
ZS_c_comp_deflate,
|
|
195
|
+
filetime.to_binary_dos_time,
|
|
196
|
+
filetime.to_binary_dos_date,
|
|
197
|
+
ZS_c_int4_zero,
|
|
198
|
+
ZS_c_int4_zero,
|
|
199
|
+
ZS_c_int4_zero,
|
|
200
|
+
bfname.length,
|
|
201
|
+
ZS_c_int2_zero
|
|
202
|
+
]
|
|
203
|
+
bin = pk.pack('VvvvvvVVVvv')
|
|
204
|
+
o << bin
|
|
205
|
+
bin = bfname
|
|
206
|
+
o << bin
|
|
207
|
+
|
|
208
|
+
m = StreamMeter.new(o)
|
|
209
|
+
d = Zip::Deflater.new(m)
|
|
210
|
+
File.open(file_path) do |f|
|
|
211
|
+
cur_filesize = filesize
|
|
212
|
+
while cur_filesize > 0
|
|
213
|
+
if cur_filesize >= file_division_size
|
|
214
|
+
d << f.read(file_division_size)
|
|
215
|
+
cur_filesize -= file_division_size
|
|
216
|
+
else
|
|
217
|
+
d << f.read(cur_filesize)
|
|
218
|
+
cur_filesize = 0
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
d.finish
|
|
223
|
+
|
|
224
|
+
pk = [
|
|
225
|
+
ZS_c_pk0708,
|
|
226
|
+
d.crc,
|
|
227
|
+
m.size,
|
|
228
|
+
d.size
|
|
229
|
+
]
|
|
230
|
+
bin = pk.pack('VVVV')
|
|
231
|
+
o << bin
|
|
232
|
+
data_positions << {
|
|
233
|
+
:folder => false,
|
|
234
|
+
:file => fname,
|
|
235
|
+
:file_dos_time => filetime.to_binary_dos_time,
|
|
236
|
+
:file_dos_date => filetime.to_binary_dos_date,
|
|
237
|
+
:binary_fname => bfname,
|
|
238
|
+
:offset => data_offset,
|
|
239
|
+
:crc => d.crc,
|
|
240
|
+
:complen => m.size,
|
|
241
|
+
:uncomplen => d.size
|
|
242
|
+
}
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Pack directory and output to stream.
|
|
247
|
+
def pack_directory(o = @o, time_created_at = @current_dir_created_at, dir = @current_dir, data_positions = @dp, encoding = @e)
|
|
248
|
+
bdir = ZipBuilder.to_bytes(dir, encoding)
|
|
249
|
+
data_offset = o.size
|
|
250
|
+
filetime = Zip::DOSTime.at(time_created_at);
|
|
251
|
+
filesize = 0
|
|
252
|
+
pk = [
|
|
253
|
+
ZS_c_pk0304,
|
|
254
|
+
ZS_c_ver_dir,
|
|
255
|
+
ZS_c_opt_none,
|
|
256
|
+
ZS_c_comp_deflate,
|
|
257
|
+
filetime.to_binary_dos_time,
|
|
258
|
+
filetime.to_binary_dos_date,
|
|
259
|
+
ZS_c_int4_zero,
|
|
260
|
+
ZS_c_int4_zero,
|
|
261
|
+
ZS_c_int4_zero,
|
|
262
|
+
bdir.length,
|
|
263
|
+
ZS_c_int2_zero
|
|
264
|
+
]
|
|
265
|
+
bin = pk.pack('VvvvvvVVVvv')
|
|
266
|
+
o << bin
|
|
267
|
+
bin = bdir
|
|
268
|
+
o << bin
|
|
269
|
+
data_positions << {
|
|
270
|
+
:folder => true,
|
|
271
|
+
:file => dir,
|
|
272
|
+
:file_dos_time => filetime.to_binary_dos_time,
|
|
273
|
+
:file_dos_date => filetime.to_binary_dos_date,
|
|
274
|
+
:binary_fname => bdir,
|
|
275
|
+
:offset => data_offset,
|
|
276
|
+
:crc => ZS_c_int4_zero,
|
|
277
|
+
:complen => ZS_c_int4_zero,
|
|
278
|
+
:uncomplen => ZS_c_int4_zero
|
|
279
|
+
}
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Pack files and output to stream. Directories are not packed but stored.
|
|
283
|
+
def pack_files(o, files, dir, dirs = @pending_dirs, data_positions = @dp, encoding = @e, file_division_size = @s)
|
|
284
|
+
files.each do |f|
|
|
285
|
+
if File.directory? f
|
|
286
|
+
dirs << {
|
|
287
|
+
:path => f,
|
|
288
|
+
:name => dir[:name] + File.basename(f),
|
|
289
|
+
:time => dir[:time]
|
|
290
|
+
}
|
|
291
|
+
next
|
|
292
|
+
end
|
|
293
|
+
next unless File.file? f
|
|
294
|
+
data_offset = o.size
|
|
295
|
+
file_path = f
|
|
296
|
+
file = dir[:name] + File.basename(file_path)
|
|
297
|
+
bfile = ZipBuilder.to_bytes(file, encoding)
|
|
298
|
+
filetime = Zip::DOSTime.at(dir[:time] || File.mtime(file_path))
|
|
299
|
+
filesize = File.size(file_path)
|
|
300
|
+
pk = [
|
|
301
|
+
ZS_c_pk0304,
|
|
302
|
+
ZS_c_ver_file,
|
|
303
|
+
ZS_c_opt_nosize,
|
|
304
|
+
ZS_c_comp_deflate,
|
|
305
|
+
filetime.to_binary_dos_time,
|
|
306
|
+
filetime.to_binary_dos_date,
|
|
307
|
+
ZS_c_int4_zero,
|
|
308
|
+
ZS_c_int4_zero,
|
|
309
|
+
ZS_c_int4_zero,
|
|
310
|
+
bfile.length,
|
|
311
|
+
ZS_c_int2_zero
|
|
312
|
+
]
|
|
313
|
+
bin = pk.pack('VvvvvvVVVvv')
|
|
314
|
+
o << bin
|
|
315
|
+
bin = bfile
|
|
316
|
+
o << bin
|
|
317
|
+
|
|
318
|
+
m = StreamMeter.new(o)
|
|
319
|
+
d = Zip::Deflater.new(m)
|
|
320
|
+
File.open(file_path) do |f|
|
|
321
|
+
cur_filesize = filesize
|
|
322
|
+
while cur_filesize > 0
|
|
323
|
+
if cur_filesize >= file_division_size
|
|
324
|
+
d << f.read(file_division_size)
|
|
325
|
+
cur_filesize -= file_division_size
|
|
326
|
+
else
|
|
327
|
+
d << f.read(cur_filesize)
|
|
328
|
+
cur_filesize = 0
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
d.finish
|
|
333
|
+
|
|
334
|
+
pk = [
|
|
335
|
+
ZS_c_pk0708,
|
|
336
|
+
d.crc,
|
|
337
|
+
m.size,
|
|
338
|
+
d.size
|
|
339
|
+
]
|
|
340
|
+
bin = pk.pack('VVVV')
|
|
341
|
+
o << bin
|
|
342
|
+
data_positions << {
|
|
343
|
+
:folder => false,
|
|
344
|
+
:file => file,
|
|
345
|
+
:file_dos_time => filetime.to_binary_dos_time,
|
|
346
|
+
:file_dos_date => filetime.to_binary_dos_date,
|
|
347
|
+
:binary_fname => bfile,
|
|
348
|
+
:offset => data_offset,
|
|
349
|
+
:crc => d.crc,
|
|
350
|
+
:complen => m.size,
|
|
351
|
+
:uncomplen => d.size
|
|
352
|
+
}
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Write central directories.
|
|
357
|
+
def write_central_dir_headers(o = @o, data_positions = @dp)
|
|
358
|
+
data_positions.each do |dp|
|
|
359
|
+
pk = [
|
|
360
|
+
ZS_c_pk0102,
|
|
361
|
+
ZS_c_ver_made,
|
|
362
|
+
(dp[:folder] ? ZS_c_ver_dir : ZS_c_ver_file),
|
|
363
|
+
ZS_c_opt_nosize,
|
|
364
|
+
ZS_c_comp_deflate,
|
|
365
|
+
dp[:file_dos_time],
|
|
366
|
+
dp[:file_dos_date],
|
|
367
|
+
dp[:crc],
|
|
368
|
+
dp[:complen],
|
|
369
|
+
dp[:uncomplen],
|
|
370
|
+
dp[:binary_fname].length,
|
|
371
|
+
ZS_c_int2_zero,
|
|
372
|
+
ZS_c_int2_zero,
|
|
373
|
+
ZS_c_int2_zero,
|
|
374
|
+
ZS_c_int2_zero,
|
|
375
|
+
(dp[:folder] ? ZS_c_oattr_dir : ZS_c_oattr_file),
|
|
376
|
+
dp[:offset]
|
|
377
|
+
]
|
|
378
|
+
bin = pk.pack('VvvvvvvVVVvvvvvVV')
|
|
379
|
+
o << bin
|
|
380
|
+
bin = dp[:binary_fname]
|
|
381
|
+
o << bin
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
# Write end of central directory.
|
|
386
|
+
def write_end_central_dir_header(o = @o, entry_count = @dp.length, dirsize = @header_size, offset = @header_offset)
|
|
387
|
+
pk = [
|
|
388
|
+
ZS_c_pk0506,
|
|
389
|
+
ZS_c_int2_zero,
|
|
390
|
+
ZS_c_int2_zero,
|
|
391
|
+
entry_count,
|
|
392
|
+
entry_count,
|
|
393
|
+
dirsize,
|
|
394
|
+
offset,
|
|
395
|
+
ZS_c_int2_zero
|
|
396
|
+
]
|
|
397
|
+
o << pk.pack('VvvvvVVv')
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
#
|
|
403
|
+
# Internal method
|
|
404
|
+
#
|
|
405
|
+
|
|
406
|
+
# Pack files into zip.
|
|
407
|
+
# You must pass an entity Hash (or Array of them) consists of :path(path of file to pack into zip) and :name(file path inside zip) to this method as 'target_files'.
|
|
408
|
+
# Optionally, you may add :time(time created at) to the entity Hashes.
|
|
409
|
+
def self.create_zip_file_with_file_entities(outputStream, target_files, usesjis = true, file_division_size = 1048576)
|
|
410
|
+
begin
|
|
411
|
+
|
|
412
|
+
# prepare entry list for zip
|
|
413
|
+
target_files = [target_files] unless target_files.instance_of? Array
|
|
414
|
+
entries = []
|
|
415
|
+
target_files.each do |file|
|
|
416
|
+
if file.is_a? String
|
|
417
|
+
begin
|
|
418
|
+
entry = {
|
|
419
|
+
:path => file,
|
|
420
|
+
:name => File.basename(file),
|
|
421
|
+
:time => File.mtime(file)
|
|
422
|
+
}
|
|
423
|
+
rescue => e
|
|
424
|
+
next
|
|
425
|
+
end
|
|
426
|
+
elsif file.is_a? Hash
|
|
427
|
+
next unless file[:path].present? && file[:path].is_a?(String)
|
|
428
|
+
entry = file
|
|
429
|
+
path = entry[:path]
|
|
430
|
+
entry[:name] = File.basename(path) unless entry[:name].present? && entry[:name].is_a?(String)
|
|
431
|
+
entry[:time] = File.mtime(path) unless entry[:time].present? && entry[:time].is_a?(Time)
|
|
432
|
+
else
|
|
433
|
+
next
|
|
434
|
+
end
|
|
435
|
+
entries << entry
|
|
436
|
+
end
|
|
437
|
+
return if entries.empty?
|
|
438
|
+
|
|
439
|
+
# prepare to measure stream size
|
|
440
|
+
o = StreamMeter.new(outputStream)
|
|
441
|
+
|
|
442
|
+
# container to collect header info
|
|
443
|
+
data_positions = []
|
|
444
|
+
|
|
445
|
+
# compress entries
|
|
446
|
+
self.compress_entries(o, entries, data_positions, usesjis, file_division_size)
|
|
447
|
+
|
|
448
|
+
# measure stream size
|
|
449
|
+
pk0102_offset = o.size
|
|
450
|
+
|
|
451
|
+
# prepare to measure header size
|
|
452
|
+
m = StreamMeter.new(o)
|
|
453
|
+
|
|
454
|
+
# write headers
|
|
455
|
+
self.create_central_dir_headers(m, data_positions)
|
|
456
|
+
|
|
457
|
+
# measure header size
|
|
458
|
+
pk0102_size = m.size
|
|
459
|
+
|
|
460
|
+
# write tail header
|
|
461
|
+
self.create_end_cent_dir_header(o, data_positions.length, pk0102_size, pk0102_offset)
|
|
462
|
+
rescue => e
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# Pack files and folders into zip.
|
|
467
|
+
# All files in folders are also packed into zip, and the structure inside folders are conserved.
|
|
468
|
+
def self.create_zip_file_with_files_and_directories(outputStream, target_files, usesjis = true, file_division_size = 1048576)
|
|
469
|
+
begin
|
|
470
|
+
|
|
471
|
+
target_files = [target_files] unless target_files.instance_of? Array
|
|
472
|
+
return if target_files.empty?
|
|
473
|
+
|
|
474
|
+
dirs = []
|
|
475
|
+
o = StreamMeter.new(outputStream)
|
|
476
|
+
data_positions = []
|
|
477
|
+
|
|
478
|
+
self.compress_file_list(o, target_files, "", dirs, data_positions, usesjis, file_division_size)
|
|
479
|
+
|
|
480
|
+
while dirs.length > 0 do
|
|
481
|
+
current_directory = dirs.shift
|
|
482
|
+
dir_path = current_directory[0]
|
|
483
|
+
dir = current_directory[1]
|
|
484
|
+
dir << '/'
|
|
485
|
+
self.create_directory_entry(o, dir_path, dir, data_positions, usesjis, file_division_size)
|
|
486
|
+
|
|
487
|
+
files = Dir.glob(dir_path << '/*')
|
|
488
|
+
self.compress_file_list(o, files, dir, dirs, data_positions, usesjis, file_division_size)
|
|
489
|
+
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
pk0102_offset = o.size
|
|
493
|
+
m = StreamMeter.new(o)
|
|
494
|
+
self.create_central_dir_headers(m, data_positions)
|
|
495
|
+
|
|
496
|
+
self.create_end_cent_dir_header(o, data_positions.length, m.size, pk0102_offset)
|
|
497
|
+
rescue => e
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Get file name as ASCII-8bits.
|
|
502
|
+
# If needed, also convert encoding.
|
|
503
|
+
def self.get_binary_fname(str, usesjis)
|
|
504
|
+
if usesjis
|
|
505
|
+
begin
|
|
506
|
+
str = str.encode 'Shift_JIS', :invalid => :replace, :replace => '??'
|
|
507
|
+
rescue => e
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
return [str].pack('a*')
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# Write directory entry.
|
|
514
|
+
#
|
|
515
|
+
def self.create_directory_entry(o, dir_path, dir, data_positions, usesjis = false, file_division_size = 1048576)
|
|
516
|
+
bdir = self.get_binary_fname(dir, usesjis)
|
|
517
|
+
data_offset = o.size
|
|
518
|
+
filetime = Zip::DOSTime.at(File.mtime(dir_path))
|
|
519
|
+
filesize = 0
|
|
520
|
+
pk = [
|
|
521
|
+
ZS_c_pk0304,
|
|
522
|
+
ZS_c_ver_dir,
|
|
523
|
+
ZS_c_opt_none,
|
|
524
|
+
ZS_c_comp_deflate,
|
|
525
|
+
filetime.to_binary_dos_time,
|
|
526
|
+
filetime.to_binary_dos_date,
|
|
527
|
+
ZS_c_int4_zero,
|
|
528
|
+
ZS_c_int4_zero,
|
|
529
|
+
ZS_c_int4_zero,
|
|
530
|
+
bdir.length,
|
|
531
|
+
ZS_c_int2_zero
|
|
532
|
+
]
|
|
533
|
+
bin = pk.pack('VvvvvvVVVvv')
|
|
534
|
+
o << bin
|
|
535
|
+
bin = bdir
|
|
536
|
+
o << bin
|
|
537
|
+
data_positions << {
|
|
538
|
+
:folder => true,
|
|
539
|
+
:file => dir,
|
|
540
|
+
:file_dos_time => filetime.to_binary_dos_time,
|
|
541
|
+
:file_dos_date => filetime.to_binary_dos_date,
|
|
542
|
+
:binary_fname => bdir,
|
|
543
|
+
:offset => data_offset,
|
|
544
|
+
:crc => ZS_c_int4_zero,
|
|
545
|
+
:complen => ZS_c_int4_zero,
|
|
546
|
+
:uncomplen => ZS_c_int4_zero
|
|
547
|
+
}
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def self.compress_entries(o, entries, data_positions, usesjis = false, file_division_size = 1048576)
|
|
551
|
+
# `o' must be an output stream which has `size' method
|
|
552
|
+
|
|
553
|
+
entries.each do |entry|
|
|
554
|
+
path = entry[:path]
|
|
555
|
+
name = entry[:name]
|
|
556
|
+
mtime = entry[:time]
|
|
557
|
+
|
|
558
|
+
next if File.directory? path
|
|
559
|
+
next unless File.file? path
|
|
560
|
+
data_offset = o.size
|
|
561
|
+
b_name = self.get_binary_fname(name, usesjis)
|
|
562
|
+
filesize = File.size(path)
|
|
563
|
+
pk = [
|
|
564
|
+
ZS_c_pk0304,
|
|
565
|
+
ZS_c_ver_file,
|
|
566
|
+
ZS_c_opt_nosize,
|
|
567
|
+
ZS_c_comp_deflate,
|
|
568
|
+
mtime.to_binary_dos_time,
|
|
569
|
+
mtime.to_binary_dos_date,
|
|
570
|
+
ZS_c_int4_zero,
|
|
571
|
+
ZS_c_int4_zero,
|
|
572
|
+
ZS_c_int4_zero,
|
|
573
|
+
b_name.length,
|
|
574
|
+
ZS_c_int2_zero
|
|
575
|
+
]
|
|
576
|
+
bin = pk.pack('VvvvvvVVVvv')
|
|
577
|
+
o << bin
|
|
578
|
+
bin = b_name
|
|
579
|
+
o << bin
|
|
580
|
+
|
|
581
|
+
m = StreamMeter.new(o)
|
|
582
|
+
d = Zip::Deflater.new(m)
|
|
583
|
+
File.open(path) do |f|
|
|
584
|
+
cur_filesize = filesize
|
|
585
|
+
while cur_filesize > 0
|
|
586
|
+
if cur_filesize >= file_division_size
|
|
587
|
+
d << f.read(file_division_size)
|
|
588
|
+
cur_filesize -= file_division_size
|
|
589
|
+
else
|
|
590
|
+
d << f.read(cur_filesize)
|
|
591
|
+
cur_filesize = 0
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
end
|
|
595
|
+
d.finish
|
|
596
|
+
|
|
597
|
+
pk = [
|
|
598
|
+
ZS_c_pk0708,
|
|
599
|
+
d.crc,
|
|
600
|
+
m.size,
|
|
601
|
+
d.size
|
|
602
|
+
]
|
|
603
|
+
bin = pk.pack('VVVV')
|
|
604
|
+
o << bin
|
|
605
|
+
data_positions << {
|
|
606
|
+
:folder => false,
|
|
607
|
+
:file => name,
|
|
608
|
+
:file_dos_time => filetime.to_binary_dos_time,
|
|
609
|
+
:file_dos_date => filetime.to_binary_dos_date,
|
|
610
|
+
:binary_fname => b_name,
|
|
611
|
+
:offset => data_offset,
|
|
612
|
+
:crc => d.crc,
|
|
613
|
+
:complen => m.size,
|
|
614
|
+
:uncomplen => d.size
|
|
615
|
+
}
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
def self.compress_file_list(o, files, dir, dirs, data_positions, usesjis = false, file_division_size = 1048576)
|
|
621
|
+
files.each do |f|
|
|
622
|
+
if File.directory? f
|
|
623
|
+
dirs << [f, dir.clone << File.basename(f)]
|
|
624
|
+
next
|
|
625
|
+
end
|
|
626
|
+
next unless File.file? f
|
|
627
|
+
data_offset = o.size
|
|
628
|
+
file_path = f
|
|
629
|
+
file = dir.clone << File.basename(file_path)
|
|
630
|
+
bfile = self.get_binary_fname(file, usesjis)
|
|
631
|
+
filetime = Zip::DOSTime.at(File.mtime(file_path))
|
|
632
|
+
filesize = File.size(file_path)
|
|
633
|
+
pk = [
|
|
634
|
+
ZS_c_pk0304,
|
|
635
|
+
ZS_c_ver_file,
|
|
636
|
+
ZS_c_opt_nosize,
|
|
637
|
+
ZS_c_comp_deflate,
|
|
638
|
+
filetime.to_binary_dos_time,
|
|
639
|
+
filetime.to_binary_dos_date,
|
|
640
|
+
ZS_c_int4_zero,
|
|
641
|
+
ZS_c_int4_zero,
|
|
642
|
+
ZS_c_int4_zero,
|
|
643
|
+
bfile.length,
|
|
644
|
+
ZS_c_int2_zero
|
|
645
|
+
]
|
|
646
|
+
bin = pk.pack('VvvvvvVVVvv')
|
|
647
|
+
o << bin
|
|
648
|
+
bin = bfile
|
|
649
|
+
o << bin
|
|
650
|
+
|
|
651
|
+
m = StreamMeter.new(o)
|
|
652
|
+
d = Zip::Deflater.new(m)
|
|
653
|
+
File.open(file_path) do |f|
|
|
654
|
+
cur_filesize = filesize
|
|
655
|
+
while cur_filesize > 0
|
|
656
|
+
if cur_filesize >= file_division_size
|
|
657
|
+
d << f.read(file_division_size)
|
|
658
|
+
cur_filesize -= file_division_size
|
|
659
|
+
else
|
|
660
|
+
d << f.read(cur_filesize)
|
|
661
|
+
cur_filesize = 0
|
|
662
|
+
end
|
|
663
|
+
end
|
|
664
|
+
end
|
|
665
|
+
d.finish
|
|
666
|
+
|
|
667
|
+
pk = [
|
|
668
|
+
ZS_c_pk0708,
|
|
669
|
+
d.crc,
|
|
670
|
+
m.size,
|
|
671
|
+
d.size
|
|
672
|
+
]
|
|
673
|
+
bin = pk.pack('VVVV')
|
|
674
|
+
o << bin
|
|
675
|
+
data_positions << {
|
|
676
|
+
:folder => false,
|
|
677
|
+
:file => file,
|
|
678
|
+
:file_dos_time => filetime.to_binary_dos_time,
|
|
679
|
+
:file_dos_date => filetime.to_binary_dos_date,
|
|
680
|
+
:binary_fname => bfile,
|
|
681
|
+
:offset => data_offset,
|
|
682
|
+
:crc => d.crc,
|
|
683
|
+
:complen => m.size,
|
|
684
|
+
:uncomplen => d.size
|
|
685
|
+
}
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
def self.create_central_dir_headers(o, data_positions)
|
|
691
|
+
data_positions.each do |dp|
|
|
692
|
+
pk = [
|
|
693
|
+
ZS_c_pk0102,
|
|
694
|
+
ZS_c_ver_made,
|
|
695
|
+
(dp[:folder] ? ZS_c_ver_dir : ZS_c_ver_file),
|
|
696
|
+
ZS_c_opt_nosize,
|
|
697
|
+
ZS_c_comp_deflate,
|
|
698
|
+
dp[:file_dos_time],
|
|
699
|
+
dp[:file_dos_date],
|
|
700
|
+
dp[:crc],
|
|
701
|
+
dp[:complen],
|
|
702
|
+
dp[:uncomplen],
|
|
703
|
+
dp[:binary_fname].length,
|
|
704
|
+
ZS_c_int2_zero,
|
|
705
|
+
ZS_c_int2_zero,
|
|
706
|
+
ZS_c_int2_zero,
|
|
707
|
+
ZS_c_int2_zero,
|
|
708
|
+
(dp[:folder] ? ZS_c_oattr_dir : ZS_c_oattr_file),
|
|
709
|
+
dp[:offset]
|
|
710
|
+
]
|
|
711
|
+
bin = pk.pack('VvvvvvvVVVvvvvvVV')
|
|
712
|
+
o << bin
|
|
713
|
+
bin = dp[:binary_fname]
|
|
714
|
+
o << bin
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
def self.create_end_cent_dir_header(o, entry_count, dirsize, offset)
|
|
719
|
+
pk = [
|
|
720
|
+
ZS_c_pk0506,
|
|
721
|
+
ZS_c_int2_zero,
|
|
722
|
+
ZS_c_int2_zero,
|
|
723
|
+
entry_count,
|
|
724
|
+
entry_count,
|
|
725
|
+
dirsize,
|
|
726
|
+
offset,
|
|
727
|
+
ZS_c_int2_zero
|
|
728
|
+
]
|
|
729
|
+
o << pk.pack('VvvvvVVv')
|
|
730
|
+
end
|
|
731
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
3
|
+
require 'rspec'
|
|
4
|
+
require 'zipping'
|
|
5
|
+
|
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
|
7
|
+
# in ./support/ and its subdirectories.
|
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
|
9
|
+
|
|
10
|
+
RSpec.configure do |config|
|
|
11
|
+
|
|
12
|
+
end
|
data/zipping.gemspec
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'zipping/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "zipping"
|
|
8
|
+
spec.version = Zipping::VERSION
|
|
9
|
+
spec.authors = ["Shuntaro Shitasako"]
|
|
10
|
+
spec.email = ["info@nekojarashi.com.com"]
|
|
11
|
+
spec.description = "This gem is for compressing files as a zip and outputting to a stream (or a stream-like interface object). The output to a stream proceeds little by little, as files are compressed."
|
|
12
|
+
spec.summary = "Compress files as a zip and output it to a stream."
|
|
13
|
+
spec.homepage = "http://www.nekojarashi.com"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files`.split($/)
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
|
22
|
+
spec.add_development_dependency "rake"
|
|
23
|
+
|
|
24
|
+
spec.add_dependency("rubyzip", [">= 1.0.0"])
|
|
25
|
+
spec.add_dependency("zip-zip", ["~> 0.2"])
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: zipping
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Shuntaro Shitasako
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2013-12-19 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.3'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.3'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - '>='
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - '>='
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rubyzip
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - '>='
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 1.0.0
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - '>='
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 1.0.0
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: zip-zip
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ~>
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0.2'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ~>
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0.2'
|
|
69
|
+
description: This gem is for compressing files as a zip and outputting to a stream
|
|
70
|
+
(or a stream-like interface object). The output to a stream proceeds little by little,
|
|
71
|
+
as files are compressed.
|
|
72
|
+
email:
|
|
73
|
+
- info@nekojarashi.com.com
|
|
74
|
+
executables: []
|
|
75
|
+
extensions: []
|
|
76
|
+
extra_rdoc_files: []
|
|
77
|
+
files:
|
|
78
|
+
- .gitignore
|
|
79
|
+
- .rspec
|
|
80
|
+
- Gemfile
|
|
81
|
+
- Gemfile.lock
|
|
82
|
+
- LICENSE.txt
|
|
83
|
+
- README.md
|
|
84
|
+
- Rakefile
|
|
85
|
+
- VERSION
|
|
86
|
+
- lib/zipping.rb
|
|
87
|
+
- lib/zipping/version.rb
|
|
88
|
+
- spec/spec_helper.rb
|
|
89
|
+
- spec/zipping_spec.rb
|
|
90
|
+
- zipping.gemspec
|
|
91
|
+
homepage: http://www.nekojarashi.com
|
|
92
|
+
licenses:
|
|
93
|
+
- MIT
|
|
94
|
+
metadata: {}
|
|
95
|
+
post_install_message:
|
|
96
|
+
rdoc_options: []
|
|
97
|
+
require_paths:
|
|
98
|
+
- lib
|
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - '>='
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
106
|
+
- - '>='
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '0'
|
|
109
|
+
requirements: []
|
|
110
|
+
rubyforge_project:
|
|
111
|
+
rubygems_version: 2.0.3
|
|
112
|
+
signing_key:
|
|
113
|
+
specification_version: 4
|
|
114
|
+
summary: Compress files as a zip and output it to a stream.
|
|
115
|
+
test_files:
|
|
116
|
+
- spec/spec_helper.rb
|
|
117
|
+
- spec/zipping_spec.rb
|