zip_kit 6.2.0 → 6.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 +4 -4
- data/CHANGELOG.md +6 -1
- data/CONTRIBUTING.md +2 -2
- data/README.md +30 -21
- data/lib/zip_kit/block_write.rb +4 -1
- data/lib/zip_kit/output_enumerator.rb +16 -5
- data/lib/zip_kit/rails_streaming.rb +32 -13
- data/lib/zip_kit/streamer.rb +11 -11
- data/lib/zip_kit/version.rb +1 -1
- data/lib/zip_kit/write_shovel.rb +2 -2
- data/rbi/zip_kit.rbi +52 -42
- data/zip_kit.gemspec +6 -3
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1d33b58f4501d3ddbae7abcab3957fde0549abf734eae72ca1a7ce45601f479
|
4
|
+
data.tar.gz: e9126924e6fe75329237ba551a1a65218676c7d2b3757f4ad91e73eb0bce154e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 011e57f856ebe7f625b0bfa5eeb4a240c6c38f2b07ff0434b7e89805516b2d47b6d4230ac404203d00562586909c72d7ea225a7238d47af70fb99ed97b3d50bc
|
7
|
+
data.tar.gz: b68fbaae2e57314c47e7971aeef2150341ba80308c7dee1536718250f5cac01b4b387fe3f73cde5f84fb1ffcd93500343ec451d0fccf9f19b2c0c4a58e74aa2f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## 6.2.1
|
2
|
+
|
3
|
+
* Make `RailsStreaming` compatible with `ActionController::Live` (previously the response would hang)
|
4
|
+
* Make `BlockWrite` respond to `write` in addition to `<<`
|
5
|
+
|
1
6
|
## 6.2.0
|
2
7
|
|
3
8
|
* Remove forced `Transfer-Encoding: chunked` and the chunking body wrapper. It is actually a good idea to trust the app webserver to apply the transfer encoding as is appropriate. For the case when "you really have to", add a bypass in `RailsStreaming#zip_kit_stream` for forcing the chunking manually.
|
@@ -149,7 +154,7 @@
|
|
149
154
|
## 4.4.2
|
150
155
|
|
151
156
|
* Add 2.4 to Travis rubies
|
152
|
-
* Fix a severe performance degradation in Streamer with large file counts (https://github.com/WeTransfer/
|
157
|
+
* Fix a severe performance degradation in Streamer with large file counts (https://github.com/WeTransfer/zip_tricks/pull/14)
|
153
158
|
|
154
159
|
## 4.4.1
|
155
160
|
|
data/CONTRIBUTING.md
CHANGED
@@ -106,11 +106,11 @@ project:
|
|
106
106
|
|
107
107
|
```bash
|
108
108
|
# Clone your fork of the repo into the current directory
|
109
|
-
git clone git@github.com:
|
109
|
+
git clone git@github.com:julik/zip_kit.git
|
110
110
|
# Navigate to the newly cloned directory
|
111
111
|
cd zip_kit
|
112
112
|
# Assign the original repo to a remote called "upstream"
|
113
|
-
git remote add upstream git@github.com:
|
113
|
+
git remote add upstream git@github.com:julik/zip_kit.git
|
114
114
|
```
|
115
115
|
|
116
116
|
2. If you cloned a while ago, get the latest changes from upstream:
|
data/README.md
CHANGED
@@ -59,7 +59,7 @@ via HTTP.
|
|
59
59
|
and the ZIP output will run in the same thread as your main request. Your testing flows (be it minitest or
|
60
60
|
RSpec) should work normally with controller actions returning ZIPs.
|
61
61
|
|
62
|
-
## Writing into
|
62
|
+
## Writing into streaming destinations
|
63
63
|
|
64
64
|
Any object that accepts bytes via either `<<` or `write` methods can be a write destination. For example, here
|
65
65
|
is how to upload a sizeable ZIP to S3 - the SDK will happily chop your upload into multipart upload parts:
|
@@ -69,23 +69,23 @@ bucket = Aws::S3::Bucket.new("mybucket")
|
|
69
69
|
obj = bucket.object("big.zip")
|
70
70
|
obj.upload_stream do |write_stream|
|
71
71
|
ZipKit::Streamer.open(write_stream) do |zip|
|
72
|
-
zip.write_file("
|
73
|
-
|
74
|
-
|
75
|
-
20_000.times do |n|
|
76
|
-
csv << [n, "Item number #{n}"]
|
77
|
-
end
|
72
|
+
zip.write_file("file.csv") do |sink|
|
73
|
+
File.open("large.csv", "rb") do |file_input|
|
74
|
+
IO.copy_stream(file_input, sink)
|
78
75
|
end
|
79
76
|
end
|
80
77
|
end
|
81
78
|
end
|
82
79
|
```
|
83
80
|
|
81
|
+
## Writing through streaming wrappers
|
82
|
+
|
84
83
|
Any object that writes using either `<<` or `write` can write into a `sink`. For example, you can do streaming
|
85
|
-
output with [builder](https://github.com/jimweirich/builder#project-builder)
|
84
|
+
output with [builder](https://github.com/jimweirich/builder#project-builder) which calls `<<` on its `target`
|
85
|
+
every time a complete write call is done:
|
86
86
|
|
87
87
|
```ruby
|
88
|
-
zip.write_file('
|
88
|
+
zip.write_file('employees.xml') do |sink|
|
89
89
|
builder = Builder::XmlMarkup.new(target: sink, indent: 2)
|
90
90
|
builder.people do
|
91
91
|
Person.all.find_each do |person|
|
@@ -95,8 +95,18 @@ zip.write_file('report1.csv') do |sink|
|
|
95
95
|
end
|
96
96
|
```
|
97
97
|
|
98
|
-
|
99
|
-
|
98
|
+
The output will be compressed and output into the ZIP file on the fly. Same for CSV:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
zip.write_file('line_items.csv') do |sink|
|
102
|
+
CSV(sink) do |csv|
|
103
|
+
csv << ["Line", "Item"]
|
104
|
+
20_000.times do |n|
|
105
|
+
csv << [n, "Item number #{n}"]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
```
|
100
110
|
|
101
111
|
## Create a ZIP file without size estimation, compress on-the-fly during writes
|
102
112
|
|
@@ -122,12 +132,10 @@ since you do not know how large the compressed data segments are going to be.
|
|
122
132
|
## Send a ZIP from a Rack response
|
123
133
|
|
124
134
|
zip_kit provides an `OutputEnumerator` object which will yield the binary chunks piece
|
125
|
-
by piece, and apply some amount of buffering as well.
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
start executing once your response body starts getting iterated over - when actually sending
|
130
|
-
the response to the client (unless you are using a buffering Rack webserver, such as Webrick).
|
135
|
+
by piece, and apply some amount of buffering as well. Return the headers and the body to your webserver
|
136
|
+
and you will have your ZIP streamed! The block that you give to the `OutputEnumerator` will receive
|
137
|
+
the {ZipKit::Streamer} object and will only start executing once your response body starts getting iterated
|
138
|
+
over - when actually sending the response to the client (unless you are using a buffering Rack webserver, such as Webrick).
|
131
139
|
|
132
140
|
```ruby
|
133
141
|
body = ZipKit::OutputEnumerator.new do | zip |
|
@@ -139,8 +147,7 @@ body = ZipKit::OutputEnumerator.new do | zip |
|
|
139
147
|
end
|
140
148
|
end
|
141
149
|
|
142
|
-
|
143
|
-
[200, headers, streaming_body]
|
150
|
+
[200, body.streaming_http_headers, body]
|
144
151
|
```
|
145
152
|
|
146
153
|
## Send a ZIP file of known size, with correct headers
|
@@ -160,8 +167,10 @@ zip_body = ZipKit::OutputEnumerator.new do | zip |
|
|
160
167
|
zip << read_file('myfile2.bin')
|
161
168
|
end
|
162
169
|
|
163
|
-
|
164
|
-
[
|
170
|
+
hh = zip_body.streaming_http_headers
|
171
|
+
hh["Content-Length"] = bytesize.to_s
|
172
|
+
|
173
|
+
[200, hh, zip_body]
|
165
174
|
```
|
166
175
|
|
167
176
|
## Writing ZIP files using the Streamer bypass
|
data/lib/zip_kit/block_write.rb
CHANGED
@@ -17,9 +17,12 @@
|
|
17
17
|
# end
|
18
18
|
# [200, {}, MyRackResponse.new]
|
19
19
|
class ZipKit::BlockWrite
|
20
|
+
include ZipKit::WriteShovel
|
21
|
+
|
20
22
|
# Creates a new BlockWrite.
|
21
23
|
#
|
22
24
|
# @param block The block that will be called when this object receives the `<<` message
|
25
|
+
# @yieldparam bytes[String] A string in binary encoding which has just been written into the object
|
23
26
|
def initialize(&block)
|
24
27
|
@block = block
|
25
28
|
end
|
@@ -36,7 +39,7 @@ class ZipKit::BlockWrite
|
|
36
39
|
# @param buf[String] the string to write. Note that a zero-length String
|
37
40
|
# will not be forwarded to the block, as it has special meaning when used
|
38
41
|
# with chunked encoding (it indicates the end of the stream).
|
39
|
-
# @return
|
42
|
+
# @return [ZipKit::BlockWrite]
|
40
43
|
def <<(buf)
|
41
44
|
# Zero-size output has a special meaning when using chunked encoding
|
42
45
|
return if buf.nil? || buf.bytesize.zero?
|
@@ -60,14 +60,11 @@ class ZipKit::OutputEnumerator
|
|
60
60
|
# ...
|
61
61
|
# end
|
62
62
|
#
|
63
|
-
# @param kwargs_for_new [Hash] keyword arguments for {Streamer.new}
|
64
|
-
# @return [ZipKit::OutputEnumerator] the enumerator you can read bytestrings of the ZIP from by calling `each`
|
65
|
-
#
|
66
63
|
# @param streamer_options[Hash] options for Streamer, see {ZipKit::Streamer.new}
|
67
64
|
# @param write_buffer_size[Integer] By default all ZipKit writes are unbuffered. For output to sockets
|
68
65
|
# it is beneficial to bulkify those writes so that they are roughly sized to a socket buffer chunk. This
|
69
66
|
# object will bulkify writes for you in this way (so `each` will yield not on every call to `<<` from the Streamer
|
70
|
-
# but at block size boundaries or greater). Set
|
67
|
+
# but at block size boundaries or greater). Set the parameter to 0 for unbuffered writes.
|
71
68
|
# @param blk a block that will receive the Streamer object when executing. The block will not be executed
|
72
69
|
# immediately but only once `each` is called on the OutputEnumerator
|
73
70
|
def initialize(write_buffer_size: DEFAULT_WRITE_BUFFER_SIZE, **streamer_options, &blk)
|
@@ -100,9 +97,14 @@ class ZipKit::OutputEnumerator
|
|
100
97
|
end
|
101
98
|
|
102
99
|
# Returns a Hash of HTTP response headers you are likely to need to have your response stream correctly.
|
100
|
+
# This is on the {ZipKit::OutputEnumerator} class since those headers are common, independent of the
|
101
|
+
# particular response body getting served. You might want to override the headers with your particular
|
102
|
+
# ones - for example, specific content types are needed for files which are, technically, ZIP files
|
103
|
+
# but are of a file format built "on top" of ZIPs - such as ODTs, [pkpass files](https://developer.apple.com/documentation/walletpasses/building_a_pass)
|
104
|
+
# and ePubs.
|
103
105
|
#
|
104
106
|
# @return [Hash]
|
105
|
-
def streaming_http_headers
|
107
|
+
def self.streaming_http_headers
|
106
108
|
_headers = {
|
107
109
|
# We need to ensure Rack::ETag does not suddenly start buffering us, see
|
108
110
|
# https://github.com/rack/rack/issues/1619#issuecomment-606315714
|
@@ -121,6 +123,15 @@ class ZipKit::OutputEnumerator
|
|
121
123
|
}
|
122
124
|
end
|
123
125
|
|
126
|
+
# Returns a Hash of HTTP response headers for this particular response. This used to contain "Content-Length" for
|
127
|
+
# presized responses, but is now effectively a no-op.
|
128
|
+
#
|
129
|
+
# @see [ZipKit::OutputEnumerator.streaming_http_headers]
|
130
|
+
# @return [Hash]
|
131
|
+
def streaming_http_headers
|
132
|
+
self.class.streaming_http_headers
|
133
|
+
end
|
134
|
+
|
124
135
|
# Returns a tuple of `headers, body` - headers are a `Hash` and the body is
|
125
136
|
# an object that can be used as a Rack response body. This method used to accept arguments
|
126
137
|
# but will now just ignore them.
|
@@ -13,10 +13,6 @@ module ZipKit::RailsStreaming
|
|
13
13
|
# @yieldparam [ZipKit::Streamer] the streamer that can be written to
|
14
14
|
# @return [ZipKit::OutputEnumerator] The output enumerator assigned to the response body
|
15
15
|
def zip_kit_stream(filename: "download.zip", type: "application/zip", use_chunked_transfer_encoding: false, **zip_streamer_options, &zip_streaming_blk)
|
16
|
-
# The output enumerator yields chunks of bytes generated from ZipKit. Instantiating it
|
17
|
-
# first will also validate the Streamer options.
|
18
|
-
output_enum = ZipKit::OutputEnumerator.new(**zip_streamer_options, &zip_streaming_blk)
|
19
|
-
|
20
16
|
# We want some common headers for file sending. Rails will also set
|
21
17
|
# self.sending_file = true for us when we call send_file_headers!
|
22
18
|
send_file_headers!(type: type, filename: filename)
|
@@ -29,16 +25,39 @@ module ZipKit::RailsStreaming
|
|
29
25
|
logger&.warn { "The downstream HTTP proxy/LB insists on HTTP/1.0 protocol, ZIP response will be buffered." }
|
30
26
|
end
|
31
27
|
|
32
|
-
headers =
|
28
|
+
headers = ZipKit::OutputEnumerator.streaming_http_headers
|
29
|
+
response.headers.merge!(headers)
|
33
30
|
|
34
|
-
#
|
35
|
-
#
|
36
|
-
|
37
|
-
output_enum = ZipKit::RackChunkedBody.new(output_enum)
|
38
|
-
headers["Transfer-Encoding"] = "chunked"
|
39
|
-
end
|
31
|
+
# The output enumerator yields chunks of bytes generated from the Streamer,
|
32
|
+
# with some buffering
|
33
|
+
output_enum = ZipKit::OutputEnumerator.new(**zip_streamer_options, &zip_streaming_blk)
|
40
34
|
|
41
|
-
|
42
|
-
|
35
|
+
# Time for some branching, which mostly has to do with the 999 flavours of
|
36
|
+
# "how to make both Rails and Rack stream"
|
37
|
+
if self.class.ancestors.include?(ActionController::Live)
|
38
|
+
# If this controller includes Live it will not work correctly with a Rack
|
39
|
+
# response body assignment - we need to write into the Live output stream instead
|
40
|
+
begin
|
41
|
+
output_enum.each { |bytes| response.stream.write(bytes) }
|
42
|
+
ensure
|
43
|
+
response.stream.close
|
44
|
+
end
|
45
|
+
elsif use_chunked_transfer_encoding
|
46
|
+
# Chunked encoding may be forced if, for example, you _need_ to bypass Rack::ContentLength.
|
47
|
+
# Rack::ContentLength is normally not in a Rails middleware stack, but it might get
|
48
|
+
# introduced unintentionally - for example, "rackup" adds the ContentLength middleware for you.
|
49
|
+
# There is a recommendation to leave the chunked encoding to the app server, so that servers
|
50
|
+
# that support HTTP/2 can use native framing and not have to deal with the chunked encoding,
|
51
|
+
# see https://github.com/julik/zip_kit/issues/7
|
52
|
+
# But it is not to be excluded that a user may need to force the chunked encoding to bypass
|
53
|
+
# some especially pesky Rack middleware that just would not cooperate. Those include
|
54
|
+
# Rack::MiniProfiler and the above-mentioned Rack::ContentLength.
|
55
|
+
response.headers["Transfer-Encoding"] = "chunked"
|
56
|
+
self.response_body = ZipKit::RackChunkedBody.new(output_enum)
|
57
|
+
else
|
58
|
+
# Stream using a Rack body assigned to the ActionController response body, without
|
59
|
+
# doing explicit chunked encoding. See above for the reasoning.
|
60
|
+
self.response_body = output_enum
|
61
|
+
end
|
43
62
|
end
|
44
63
|
end
|
data/lib/zip_kit/streamer.rb
CHANGED
@@ -2,19 +2,19 @@
|
|
2
2
|
|
3
3
|
require "set"
|
4
4
|
|
5
|
-
# Is used to write
|
6
|
-
#
|
7
|
-
# of this object can be coupled directly to, say, a Rack output. The
|
8
|
-
# output can also be a String, Array or anything that responds to `<<`.
|
5
|
+
# Is used to write ZIP archives without having to read them back or to overwrite
|
6
|
+
# data. It outputs into any object that supports `<<` or `write`, namely:
|
9
7
|
#
|
10
|
-
#
|
11
|
-
#
|
8
|
+
# An `Array`, `File`, `IO`, `Socket` and even `String` all can be output destinations
|
9
|
+
# for the `Streamer`.
|
12
10
|
#
|
13
|
-
#
|
14
|
-
#
|
11
|
+
# You can also combine output through the `Streamer` with direct output to the destination,
|
12
|
+
# all while preserving the correct offsets in the ZIP file structures. This allows usage
|
13
|
+
# of `sendfile()` or socket `splice()` calls for "through" proxying.
|
15
14
|
#
|
16
|
-
#
|
17
|
-
#
|
15
|
+
# If you want to avoid data descriptors - or write data bypassing the Streamer -
|
16
|
+
# you need to know the CRC32 (as a uint) and the filesize upfront,
|
17
|
+
# before the writing of the entry body starts.
|
18
18
|
#
|
19
19
|
# ## Using the Streamer with runtime compression
|
20
20
|
#
|
@@ -34,7 +34,7 @@ require "set"
|
|
34
34
|
# end
|
35
35
|
# end
|
36
36
|
#
|
37
|
-
# The central directory will be written automatically at the end of the block.
|
37
|
+
# The central directory will be written automatically at the end of the `open` block.
|
38
38
|
#
|
39
39
|
# ## Using the Streamer with entries of known size and having a known CRC32 checksum
|
40
40
|
#
|
data/lib/zip_kit/version.rb
CHANGED
data/lib/zip_kit/write_shovel.rb
CHANGED
@@ -13,8 +13,8 @@ module ZipKit::WriteShovel
|
|
13
13
|
# Writes the given data to the output stream. Allows the object to be used as
|
14
14
|
# a target for `IO.copy_stream(from, to)`
|
15
15
|
#
|
16
|
-
# @param
|
17
|
-
# @return [Fixnum] the number of bytes written
|
16
|
+
# @param bytes[String] the binary string to write (part of the uncompressed file)
|
17
|
+
# @return [Fixnum] the number of bytes written (will always be the bytesize of `bytes`)
|
18
18
|
def write(bytes)
|
19
19
|
self << bytes
|
20
20
|
bytes.bytesize
|
data/rbi/zip_kit.rbi
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# typed: strong
|
2
2
|
module ZipKit
|
3
|
-
VERSION = T.let("6.2.
|
3
|
+
VERSION = T.let("6.2.1", T.untyped)
|
4
4
|
|
5
5
|
# A ZIP archive contains a flat list of entries. These entries can implicitly
|
6
6
|
# create directories when the archive is expanded. For example, an entry with
|
@@ -100,19 +100,19 @@ module ZipKit
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
# Is used to write
|
104
|
-
#
|
105
|
-
# of this object can be coupled directly to, say, a Rack output. The
|
106
|
-
# output can also be a String, Array or anything that responds to `<<`.
|
103
|
+
# Is used to write ZIP archives without having to read them back or to overwrite
|
104
|
+
# data. It outputs into any object that supports `<<` or `write`, namely:
|
107
105
|
#
|
108
|
-
#
|
109
|
-
#
|
106
|
+
# An `Array`, `File`, `IO`, `Socket` and even `String` all can be output destinations
|
107
|
+
# for the `Streamer`.
|
110
108
|
#
|
111
|
-
#
|
112
|
-
#
|
109
|
+
# You can also combine output through the `Streamer` with direct output to the destination,
|
110
|
+
# all while preserving the correct offsets in the ZIP file structures. This allows usage
|
111
|
+
# of `sendfile()` or socket `splice()` calls for "through" proxying.
|
113
112
|
#
|
114
|
-
#
|
115
|
-
#
|
113
|
+
# If you want to avoid data descriptors - or write data bypassing the Streamer -
|
114
|
+
# you need to know the CRC32 (as a uint) and the filesize upfront,
|
115
|
+
# before the writing of the entry body starts.
|
116
116
|
#
|
117
117
|
# ## Using the Streamer with runtime compression
|
118
118
|
#
|
@@ -132,7 +132,7 @@ module ZipKit
|
|
132
132
|
# end
|
133
133
|
# end
|
134
134
|
#
|
135
|
-
# The central directory will be written automatically at the end of the block.
|
135
|
+
# The central directory will be written automatically at the end of the `open` block.
|
136
136
|
#
|
137
137
|
# ## Using the Streamer with entries of known size and having a known CRC32 checksum
|
138
138
|
#
|
@@ -563,13 +563,12 @@ module ZipKit
|
|
563
563
|
sig { params(filename: T.untyped).returns(T.untyped) }
|
564
564
|
def remove_backslash(filename); end
|
565
565
|
|
566
|
-
# sord infer - argument name in single @param inferred as "bytes"
|
567
566
|
# Writes the given data to the output stream. Allows the object to be used as
|
568
567
|
# a target for `IO.copy_stream(from, to)`
|
569
568
|
#
|
570
|
-
# _@param_ `
|
569
|
+
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
571
570
|
#
|
572
|
-
# _@return_ — the number of bytes written
|
571
|
+
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
573
572
|
sig { params(bytes: String).returns(Fixnum) }
|
574
573
|
def write(bytes); end
|
575
574
|
|
@@ -678,13 +677,12 @@ module ZipKit
|
|
678
677
|
sig { returns(T.untyped) }
|
679
678
|
def close; end
|
680
679
|
|
681
|
-
# sord infer - argument name in single @param inferred as "bytes"
|
682
680
|
# Writes the given data to the output stream. Allows the object to be used as
|
683
681
|
# a target for `IO.copy_stream(from, to)`
|
684
682
|
#
|
685
|
-
# _@param_ `
|
683
|
+
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
686
684
|
#
|
687
|
-
# _@return_ — the number of bytes written
|
685
|
+
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
688
686
|
sig { params(bytes: String).returns(Fixnum) }
|
689
687
|
def write(bytes); end
|
690
688
|
end
|
@@ -748,13 +746,12 @@ module ZipKit
|
|
748
746
|
sig { returns(T::Hash[T.untyped, T.untyped]) }
|
749
747
|
def finish; end
|
750
748
|
|
751
|
-
# sord infer - argument name in single @param inferred as "bytes"
|
752
749
|
# Writes the given data to the output stream. Allows the object to be used as
|
753
750
|
# a target for `IO.copy_stream(from, to)`
|
754
751
|
#
|
755
|
-
# _@param_ `
|
752
|
+
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
756
753
|
#
|
757
|
-
# _@return_ — the number of bytes written
|
754
|
+
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
758
755
|
sig { params(bytes: String).returns(Fixnum) }
|
759
756
|
def write(bytes); end
|
760
757
|
end
|
@@ -787,13 +784,12 @@ module ZipKit
|
|
787
784
|
sig { returns(T::Hash[T.untyped, T.untyped]) }
|
788
785
|
def finish; end
|
789
786
|
|
790
|
-
# sord infer - argument name in single @param inferred as "bytes"
|
791
787
|
# Writes the given data to the output stream. Allows the object to be used as
|
792
788
|
# a target for `IO.copy_stream(from, to)`
|
793
789
|
#
|
794
|
-
# _@param_ `
|
790
|
+
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
795
791
|
#
|
796
|
-
# _@return_ — the number of bytes written
|
792
|
+
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
797
793
|
sig { params(bytes: String).returns(Fixnum) }
|
798
794
|
def write(bytes); end
|
799
795
|
end
|
@@ -1107,19 +1103,28 @@ end, T.untyped)
|
|
1107
1103
|
# end
|
1108
1104
|
# [200, {}, MyRackResponse.new]
|
1109
1105
|
class BlockWrite
|
1106
|
+
include ZipKit::WriteShovel
|
1107
|
+
|
1110
1108
|
# Creates a new BlockWrite.
|
1111
1109
|
#
|
1112
1110
|
# _@param_ `block` — The block that will be called when this object receives the `<<` message
|
1113
|
-
sig { params(block: T.
|
1111
|
+
sig { params(block: T.proc.params(bytes: String).void).void }
|
1114
1112
|
def initialize(&block); end
|
1115
1113
|
|
1116
1114
|
# Sends a string through to the block stored in the BlockWrite.
|
1117
1115
|
#
|
1118
1116
|
# _@param_ `buf` — the string to write. Note that a zero-length String will not be forwarded to the block, as it has special meaning when used with chunked encoding (it indicates the end of the stream).
|
1119
|
-
|
1120
|
-
# _@return_ — self
|
1121
|
-
sig { params(buf: String).returns(T.untyped) }
|
1117
|
+
sig { params(buf: String).returns(ZipKit::BlockWrite) }
|
1122
1118
|
def <<(buf); end
|
1119
|
+
|
1120
|
+
# Writes the given data to the output stream. Allows the object to be used as
|
1121
|
+
# a target for `IO.copy_stream(from, to)`
|
1122
|
+
#
|
1123
|
+
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
1124
|
+
#
|
1125
|
+
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
1126
|
+
sig { params(bytes: String).returns(Fixnum) }
|
1127
|
+
def write(bytes); end
|
1123
1128
|
end
|
1124
1129
|
|
1125
1130
|
# A very barebones ZIP file reader. Is made for maximum interoperability, but at the same
|
@@ -1657,13 +1662,12 @@ end, T.untyped)
|
|
1657
1662
|
sig { params(crc32: Fixnum, blob_size: Fixnum).returns(Fixnum) }
|
1658
1663
|
def append(crc32, blob_size); end
|
1659
1664
|
|
1660
|
-
# sord infer - argument name in single @param inferred as "bytes"
|
1661
1665
|
# Writes the given data to the output stream. Allows the object to be used as
|
1662
1666
|
# a target for `IO.copy_stream(from, to)`
|
1663
1667
|
#
|
1664
|
-
# _@param_ `
|
1668
|
+
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
1665
1669
|
#
|
1666
|
-
# _@return_ — the number of bytes written
|
1670
|
+
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
1667
1671
|
sig { params(bytes: String).returns(Fixnum) }
|
1668
1672
|
def write(bytes); end
|
1669
1673
|
end
|
@@ -1728,13 +1732,12 @@ end, T.untyped)
|
|
1728
1732
|
# "IO-ish" things to also respond to `write`? This is what this module does.
|
1729
1733
|
# Jim would be proud. We miss you, Jim.
|
1730
1734
|
module WriteShovel
|
1731
|
-
# sord infer - argument name in single @param inferred as "bytes"
|
1732
1735
|
# Writes the given data to the output stream. Allows the object to be used as
|
1733
1736
|
# a target for `IO.copy_stream(from, to)`
|
1734
1737
|
#
|
1735
|
-
# _@param_ `
|
1738
|
+
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
1736
1739
|
#
|
1737
|
-
# _@return_ — the number of bytes written
|
1740
|
+
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
1738
1741
|
sig { params(bytes: String).returns(Fixnum) }
|
1739
1742
|
def write(bytes); end
|
1740
1743
|
end
|
@@ -1960,13 +1963,12 @@ end, T.untyped)
|
|
1960
1963
|
sig { returns(T.untyped) }
|
1961
1964
|
def tell; end
|
1962
1965
|
|
1963
|
-
# sord infer - argument name in single @param inferred as "bytes"
|
1964
1966
|
# Writes the given data to the output stream. Allows the object to be used as
|
1965
1967
|
# a target for `IO.copy_stream(from, to)`
|
1966
1968
|
#
|
1967
|
-
# _@param_ `
|
1969
|
+
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
1968
1970
|
#
|
1969
|
-
# _@return_ — the number of bytes written
|
1971
|
+
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
1970
1972
|
sig { params(bytes: String).returns(Fixnum) }
|
1971
1973
|
def write(bytes); end
|
1972
1974
|
end
|
@@ -2056,15 +2058,11 @@ end, T.untyped)
|
|
2056
2058
|
# ...
|
2057
2059
|
# end
|
2058
2060
|
#
|
2059
|
-
# _@param_ `kwargs_for_new` — keyword arguments for {Streamer.new}
|
2060
|
-
#
|
2061
2061
|
# _@param_ `streamer_options` — options for Streamer, see {ZipKit::Streamer.new}
|
2062
2062
|
#
|
2063
|
-
# _@param_ `write_buffer_size` — By default all ZipKit writes are unbuffered. For output to sockets it is beneficial to bulkify those writes so that they are roughly sized to a socket buffer chunk. This object will bulkify writes for you in this way (so `each` will yield not on every call to `<<` from the Streamer but at block size boundaries or greater). Set
|
2063
|
+
# _@param_ `write_buffer_size` — By default all ZipKit writes are unbuffered. For output to sockets it is beneficial to bulkify those writes so that they are roughly sized to a socket buffer chunk. This object will bulkify writes for you in this way (so `each` will yield not on every call to `<<` from the Streamer but at block size boundaries or greater). Set the parameter to 0 for unbuffered writes.
|
2064
2064
|
#
|
2065
2065
|
# _@param_ `blk` — a block that will receive the Streamer object when executing. The block will not be executed immediately but only once `each` is called on the OutputEnumerator
|
2066
|
-
#
|
2067
|
-
# _@return_ — the enumerator you can read bytestrings of the ZIP from by calling `each`
|
2068
2066
|
sig { params(write_buffer_size: Integer, streamer_options: T::Hash[T.untyped, T.untyped], blk: T.untyped).void }
|
2069
2067
|
def initialize(write_buffer_size: DEFAULT_WRITE_BUFFER_SIZE, **streamer_options, &blk); end
|
2070
2068
|
|
@@ -2083,6 +2081,18 @@ end, T.untyped)
|
|
2083
2081
|
def each; end
|
2084
2082
|
|
2085
2083
|
# Returns a Hash of HTTP response headers you are likely to need to have your response stream correctly.
|
2084
|
+
# This is on the {ZipKit::OutputEnumerator} class since those headers are common, independent of the
|
2085
|
+
# particular response body getting served. You might want to override the headers with your particular
|
2086
|
+
# ones - for example, specific content types are needed for files which are, technically, ZIP files
|
2087
|
+
# but are of a file format built "on top" of ZIPs - such as ODTs, [pkpass files](https://developer.apple.com/documentation/walletpasses/building_a_pass)
|
2088
|
+
# and ePubs.
|
2089
|
+
sig { returns(T::Hash[T.untyped, T.untyped]) }
|
2090
|
+
def self.streaming_http_headers; end
|
2091
|
+
|
2092
|
+
# Returns a Hash of HTTP response headers for this particular response. This used to contain "Content-Length" for
|
2093
|
+
# presized responses, but is now effectively a no-op.
|
2094
|
+
#
|
2095
|
+
# _@see_ `[ZipKit::OutputEnumerator.streaming_http_headers]`
|
2086
2096
|
sig { returns(T::Hash[T.untyped, T.untyped]) }
|
2087
2097
|
def streaming_http_headers; end
|
2088
2098
|
|
data/zip_kit.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.version = ZipKit::VERSION
|
8
8
|
spec.authors = ["Julik Tarkhanov", "Noah Berman", "Dmitry Tymchuk", "David Bosveld", "Felix Bünemann"]
|
9
9
|
spec.email = ["me@julik.nl"]
|
10
|
-
|
10
|
+
spec.license = "MIT"
|
11
11
|
spec.summary = "Stream out ZIP files from Ruby. Successor to zip_tricks."
|
12
12
|
spec.description = "Stream out ZIP files from Ruby. Successor to zip_tricks."
|
13
13
|
spec.homepage = "https://github.com/julik/zip_kit"
|
@@ -23,9 +23,12 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler"
|
26
|
-
spec.add_development_dependency "rubyzip", "~> 1"
|
27
26
|
|
28
|
-
|
27
|
+
# zip_kit does not use any runtime dependencies (besides zlib). However, for testing
|
28
|
+
# things quite a few things are used - and for a good reason.
|
29
|
+
|
30
|
+
spec.add_development_dependency "rubyzip", "~> 1" # We test our output with _another_ ZIP library, which is the way to go here
|
31
|
+
spec.add_development_dependency "rack" # For tests where we spin up a server. Both for streaming out and for testing reads over HTTP
|
29
32
|
spec.add_development_dependency "rake", "~> 12.2"
|
30
33
|
spec.add_development_dependency "rspec", "~> 3"
|
31
34
|
spec.add_development_dependency "rspec-mocks", "~> 3.10", ">= 3.10.2" # ruby 3 compatibility
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zip_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.2.
|
4
|
+
version: 6.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: exe
|
14
14
|
cert_chain: []
|
15
|
-
date: 2024-03-
|
15
|
+
date: 2024-03-23 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: bundler
|
@@ -324,7 +324,8 @@ files:
|
|
324
324
|
- rbi/zip_kit.rbi
|
325
325
|
- zip_kit.gemspec
|
326
326
|
homepage: https://github.com/julik/zip_kit
|
327
|
-
licenses:
|
327
|
+
licenses:
|
328
|
+
- MIT
|
328
329
|
metadata:
|
329
330
|
allowed_push_host: https://rubygems.org
|
330
331
|
post_install_message:
|