zip_kit 6.2.2 → 6.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1136ebba851638486c9e47150a8d706c49a2bbc0074f457c794582d8ce19089
4
- data.tar.gz: 80de3edcb5bc748aaf855a7bf0b1f19439522c8efa4b97754f813fe9413bac2c
3
+ metadata.gz: 442833a965d373fd56e8d085164f536e17560ed4a74e11aab5befc61946de1bc
4
+ data.tar.gz: 6c470314702d643b8f5b55fb3a328ab62cecfe1982587df9b8179fd84bf9013e
5
5
  SHA512:
6
- metadata.gz: 20c5922a4178f2068a4f06388b201bd263f01c387d308c2c6297feba1c05385d601072cae0451d59a4a0b4e1ba1e354a6fa7f622ff1b58daf70947e6991b1e82
7
- data.tar.gz: c373972ec6980000b40d1808247759b44f317a7aa3795b406e02005412cf0687e0f2311e5809f011eb1fbc19e6b2b7eb2a6a8f036cafe27a2645f6476cf0c441
6
+ metadata.gz: 8532b5faf979cc98ba0f1e05dff6adf3e6748466553446397c3f7f706fe663182f8fab47a973e3e911b2457eb0622579a62d7b35c1fe18644b7ea05541d7e316
7
+ data.tar.gz: 377ef88938f5ec86ea6cd2e15c6857eac9ff2ffc25bb629cf2a0d0ba774a823013e4b4061d1a5392dc4b88e8cbd3d022a1f90e41d1cb68ad72c5e9d42f3c51cd
@@ -14,7 +14,7 @@ jobs:
14
14
  matrix:
15
15
  ruby:
16
16
  - '2.6'
17
- - '3.2'
17
+ - '3.3'
18
18
  steps:
19
19
  - name: Checkout
20
20
  uses: actions/checkout@v4
data/.yardopts CHANGED
@@ -1 +1 @@
1
- --markup markdown
1
+ --markup markdown --no-private --protected lib/**/*.rb - LICENSE.txt IMPLEMENTATION_DETAILS.md RUBYZIP_DIFFERENCES.md CONTRIBUTING.md CODE_OF_CONDUCT.md CHANGELOG.md
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 6.3.1
2
+
3
+ * Include `RailsStreaming` in a Rails loader callback, so that ActionController does not need to be in the namespace.
4
+
5
+ ## 6.3.0
6
+
7
+ * Include `RailsStreaming` automatically via a Railtie. It is not really necessary to force people to manage it manually.
8
+
1
9
  ## 6.2.2
2
10
 
3
11
  * Make sure "zlib" gets required at the top, as it is used everywhere
data/CONTRIBUTING.md CHANGED
@@ -16,7 +16,7 @@ If you are interested in contributing code and would like to learn more about th
16
16
 
17
17
  - [ruby](https://ruby-doc.org)
18
18
  - [rubyzip](https://github.com/rubyzip/rubyzip) as we like to test "our implementation against theirs"
19
- - [rspec](http://rspec.info/) and [appraisal]() https://github.com/thoughtbot/appraisal) for testing
19
+ - [rspec](http://rspec.info/) for testing
20
20
  - [zip files](https://en.wikipedia.org/wiki/Zip_(file_format))
21
21
 
22
22
  # How do I make a contribution?
@@ -5,6 +5,7 @@ The ZipKit streaming implementation is designed around the following requirement
5
5
  * Only ahead-writes (no IO seek or rewind)
6
6
  * Automatic switching to Zip64 as the files get written (no IO seeks), but not requiring Zip64 support if the archive can do without
7
7
  * Make use of the fact that CRC32 checksums and the sizes of the files (compressed _and_ uncompressed) are known upfront
8
+ * Make it possible to output "sparse" ZIP archives (manifests that can be resolved into a ZIP via edge includes)
8
9
 
9
10
  It strives to be compatible with the following unzip programs _at the minimum:_
10
11
 
@@ -14,9 +15,6 @@ It strives to be compatible with the following unzip programs _at the minimum:_
14
15
  * Windows 7 - 7Zip 9.20
15
16
 
16
17
  Below is the list of _specific_ decisions taken when writing the implementation, with an explanation for each.
17
- We specifically _omit_ a number of things that we could do, but that are not necessary to satisfy our objectives.
18
- The omissions are _intentional_ since we do not want to have things of which we _assume_ they work, or have things
19
- that work only for one obscure unarchiver in one obscure case (like WinRAR with chinese filenames).
20
18
 
21
19
  ## Data descriptors (postfix CRC32/file sizes)
22
20
 
@@ -53,38 +51,14 @@ field, any other extra fields should come after.
53
51
 
54
52
  If a diacritic-containing character (such as å) does fit into the DOS-437
55
53
  codepage, it should be encodable as such. This would, in theory, let older Windows tools
56
- decode the filename correctly. However, this kills the filename decoding for the OSX builtin
57
- archive utility (it assumes the filename to be UTF-8, regardless). So if we allow filenames
58
- to be encoded in DOS-437, we _potentially_ have support in Windows but we upset everyone on Mac.
59
- If we just use UTF-8 and set the right EFS bit in general purpose flags, we upset Windows users
60
- because most of the Windows unarchive tools (at least the builtin ones) do not give a flying eff
61
- about the EFS support bit being set.
62
-
63
- Additionally, if we use Unarchiver on OSX (which is our recommended unpacker for large files),
64
- it will (very rightfully) ask us how we should decode each filename that does not have the EFS bit,
65
- but does contain something non-ASCII-decodable. This is horrible UX for users.
66
-
67
- So, basically, we have 2 choices, for filenames containing diacritics (for bona-fide UTF-8 you do not
68
- even get those choices, you _have_ to use UTF-8):
69
-
70
- * Make life easier for Windows users by setting stuff to DOS, not care about the standard _and_ make
71
- most of Mac users upset
72
- * Make life easy for Mac users and conform to the standard, and tell Windows users to get a _decent_
73
- ZIP unarchiving tool.
74
-
75
- We are going with option 2, and this is well-thought-out. Trust me. If you want the crazytown
76
- filename encoding scheme that is described here http://stackoverflow.com/questions/13261347
77
- you can try this:
78
-
79
- [Encoding::CP437, Encoding::ISO_8859_1, Encoding::UTF_8]
80
-
81
- We don't want no such thing, and sorry Windows users, you are going to need a decent unarchiver
82
- that honors the standard. Alas, alas.
83
-
84
- Additionally, the tests with the unarchivers we _do_ support have shown that including the InfoZIP
85
- extra field does not actually help any of them recognize the file name correctly. And the use of
86
- those fields for the UTF-8 filename, per spec, tells us we should not set the EFS bit - which ruins
87
- the unarchiving for all other solutions. As any other, this decision may be changed in the future.
54
+ decode the filename correctly. However, this only works under the following circumstances:
55
+
56
+ * All the filenames in the archive are within the same "super-ASCII" encoding
57
+ * The Windows locale on the computer opening the archive is set to the same locale as the filename in the archive
58
+
59
+ A better approach is to use the EFS flag, which we enable when a filename does not encode cleanly
60
+ into base ASCII. The extended filename extra field did not work well for us - and it does not
61
+ combine correctly with the EFS flag.
88
62
 
89
63
  There are some interesting notes about the Info-ZIP/EFS combination here
90
64
  https://commons.apache.org/proper/commons-compress/zip.html
data/README.md CHANGED
@@ -5,17 +5,32 @@
5
5
 
6
6
  Allows streaming, non-rewinding ZIP file output from Ruby.
7
7
 
8
- `zip_kit` is a successor to and continuation of [zip_tricks](https://github.com/WeTransfer/zip_tricks), which
9
- was inspired by [zipline](https://github.com/fringd/zipline). I am grateful to WeTransfer for allowing me
10
- to develop zip_tricks and for sharing it with the community.
8
+ > [!IMPORTANT]
9
+ > `zip_kit` is a successor to and continuation of [zip_tricks.](https://github.com/WeTransfer/zip_tricks)
10
+ > I am grateful to WeTransfer for allowing me to develop zip_tricks and for sharing it with the community.
11
11
 
12
12
  Allows you to write a ZIP archive out to a `File`, `Socket`, `String` or `Array` without having to rewind it at any
13
13
  point. Usable for creating very large ZIP archives for immediate sending out to clients, or for writing
14
14
  large ZIP archives without memory inflation.
15
15
 
16
- The original gem (zip_tricks) handled all the zipping needs (millions of ZIP files generated per day),
17
- for a large file transfer service, so we are pretty confident it is widely compatible with a large number
18
- of unarchiving end-user applications and is well tested.
16
+ The gem handled all the zipping needs for WeTransfer for half a decade, with hundreds of millions
17
+ of correct ZIP files generated. It is compatible with most end-user applications for opening archives.
18
+
19
+ The files output with zip_kit will be valid [OCF containers](https://www.w3.org/TR/epub-33/#sec-container-zip),
20
+ the library can be used to generate JAR files, EPUBs, OpenOffice/Office documents etc.
21
+
22
+ ## How does it work? How is it different from Rubyzip?
23
+
24
+ Check out [the implementation details](IMPLEMENTATION_DETAILS.md) on the design of the library, and
25
+ we have a separate [reference](RUBYZIP_DIFFERENCES.md) on why you might want to use ZipKit over
26
+ Rubyzip and vice versa.
27
+
28
+ ## Migrating from zip_tricks
29
+
30
+ If you want to migrate your code from zip_tricks to zip_kit, all you need to do is a blanket replacement in your code.
31
+ Swap out the `ZipTricks` constant for `ZipKit` and you should be in business. All of the API available in ZipTricks 5.x
32
+ still works as of ZipKit 6.x and will stay working. If something in your project still depends on zip_tricks you can use
33
+ both gems inside of the same "apex" project - there will be no conflicts.
19
34
 
20
35
  ## Requirements
21
36
 
@@ -23,13 +38,11 @@ Ruby 2.6+ syntax support is required, as well as a a working zlib (all available
23
38
 
24
39
  ## Diving in: send some large CSV reports from Rails
25
40
 
26
- The easiest is to include the `ZipKit::RailsStreaming` module into your
27
- controller. You will then have a `zip_kit_stream` method available which accepts a block:
41
+ The included `Railtie` will automatically include `ZipKit::RailsStreaming` into the
42
+ `ActionController::Base` class. You will then have a `zip_kit_stream` method available which accepts a block:
28
43
 
29
44
  ```ruby
30
45
  class ZipsController < ActionController::Base
31
- include ZipKit::RailsStreaming
32
-
33
46
  def download
34
47
  zip_kit_stream do |zip|
35
48
  zip.write_file('report1.csv') do |sink|
@@ -48,6 +61,8 @@ class ZipsController < ActionController::Base
48
61
  end
49
62
  ```
50
63
 
64
+ The block receives the `ZipKit::Streamer` object you can write your files through.
65
+
51
66
  The `write_file` method will use some heuristics to determine whether your output file would benefit
52
67
  from compression, and pick the appropriate storage mode for the file accordingly.
53
68
 
@@ -55,9 +70,8 @@ If you want some more conveniences you can also use [zipline](https://github.com
55
70
  will automatically process and stream attachments (Carrierwave, Shrine, ActiveStorage) and remote objects
56
71
  via HTTP.
57
72
 
58
- `RailsStreaming` does *not* require [ActionController::Live](https://api.rubyonrails.org/classes/ActionController/Live.html)
59
- and will stream without it. See {ZipKit::RailsStreaming#zip_kit_stream} for more details on this. You can use it
60
- together with `Live` just fine if you need to.
73
+ `zip_kit_stream` does *not* require [ActionController::Live](https://api.rubyonrails.org/classes/ActionController/Live.html)
74
+ and will stream without it. It will work inside `Live` controllers just fine though.
61
75
 
62
76
  ## Writing into streaming destinations
63
77
 
@@ -123,10 +137,10 @@ output direct to STDOUT (so that you can run `$ ruby archive.rb > file.zip` in y
123
137
 
124
138
  ```ruby
125
139
  ZipKit::Streamer.open($stdout) do |zip|
126
- zip.write_file('mov.mp4.txt') do |sink|
140
+ zip.write_file('mov.mp4') do |sink| # Will use "stored" mode
127
141
  File.open('mov.mp4', 'rb'){|source| IO.copy_stream(source, sink) }
128
142
  end
129
- zip.write_file('long-novel.txt') do |sink|
143
+ zip.write_file('long-novel.txt') do |sink| # Will use "deflated" mode
130
144
  File.open('novel.txt', 'rb'){|source| IO.copy_stream(source, sink) }
131
145
  end
132
146
  end
@@ -161,7 +175,7 @@ end
161
175
  Sending a file with data descriptors is not always desirable - you don't really know how large your ZIP is going to be.
162
176
  If you want to present your users with proper download progress, you would need to set a `Content-Length` header - and
163
177
  know ahead of time how large your download is going to be. This can be done with ZipKit, provided you know how large
164
- the compressed versions of your file are going to be. Use the {ZipKit::SizeEstimator} to do the pre-calculation - it
178
+ the compressed versions of your file are going to be. Use the `ZipKit::SizeEstimator` to do the pre-calculation - it
165
179
  is not going to produce any large amounts of output, and will give you a to-the-byte value for your future archive:
166
180
 
167
181
  ```ruby
@@ -0,0 +1,53 @@
1
+ # Key differences between Rubyzip and ZipKit
2
+
3
+ Please bear in mind that this is written down not to disparage [Rubyzip.](https://github.com/rubyzip/rubyzip)
4
+
5
+ Rubyzip is, by all means, a very mature, fully featured library, and while ZipKit does have overlap with it in some functionality there are
6
+ differences in supported features which may be important for you when choosing.
7
+
8
+ ## What ZipKit supports and Rubyzip does not
9
+
10
+ * ZipKit outputs archives in a streaming fashion, using data descriptors.
11
+ This allows output of archives of very large size, without buffering.
12
+ Rubyzip will seek in the already written archive to overwrite the local entry after the write of every file into the output ZIP.
13
+ At the moment, it is difficult to build a streaming Rubyzip solution due to the output of extra field placeholders.
14
+ * ZipKit supports block-deflate which allows for distributed compression of files
15
+ * ZipKit reads files from the central directory, which allows for very rapid reading. Reading works well with data descriptors
16
+ and Zip64, and is economical enough to enable "remote uncapping" where pieces of a ZIP file get read over HTTP to reconstruct
17
+ the archive structure. Actual reading can then be done on a per-entry basis. Rubyzip reads entry data from local entries, which
18
+ is error prone and much less economical than using the central directory
19
+ * When writing, ZipKit applies careful buffering to speed up CRC32 calculations. Rubyzip combines CRC32 values at every write, which
20
+ can be slow if there are many small writes.
21
+ * ZipKit comes with a Rails helper and a Rack-compatible response body for facilitating streaming. Rubyzip has no Rails integration
22
+ and no Rack integration.
23
+ * ZipKit allows you to estimate the exact size of an archive ahead of time
24
+ * ZipKit has a heuristic module which picks the storage mode (stored or deflated) depending on how well your input compresses
25
+ * ZipKit requires components using autoloading, which means that your application will likely boot faster as you will almost never
26
+ need all of the features in one codebase. Rubyzip requires its components eagerly.
27
+ * ZipKit comes with exhaustive YARD documentation and `.rbi` typedefs for [Sorbet/Tapioca](https://sorbet.org/blog/2022/07/27/srb-tapioca)
28
+ * ZipKit allows you to compose "sparse" ZIP files where the contents of the files inside the archive comes from an external source, and does not have to be passed through the library (or be turned into Ruby strings), which enables interesting use cases such as download proxies with random access and resume.
29
+
30
+ ## What Rubyzip supports and ZipKit does not
31
+
32
+ * Rubyzip allows limited manipulation of existing ZIP files by overwriting the archive entries
33
+ * Rubyzip supports "classic" ZIP encryption - both for reading and writing. ZipKit has no encryption support.
34
+ * Rubyzip allows extraction into a directory, ZipKit avoids implementing this for security reasons
35
+ * Rubyzip allows archiving a directory, ZipKit avoids implementing this for security reasons
36
+ * Rubyzip supports separate atime and ctime in the `UniversalTime` extra fields. ZipKit outputs just one timestamp
37
+ * Rubyzip attempts to faithfully replicate UNIX permissions on the files being output. ZipKit does not attempt that
38
+ because it turned out that these permissions can break unarchiving of folders on macOS.
39
+
40
+ ## Where there is currently feature parity
41
+
42
+ These used to be different, but Rubyzip has made great progress in addressing.
43
+
44
+ * ZipKit automatically applies the EFS flag for Unicode filenames in the archive. This used to be optional in RubyZip
45
+ * ZipKit automatically enables Zip64 and does so only when necessary. applies the EFS flag for Unicode filenames in the archive. This used to be optional in RubyZip.
46
+ * ZipKit outputs the `UT` precise time extra field
47
+ * ZipKit used to be distributed under the MIT-Hippocratic license which is much more restrictive than the Rubyzip BSD-2-Clause. ZipKit is now MIT-licensed.
48
+
49
+ ## Code style differences
50
+
51
+ Rubyzip is written in a somewhat Java-like style, with a lot of encapsulation and data hiding. ZipKit aims to be more approachable and have "less" of everything.
52
+ Less modules, less classes, less OOP - just enough to be useful. But that is a matter of taste, and as such should not matter to you all that much
53
+ when picking one over the other. Or it might, you never know ;-)
data/Rakefile CHANGED
@@ -11,11 +11,7 @@ task :format do
11
11
  `bundle exec magic_frozen_string_literal ./lib`
12
12
  end
13
13
 
14
- YARD::Rake::YardocTask.new(:doc) do |t|
15
- # The dash has to be between the two to "divide" the source files and
16
- # miscellaneous documentation files that contain no code
17
- t.files = ["lib/**/*.rb", "-", "LICENSE.txt", "IMPLEMENTATION_DETAILS.md"]
18
- end
14
+ YARD::Rake::YardocTask.new(:doc)
19
15
  RSpec::Core::RakeTask.new(:spec)
20
16
 
21
17
  task :generate_typedefs do
@@ -55,7 +55,7 @@ class ZipKit::BlockDeflate
55
55
  # `output_io` can also be a {ZipKit::Streamer} to expedite ops.
56
56
  #
57
57
  # @param output_io [IO] the stream to write to (should respond to `:<<`)
58
- # @return [Fixnum] number of bytes written to `output_io`
58
+ # @return [Integer] number of bytes written to `output_io`
59
59
  def self.write_terminator(output_io)
60
60
  output_io << END_MARKER
61
61
  END_MARKER.bytesize
@@ -65,7 +65,7 @@ class ZipKit::BlockDeflate
65
65
  # The returned string can be spliced into another deflate stream.
66
66
  #
67
67
  # @param bytes [String] Bytes to compress
68
- # @param level [Fixnum] Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
68
+ # @param level [Integer] Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
69
69
  # @return [String] compressed bytes
70
70
  def self.deflate_chunk(bytes, level: Zlib::DEFAULT_COMPRESSION)
71
71
  raise "Invalid Zlib compression level #{level}" unless VALID_COMPRESSIONS.include?(level)
@@ -90,9 +90,9 @@ class ZipKit::BlockDeflate
90
90
  #
91
91
  # @param input_io [IO] the stream to read from (should respond to `:read`)
92
92
  # @param output_io [IO] the stream to write to (should respond to `:<<`)
93
- # @param level [Fixnum] Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
94
- # @param block_size [Fixnum] The block size to use (defaults to `DEFAULT_BLOCKSIZE`)
95
- # @return [Fixnum] number of bytes written to `output_io`
93
+ # @param level [Integer] Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
94
+ # @param block_size [Integer] The block size to use (defaults to `DEFAULT_BLOCKSIZE`)
95
+ # @return [Integer] number of bytes written to `output_io`
96
96
  def self.deflate_in_blocks_and_terminate(input_io,
97
97
  output_io,
98
98
  level: Zlib::DEFAULT_COMPRESSION,
@@ -110,9 +110,9 @@ class ZipKit::BlockDeflate
110
110
  #
111
111
  # @param input_io [IO] the stream to read from (should respond to `:read`)
112
112
  # @param output_io [IO] the stream to write to (should respond to `:<<`)
113
- # @param level [Fixnum] Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
114
- # @param block_size [Fixnum] The block size to use (defaults to `DEFAULT_BLOCKSIZE`)
115
- # @return [Fixnum] number of bytes written to `output_io`
113
+ # @param level [Integer] Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
114
+ # @param block_size [Integer] The block size to use (defaults to `DEFAULT_BLOCKSIZE`)
115
+ # @return [Integer] number of bytes written to `output_io`
116
116
  def self.deflate_in_blocks(input_io,
117
117
  output_io,
118
118
  level: Zlib::DEFAULT_COMPRESSION,
@@ -86,46 +86,46 @@ class ZipKit::FileReader
86
86
  # the Entry object used in Streamer for ZIP writing, since during writing more
87
87
  # data can be kept in memory for immediate use.
88
88
  class ZipEntry
89
- # @return [Fixnum] bit-packed version signature of the program that made the archive
89
+ # @return [Integer] bit-packed version signature of the program that made the archive
90
90
  attr_accessor :made_by
91
91
 
92
- # @return [Fixnum] ZIP version support needed to extract this file
92
+ # @return [Integer] ZIP version support needed to extract this file
93
93
  attr_accessor :version_needed_to_extract
94
94
 
95
- # @return [Fixnum] bit-packed general purpose flags
95
+ # @return [Integer] bit-packed general purpose flags
96
96
  attr_accessor :gp_flags
97
97
 
98
- # @return [Fixnum] Storage mode (0 for stored, 8 for deflate)
98
+ # @return [Integer] Storage mode (0 for stored, 8 for deflate)
99
99
  attr_accessor :storage_mode
100
100
 
101
- # @return [Fixnum] the bit-packed DOS time
101
+ # @return [Integer] the bit-packed DOS time
102
102
  attr_accessor :dos_time
103
103
 
104
- # @return [Fixnum] the bit-packed DOS date
104
+ # @return [Integer] the bit-packed DOS date
105
105
  attr_accessor :dos_date
106
106
 
107
- # @return [Fixnum] the CRC32 checksum of this file
107
+ # @return [Integer] the CRC32 checksum of this file
108
108
  attr_accessor :crc32
109
109
 
110
- # @return [Fixnum] size of compressed file data in the ZIP
110
+ # @return [Integer] size of compressed file data in the ZIP
111
111
  attr_accessor :compressed_size
112
112
 
113
- # @return [Fixnum] size of the file once uncompressed
113
+ # @return [Integer] size of the file once uncompressed
114
114
  attr_accessor :uncompressed_size
115
115
 
116
116
  # @return [String] the filename
117
117
  attr_accessor :filename
118
118
 
119
- # @return [Fixnum] disk number where this file starts
119
+ # @return [Integer] disk number where this file starts
120
120
  attr_accessor :disk_number_start
121
121
 
122
- # @return [Fixnum] internal attributes of the file
122
+ # @return [Integer] internal attributes of the file
123
123
  attr_accessor :internal_attrs
124
124
 
125
- # @return [Fixnum] external attributes of the file
125
+ # @return [Integer] external attributes of the file
126
126
  attr_accessor :external_attrs
127
127
 
128
- # @return [Fixnum] at what offset the local file header starts
128
+ # @return [Integer] at what offset the local file header starts
129
129
  # in your original IO object
130
130
  attr_accessor :local_file_header_offset
131
131
 
@@ -151,7 +151,7 @@ class ZipKit::FileReader
151
151
  end
152
152
  end
153
153
 
154
- # @return [Fixnum] at what offset you should start reading
154
+ # @return [Integer] at what offset you should start reading
155
155
  # for the compressed data in your original IO object
156
156
  def compressed_data_offset
157
157
  @compressed_data_offset || raise(LocalHeaderPending)
@@ -298,7 +298,7 @@ class ZipKit::FileReader
298
298
  # this offset to get the data).
299
299
  #
300
300
  # @param io[#read] an IO-ish object the ZIP file can be read from
301
- # @return [Array<ZipEntry, Fixnum>] the parsed local header entry and
301
+ # @return [Array<ZipEntry, Integer>] the parsed local header entry and
302
302
  # the compressed data offset
303
303
  def read_local_file_header(io:)
304
304
  local_file_header_offset = io.tell
@@ -365,8 +365,8 @@ class ZipKit::FileReader
365
365
  # (read starting at this offset to get the data).
366
366
  #
367
367
  # @param io[#seek, #read] an IO-ish object the ZIP file can be read from
368
- # @param local_file_header_offset[Fixnum] absolute offset (0-based) where the
369
- # local file header is supposed to begin @return [Fixnum] absolute offset
368
+ # @param local_file_header_offset[Integer] absolute offset (0-based) where the
369
+ # local file header is supposed to begin @return [Integer] absolute offset
370
370
  # (0-based) of where the compressed data begins for this file within the ZIP
371
371
  def get_compressed_data_offset(io:, local_file_header_offset:)
372
372
  seek(io, local_file_header_offset)
@@ -3,8 +3,7 @@
3
3
  # Should be included into a Rails controller for easy ZIP output from any action.
4
4
  module ZipKit::RailsStreaming
5
5
  # Opens a {ZipKit::Streamer} and yields it to the caller. The output of the streamer
6
- # gets automatically forwarded to the Rails response stream. When the output completes,
7
- # the Rails response stream is going to be closed automatically.
6
+ # will be sent through to the HTTP response body as it gets produced.
8
7
  #
9
8
  # Note that there is an important difference in how this method works, depending whether
10
9
  # you use it in a controller which includes `ActionController::Live` vs. one that does not.
@@ -25,7 +24,7 @@ module ZipKit::RailsStreaming
25
24
  # @param use_chunked_transfer_encoding[Boolean] whether to forcibly encode output as chunked. Normally you should not need this.
26
25
  # @param output_enumerator_options[Hash] options that will be passed to the OutputEnumerator - these include
27
26
  # options for the Streamer. See {ZipKit::OutputEnumerator#initialize} for the full list of options.
28
- # @yieldparam [ZipKit::Streamer] the streamer that can be written to
27
+ # @yieldparam zip[ZipKit::Streamer] the {ZipKit::Streamer} that can be written to
29
28
  # @return [Boolean] always returns true
30
29
  def zip_kit_stream(filename: "download.zip", type: "application/zip", use_chunked_transfer_encoding: false, **output_enumerator_options, &zip_streaming_blk)
31
30
  # We want some common headers for file sending. Rails will also set
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ZipKit::Railtie < ::Rails::Railtie
4
+ initializer "zip_kit.install_extensions" do |app|
5
+ ActiveSupport.on_load(:action_controller) do
6
+ include(ZipKit::RailsStreaming)
7
+ end
8
+ end
9
+ end
@@ -40,7 +40,7 @@ class ZipKit::RemoteIO
40
40
  # so if you are at offset 0 in the IO of size 10, doing a `read(20)`
41
41
  # will only return you 10 bytes of result, and not raise any exceptions.
42
42
  #
43
- # @param n_bytes[Fixnum, nil] how many bytes to read, or `nil` to read all the way to the end
43
+ # @param n_bytes[Integer, nil] how many bytes to read, or `nil` to read all the way to the end
44
44
  # @return [String] the read bytes
45
45
  def read(n_bytes = nil)
46
46
  # If the resource is empty there is nothing to read
@@ -62,7 +62,7 @@ class ZipKit::RemoteIO
62
62
 
63
63
  # Returns the current pointer position within the IO
64
64
  #
65
- # @return [Fixnum]
65
+ # @return [Integer]
66
66
  def tell
67
67
  @pos
68
68
  end
@@ -24,7 +24,7 @@ class ZipKit::SizeEstimator
24
24
  #
25
25
  # @param kwargs_for_streamer_new Any options to pass to Streamer, see {Streamer#initialize}
26
26
  # @return [Integer] the size of the resulting archive, in bytes
27
- # @yieldparam [SizeEstimator] the estimator
27
+ # @yieldparam estimator[SizeEstimator] the estimator
28
28
  def self.estimate(**kwargs_for_streamer_new)
29
29
  streamer = ZipKit::Streamer.new(ZipKit::NullWriter, **kwargs_for_streamer_new)
30
30
  estimator = new(streamer)
@@ -35,7 +35,7 @@ class ZipKit::SizeEstimator
35
35
  # Add a fake entry to the archive, to see how big it is going to be in the end.
36
36
  #
37
37
  # @param filename [String] the name of the file (filenames are variable-width in the ZIP)
38
- # @param size [Fixnum] size of the uncompressed entry
38
+ # @param size [Integer] size of the uncompressed entry
39
39
  # @param use_data_descriptor[Boolean] whether the entry uses a postfix
40
40
  # data descriptor to specify size
41
41
  # @return self
@@ -54,8 +54,8 @@ class ZipKit::SizeEstimator
54
54
  # Add a fake entry to the archive, to see how big it is going to be in the end.
55
55
  #
56
56
  # @param filename [String] the name of the file (filenames are variable-width in the ZIP)
57
- # @param uncompressed_size [Fixnum] size of the uncompressed entry
58
- # @param compressed_size [Fixnum] size of the compressed entry
57
+ # @param uncompressed_size [Integer] size of the uncompressed entry
58
+ # @param compressed_size [Integer] size of the compressed entry
59
59
  # @param use_data_descriptor[Boolean] whether the entry uses a postfix data
60
60
  # descriptor to specify size
61
61
  # @return self
@@ -16,7 +16,7 @@ class ZipKit::StreamCRC32
16
16
  # Compute a CRC32 value from an IO object. The object should respond to `read` and `eof?`
17
17
  #
18
18
  # @param io[IO] the IO to read the data from
19
- # @return [Fixnum] the computed CRC32 value
19
+ # @return [Integer] the computed CRC32 value
20
20
  def self.from_io(io)
21
21
  # If we can specify the string capacity upfront we will not have to resize
22
22
  # the string during operation. This saves time but is only available on
@@ -43,7 +43,7 @@ class ZipKit::StreamCRC32
43
43
 
44
44
  # Returns the CRC32 value computed so far
45
45
  #
46
- # @return [Fixnum] the updated CRC32 value for all the blobs so far
46
+ # @return [Integer] the updated CRC32 value for all the blobs so far
47
47
  def to_i
48
48
  @crc
49
49
  end
@@ -51,9 +51,9 @@ class ZipKit::StreamCRC32
51
51
  # Appends a known CRC32 value to the current one, and combines the
52
52
  # contained CRC32 value in-place.
53
53
  #
54
- # @param crc32[Fixnum] the CRC32 value to append
55
- # @param blob_size[Fixnum] the size of the daata the `crc32` is computed from
56
- # @return [Fixnum] the updated CRC32 value for all the blobs so far
54
+ # @param crc32[Integer] the CRC32 value to append
55
+ # @param blob_size[Integer] the size of the daata the `crc32` is computed from
56
+ # @return [Integer] the updated CRC32 value for all the blobs so far
57
57
  def append(crc32, blob_size)
58
58
  @crc = Zlib.crc32_combine(@crc, crc32, blob_size)
59
59
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ZipKit
4
- VERSION = "6.2.2"
4
+ VERSION = "6.3.1"
5
5
  end
@@ -14,7 +14,7 @@ module ZipKit::WriteShovel
14
14
  # a target for `IO.copy_stream(from, to)`
15
15
  #
16
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`)
17
+ # @return [Integer] 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
@@ -64,12 +64,12 @@ class ZipKit::ZipWriter
64
64
  #
65
65
  # @param io[#<<] the buffer to write the local file header to
66
66
  # @param filename[String] the name of the file in the archive
67
- # @param compressed_size[Fixnum] The size of the compressed (or stored) data - how much space it uses in the ZIP
68
- # @param uncompressed_size[Fixnum] The size of the file once extracted
69
- # @param crc32[Fixnum] The CRC32 checksum of the file
67
+ # @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
68
+ # @param uncompressed_size[Integer] The size of the file once extracted
69
+ # @param crc32[Integer] The CRC32 checksum of the file
70
70
  # @param mtime[Time] the modification time to be recorded in the ZIP
71
- # @param gp_flags[Fixnum] bit-packed general purpose flags
72
- # @param storage_mode[Fixnum] 8 for deflated, 0 for stored...
71
+ # @param gp_flags[Integer] bit-packed general purpose flags
72
+ # @param storage_mode[Integer] 8 for deflated, 0 for stored...
73
73
  # @return [void]
74
74
  def write_local_file_header(io:, filename:, compressed_size:, uncompressed_size:, crc32:, gp_flags:, mtime:, storage_mode:)
75
75
  requires_zip64 = compressed_size > FOUR_BYTE_MAX_UINT || uncompressed_size > FOUR_BYTE_MAX_UINT
@@ -136,11 +136,11 @@ class ZipKit::ZipWriter
136
136
  #
137
137
  # @param io[#<<] the buffer to write the local file header to
138
138
  # @param filename[String] the name of the file in the archive
139
- # @param compressed_size[Fixnum] The size of the compressed (or stored) data - how much space it uses in the ZIP
140
- # @param uncompressed_size[Fixnum] The size of the file once extracted
141
- # @param crc32[Fixnum] The CRC32 checksum of the file
139
+ # @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
140
+ # @param uncompressed_size[Integer] The size of the file once extracted
141
+ # @param crc32[Integer] The CRC32 checksum of the file
142
142
  # @param mtime[Time] the modification time to be recorded in the ZIP
143
- # @param gp_flags[Fixnum] bit-packed general purpose flags
143
+ # @param gp_flags[Integer] bit-packed general purpose flags
144
144
  # @param unix_permissions[Integer] the permissions for the file, or nil for the default to be used
145
145
  # @return [void]
146
146
  def write_central_directory_file_header(io:,
@@ -253,9 +253,9 @@ class ZipKit::ZipWriter
253
253
  # the data descriptor will have the sizes written out as 8-byte values instead of 4-byte values.
254
254
  #
255
255
  # @param io[#<<] the buffer to write the local file header to
256
- # @param crc32[Fixnum] The CRC32 checksum of the file
257
- # @param compressed_size[Fixnum] The size of the compressed (or stored) data - how much space it uses in the ZIP
258
- # @param uncompressed_size[Fixnum] The size of the file once extracted
256
+ # @param crc32[Integer] The CRC32 checksum of the file
257
+ # @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
258
+ # @param uncompressed_size[Integer] The size of the file once extracted
259
259
  # @return [void]
260
260
  def write_data_descriptor(io:, compressed_size:, uncompressed_size:, crc32:)
261
261
  # Although not originally assigned a signature, the value
@@ -282,9 +282,9 @@ class ZipKit::ZipWriter
282
282
  # Writes the "end of central directory record" (including the Zip6 salient bits if necessary)
283
283
  #
284
284
  # @param io[#<<] the buffer to write the central directory to.
285
- # @param start_of_central_directory_location[Fixnum] byte offset of the start of central directory form the beginning of ZIP file
286
- # @param central_directory_size[Fixnum] the size of the central directory (only file headers) in bytes
287
- # @param num_files_in_archive[Fixnum] How many files the archive contains
285
+ # @param start_of_central_directory_location[Integer] byte offset of the start of central directory form the beginning of ZIP file
286
+ # @param central_directory_size[Integer] the size of the central directory (only file headers) in bytes
287
+ # @param num_files_in_archive[Integer] How many files the archive contains
288
288
  # @param comment[String] the comment for the archive (defaults to ZIP_KIT_COMMENT)
289
289
  # @return [void]
290
290
  def write_end_of_central_directory(io:, start_of_central_directory_location:, central_directory_size:, num_files_in_archive:, comment: ZIP_KIT_COMMENT)
@@ -386,8 +386,8 @@ class ZipKit::ZipWriter
386
386
 
387
387
  # Writes the Zip64 extra field for the local file header. Will be used by `write_local_file_header` when any sizes given to it warrant that.
388
388
  #
389
- # @param compressed_size[Fixnum] The size of the compressed (or stored) data - how much space it uses in the ZIP
390
- # @param uncompressed_size[Fixnum] The size of the file once extracted
389
+ # @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
390
+ # @param uncompressed_size[Integer] The size of the file once extracted
391
391
  # @return [String]
392
392
  def zip_64_extra_for_local_file_header(compressed_size:, uncompressed_size:)
393
393
  data_and_packspecs = [
@@ -460,9 +460,9 @@ class ZipKit::ZipWriter
460
460
  # Writes the Zip64 extra field for the central directory header.It differs from the extra used in the local file header because it
461
461
  # also contains the location of the local file header in the ZIP as an 8-byte int.
462
462
  #
463
- # @param compressed_size[Fixnum] The size of the compressed (or stored) data - how much space it uses in the ZIP
464
- # @param uncompressed_size[Fixnum] The size of the file once extracted
465
- # @param local_file_header_location[Fixnum] Byte offset of the start of the local file header from the beginning of the ZIP archive
463
+ # @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
464
+ # @param uncompressed_size[Integer] The size of the file once extracted
465
+ # @param local_file_header_location[Integer] Byte offset of the start of the local file header from the beginning of the ZIP archive
466
466
  # @return [String]
467
467
  def zip_64_extra_for_central_directory_file_header(compressed_size:, uncompressed_size:, local_file_header_location:)
468
468
  data_and_packspecs = [
data/lib/zip_kit.rb CHANGED
@@ -24,4 +24,6 @@ module ZipKit
24
24
  autoload :WriteShovel, File.dirname(__FILE__) + "/zip_kit/write_shovel.rb"
25
25
  autoload :RackChunkedBody, File.dirname(__FILE__) + "/zip_kit/rack_chunked_body.rb"
26
26
  autoload :RackTempfileBody, File.dirname(__FILE__) + "/zip_kit/rack_tempfile_body.rb"
27
+
28
+ require_relative "zip_kit/railtie" if defined?(::Rails)
27
29
  end
data/rbi/zip_kit.rbi CHANGED
@@ -1,6 +1,9 @@
1
1
  # typed: strong
2
2
  module ZipKit
3
- VERSION = T.let("6.2.2", T.untyped)
3
+ VERSION = T.let("6.3.1", T.untyped)
4
+
5
+ class Railtie < Rails::Railtie
6
+ end
4
7
 
5
8
  # A ZIP archive contains a flat list of entries. These entries can implicitly
6
9
  # create directories when the archive is expanded. For example, an entry with
@@ -569,7 +572,7 @@ module ZipKit
569
572
  # _@param_ `bytes` — the binary string to write (part of the uncompressed file)
570
573
  #
571
574
  # _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
572
- sig { params(bytes: String).returns(Fixnum) }
575
+ sig { params(bytes: String).returns(Integer) }
573
576
  def write(bytes); end
574
577
 
575
578
  # Is used internally by Streamer to keep track of entries in the archive during writing.
@@ -683,7 +686,7 @@ module ZipKit
683
686
  # _@param_ `bytes` — the binary string to write (part of the uncompressed file)
684
687
  #
685
688
  # _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
686
- sig { params(bytes: String).returns(Fixnum) }
689
+ sig { params(bytes: String).returns(Integer) }
687
690
  def write(bytes); end
688
691
  end
689
692
 
@@ -752,7 +755,7 @@ module ZipKit
752
755
  # _@param_ `bytes` — the binary string to write (part of the uncompressed file)
753
756
  #
754
757
  # _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
755
- sig { params(bytes: String).returns(Fixnum) }
758
+ sig { params(bytes: String).returns(Integer) }
756
759
  def write(bytes); end
757
760
  end
758
761
 
@@ -790,7 +793,7 @@ module ZipKit
790
793
  # _@param_ `bytes` — the binary string to write (part of the uncompressed file)
791
794
  #
792
795
  # _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
793
- sig { params(bytes: String).returns(Fixnum) }
796
+ sig { params(bytes: String).returns(Integer) }
794
797
  def write(bytes); end
795
798
  end
796
799
  end
@@ -832,11 +835,11 @@ module ZipKit
832
835
  # _@param_ `n_bytes` — how many bytes to read, or `nil` to read all the way to the end
833
836
  #
834
837
  # _@return_ — the read bytes
835
- sig { params(n_bytes: T.nilable(Fixnum)).returns(String) }
838
+ sig { params(n_bytes: T.nilable(Integer)).returns(String) }
836
839
  def read(n_bytes = nil); end
837
840
 
838
841
  # Returns the current pointer position within the IO
839
- sig { returns(Fixnum) }
842
+ sig { returns(Integer) }
840
843
  def tell; end
841
844
 
842
845
  # Only used internally when reading the remote ZIP.
@@ -930,12 +933,12 @@ end, T.untyped)
930
933
  params(
931
934
  io: T.untyped,
932
935
  filename: String,
933
- compressed_size: Fixnum,
934
- uncompressed_size: Fixnum,
935
- crc32: Fixnum,
936
- gp_flags: Fixnum,
936
+ compressed_size: Integer,
937
+ uncompressed_size: Integer,
938
+ crc32: Integer,
939
+ gp_flags: Integer,
937
940
  mtime: Time,
938
- storage_mode: Fixnum
941
+ storage_mode: Integer
939
942
  ).void
940
943
  end
941
944
  def write_local_file_header(io:, filename:, compressed_size:, uncompressed_size:, crc32:, gp_flags:, mtime:, storage_mode:); end
@@ -965,12 +968,12 @@ end, T.untyped)
965
968
  params(
966
969
  io: T.untyped,
967
970
  local_file_header_location: T.untyped,
968
- gp_flags: Fixnum,
971
+ gp_flags: Integer,
969
972
  storage_mode: T.untyped,
970
- compressed_size: Fixnum,
971
- uncompressed_size: Fixnum,
973
+ compressed_size: Integer,
974
+ uncompressed_size: Integer,
972
975
  mtime: Time,
973
- crc32: Fixnum,
976
+ crc32: Integer,
974
977
  filename: String,
975
978
  unix_permissions: T.nilable(Integer)
976
979
  ).void
@@ -992,9 +995,9 @@ end, T.untyped)
992
995
  sig do
993
996
  params(
994
997
  io: T.untyped,
995
- compressed_size: Fixnum,
996
- uncompressed_size: Fixnum,
997
- crc32: Fixnum
998
+ compressed_size: Integer,
999
+ uncompressed_size: Integer,
1000
+ crc32: Integer
998
1001
  ).void
999
1002
  end
1000
1003
  def write_data_descriptor(io:, compressed_size:, uncompressed_size:, crc32:); end
@@ -1014,9 +1017,9 @@ end, T.untyped)
1014
1017
  sig do
1015
1018
  params(
1016
1019
  io: T.untyped,
1017
- start_of_central_directory_location: Fixnum,
1018
- central_directory_size: Fixnum,
1019
- num_files_in_archive: Fixnum,
1020
+ start_of_central_directory_location: Integer,
1021
+ central_directory_size: Integer,
1022
+ num_files_in_archive: Integer,
1020
1023
  comment: String
1021
1024
  ).void
1022
1025
  end
@@ -1027,7 +1030,7 @@ end, T.untyped)
1027
1030
  # _@param_ `compressed_size` — The size of the compressed (or stored) data - how much space it uses in the ZIP
1028
1031
  #
1029
1032
  # _@param_ `uncompressed_size` — The size of the file once extracted
1030
- sig { params(compressed_size: Fixnum, uncompressed_size: Fixnum).returns(String) }
1033
+ sig { params(compressed_size: Integer, uncompressed_size: Integer).returns(String) }
1031
1034
  def zip_64_extra_for_local_file_header(compressed_size:, uncompressed_size:); end
1032
1035
 
1033
1036
  # sord omit - no YARD type given for "mtime", using untyped
@@ -1050,7 +1053,7 @@ end, T.untyped)
1050
1053
  # _@param_ `uncompressed_size` — The size of the file once extracted
1051
1054
  #
1052
1055
  # _@param_ `local_file_header_location` — Byte offset of the start of the local file header from the beginning of the ZIP archive
1053
- sig { params(compressed_size: Fixnum, uncompressed_size: Fixnum, local_file_header_location: Fixnum).returns(String) }
1056
+ sig { params(compressed_size: Integer, uncompressed_size: Integer, local_file_header_location: Integer).returns(String) }
1054
1057
  def zip_64_extra_for_central_directory_file_header(compressed_size:, uncompressed_size:, local_file_header_location:); end
1055
1058
 
1056
1059
  # sord omit - no YARD type given for "t", using untyped
@@ -1123,7 +1126,7 @@ end, T.untyped)
1123
1126
  # _@param_ `bytes` — the binary string to write (part of the uncompressed file)
1124
1127
  #
1125
1128
  # _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
1126
- sig { params(bytes: String).returns(Fixnum) }
1129
+ sig { params(bytes: String).returns(Integer) }
1127
1130
  def write(bytes); end
1128
1131
  end
1129
1132
 
@@ -1283,7 +1286,7 @@ end, T.untyped)
1283
1286
  # _@param_ `io` — an IO-ish object the ZIP file can be read from
1284
1287
  #
1285
1288
  # _@return_ — the parsed local header entry and
1286
- sig { params(io: T.untyped).returns(T::Array[T.any(ZipEntry, Fixnum)]) }
1289
+ sig { params(io: T.untyped).returns(T::Array[T.any(ZipEntry, Integer)]) }
1287
1290
  def read_local_file_header(io:); end
1288
1291
 
1289
1292
  # sord duck - #seek looks like a duck type, replacing with untyped
@@ -1296,13 +1299,13 @@ end, T.untyped)
1296
1299
  # header offset given will be the compressed data offset of the entry
1297
1300
  # (read starting at this offset to get the data).
1298
1301
  #
1299
- # local file header is supposed to begin @return [Fixnum] absolute offset
1302
+ # local file header is supposed to begin @return [Integer] absolute offset
1300
1303
  # (0-based) of where the compressed data begins for this file within the ZIP
1301
1304
  #
1302
1305
  # _@param_ `io` — an IO-ish object the ZIP file can be read from
1303
1306
  #
1304
1307
  # _@param_ `local_file_header_offset` — absolute offset (0-based) where the
1305
- sig { params(io: T.untyped, local_file_header_offset: Fixnum).returns(T.untyped) }
1308
+ sig { params(io: T.untyped, local_file_header_offset: Integer).returns(T.untyped) }
1306
1309
  def get_compressed_data_offset(io:, local_file_header_offset:); end
1307
1310
 
1308
1311
  # Parse an IO handle to a ZIP archive into an array of Entry objects, reading from the end
@@ -1499,7 +1502,7 @@ end, T.untyped)
1499
1502
 
1500
1503
  # _@return_ — at what offset you should start reading
1501
1504
  # for the compressed data in your original IO object
1502
- sig { returns(Fixnum) }
1505
+ sig { returns(Integer) }
1503
1506
  def compressed_data_offset; end
1504
1507
 
1505
1508
  # Tells whether the compressed data offset is already known for this entry
@@ -1511,7 +1514,7 @@ end, T.untyped)
1511
1514
  sig { returns(T::Boolean) }
1512
1515
  def uses_data_descriptor?; end
1513
1516
 
1514
- # sord infer - inferred type of parameter "offset" as Fixnum using getter's return type
1517
+ # sord infer - inferred type of parameter "offset" as Integer using getter's return type
1515
1518
  # sord omit - no YARD return type given, using untyped
1516
1519
  # Sets the offset at which the compressed data for this file starts in the ZIP.
1517
1520
  # By default, the value will be set by the Reader for you. If you use delayed
@@ -1519,43 +1522,43 @@ end, T.untyped)
1519
1522
  #
1520
1523
  # entry.compressed_data_offset = reader.get_compressed_data_offset(io: file,
1521
1524
  # local_file_header_offset: entry.local_header_offset)
1522
- sig { params(offset: Fixnum).returns(T.untyped) }
1525
+ sig { params(offset: Integer).returns(T.untyped) }
1523
1526
  def compressed_data_offset=(offset); end
1524
1527
 
1525
1528
  # _@return_ — bit-packed version signature of the program that made the archive
1526
- sig { returns(Fixnum) }
1529
+ sig { returns(Integer) }
1527
1530
  attr_accessor :made_by
1528
1531
 
1529
1532
  # _@return_ — ZIP version support needed to extract this file
1530
- sig { returns(Fixnum) }
1533
+ sig { returns(Integer) }
1531
1534
  attr_accessor :version_needed_to_extract
1532
1535
 
1533
1536
  # _@return_ — bit-packed general purpose flags
1534
- sig { returns(Fixnum) }
1537
+ sig { returns(Integer) }
1535
1538
  attr_accessor :gp_flags
1536
1539
 
1537
1540
  # _@return_ — Storage mode (0 for stored, 8 for deflate)
1538
- sig { returns(Fixnum) }
1541
+ sig { returns(Integer) }
1539
1542
  attr_accessor :storage_mode
1540
1543
 
1541
1544
  # _@return_ — the bit-packed DOS time
1542
- sig { returns(Fixnum) }
1545
+ sig { returns(Integer) }
1543
1546
  attr_accessor :dos_time
1544
1547
 
1545
1548
  # _@return_ — the bit-packed DOS date
1546
- sig { returns(Fixnum) }
1549
+ sig { returns(Integer) }
1547
1550
  attr_accessor :dos_date
1548
1551
 
1549
1552
  # _@return_ — the CRC32 checksum of this file
1550
- sig { returns(Fixnum) }
1553
+ sig { returns(Integer) }
1551
1554
  attr_accessor :crc32
1552
1555
 
1553
1556
  # _@return_ — size of compressed file data in the ZIP
1554
- sig { returns(Fixnum) }
1557
+ sig { returns(Integer) }
1555
1558
  attr_accessor :compressed_size
1556
1559
 
1557
1560
  # _@return_ — size of the file once uncompressed
1558
- sig { returns(Fixnum) }
1561
+ sig { returns(Integer) }
1559
1562
  attr_accessor :uncompressed_size
1560
1563
 
1561
1564
  # _@return_ — the filename
@@ -1563,20 +1566,20 @@ end, T.untyped)
1563
1566
  attr_accessor :filename
1564
1567
 
1565
1568
  # _@return_ — disk number where this file starts
1566
- sig { returns(Fixnum) }
1569
+ sig { returns(Integer) }
1567
1570
  attr_accessor :disk_number_start
1568
1571
 
1569
1572
  # _@return_ — internal attributes of the file
1570
- sig { returns(Fixnum) }
1573
+ sig { returns(Integer) }
1571
1574
  attr_accessor :internal_attrs
1572
1575
 
1573
1576
  # _@return_ — external attributes of the file
1574
- sig { returns(Fixnum) }
1577
+ sig { returns(Integer) }
1575
1578
  attr_accessor :external_attrs
1576
1579
 
1577
1580
  # _@return_ — at what offset the local file header starts
1578
1581
  # in your original IO object
1579
- sig { returns(Fixnum) }
1582
+ sig { returns(Integer) }
1580
1583
  attr_accessor :local_file_header_offset
1581
1584
 
1582
1585
  # _@return_ — the file comment
@@ -1632,7 +1635,7 @@ end, T.untyped)
1632
1635
  # _@param_ `io` — the IO to read the data from
1633
1636
  #
1634
1637
  # _@return_ — the computed CRC32 value
1635
- sig { params(io: IO).returns(Fixnum) }
1638
+ sig { params(io: IO).returns(Integer) }
1636
1639
  def self.from_io(io); end
1637
1640
 
1638
1641
  # Creates a new streaming CRC32 calculator
@@ -1648,7 +1651,7 @@ end, T.untyped)
1648
1651
  # Returns the CRC32 value computed so far
1649
1652
  #
1650
1653
  # _@return_ — the updated CRC32 value for all the blobs so far
1651
- sig { returns(Fixnum) }
1654
+ sig { returns(Integer) }
1652
1655
  def to_i; end
1653
1656
 
1654
1657
  # Appends a known CRC32 value to the current one, and combines the
@@ -1659,7 +1662,7 @@ end, T.untyped)
1659
1662
  # _@param_ `blob_size` — the size of the daata the `crc32` is computed from
1660
1663
  #
1661
1664
  # _@return_ — the updated CRC32 value for all the blobs so far
1662
- sig { params(crc32: Fixnum, blob_size: Fixnum).returns(Fixnum) }
1665
+ sig { params(crc32: Integer, blob_size: Integer).returns(Integer) }
1663
1666
  def append(crc32, blob_size); end
1664
1667
 
1665
1668
  # Writes the given data to the output stream. Allows the object to be used as
@@ -1668,7 +1671,7 @@ end, T.untyped)
1668
1671
  # _@param_ `bytes` — the binary string to write (part of the uncompressed file)
1669
1672
  #
1670
1673
  # _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
1671
- sig { params(bytes: String).returns(Fixnum) }
1674
+ sig { params(bytes: String).returns(Integer) }
1672
1675
  def write(bytes); end
1673
1676
  end
1674
1677
 
@@ -1738,7 +1741,7 @@ end, T.untyped)
1738
1741
  # _@param_ `bytes` — the binary string to write (part of the uncompressed file)
1739
1742
  #
1740
1743
  # _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
1741
- sig { params(bytes: String).returns(Fixnum) }
1744
+ sig { params(bytes: String).returns(Integer) }
1742
1745
  def write(bytes); end
1743
1746
  end
1744
1747
 
@@ -1798,7 +1801,7 @@ end, T.untyped)
1798
1801
  # _@param_ `output_io` — the stream to write to (should respond to `:<<`)
1799
1802
  #
1800
1803
  # _@return_ — number of bytes written to `output_io`
1801
- sig { params(output_io: IO).returns(Fixnum) }
1804
+ sig { params(output_io: IO).returns(Integer) }
1802
1805
  def self.write_terminator(output_io); end
1803
1806
 
1804
1807
  # Compress a given binary string and flush the deflate stream at byte boundary.
@@ -1809,7 +1812,7 @@ end, T.untyped)
1809
1812
  # _@param_ `level` — Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
1810
1813
  #
1811
1814
  # _@return_ — compressed bytes
1812
- sig { params(bytes: String, level: Fixnum).returns(String) }
1815
+ sig { params(bytes: String, level: Integer).returns(String) }
1813
1816
  def self.deflate_chunk(bytes, level: Zlib::DEFAULT_COMPRESSION); end
1814
1817
 
1815
1818
  # Compress the contents of input_io into output_io, in blocks
@@ -1835,9 +1838,9 @@ end, T.untyped)
1835
1838
  params(
1836
1839
  input_io: IO,
1837
1840
  output_io: IO,
1838
- level: Fixnum,
1839
- block_size: Fixnum
1840
- ).returns(Fixnum)
1841
+ level: Integer,
1842
+ block_size: Integer
1843
+ ).returns(Integer)
1841
1844
  end
1842
1845
  def self.deflate_in_blocks_and_terminate(input_io, output_io, level: Zlib::DEFAULT_COMPRESSION, block_size: DEFAULT_BLOCKSIZE); end
1843
1846
 
@@ -1861,9 +1864,9 @@ end, T.untyped)
1861
1864
  params(
1862
1865
  input_io: IO,
1863
1866
  output_io: IO,
1864
- level: Fixnum,
1865
- block_size: Fixnum
1866
- ).returns(Fixnum)
1867
+ level: Integer,
1868
+ block_size: Integer
1869
+ ).returns(Integer)
1867
1870
  end
1868
1871
  def self.deflate_in_blocks(input_io, output_io, level: Zlib::DEFAULT_COMPRESSION, block_size: DEFAULT_BLOCKSIZE); end
1869
1872
  end
@@ -1889,7 +1892,7 @@ end, T.untyped)
1889
1892
  # _@param_ `kwargs_for_streamer_new` — Any options to pass to Streamer, see {Streamer#initialize}
1890
1893
  #
1891
1894
  # _@return_ — the size of the resulting archive, in bytes
1892
- sig { params(kwargs_for_streamer_new: T.untyped, blk: T.proc.params(the: SizeEstimator).void).returns(Integer) }
1895
+ sig { params(kwargs_for_streamer_new: T.untyped, blk: T.proc.params(estimator: SizeEstimator).void).returns(Integer) }
1893
1896
  def self.estimate(**kwargs_for_streamer_new, &blk); end
1894
1897
 
1895
1898
  # Add a fake entry to the archive, to see how big it is going to be in the end.
@@ -1903,7 +1906,7 @@ end, T.untyped)
1903
1906
  # _@param_ `use_data_descriptor` — whether the entry uses a postfix
1904
1907
  #
1905
1908
  # _@return_ — self
1906
- sig { params(filename: String, size: Fixnum, use_data_descriptor: T::Boolean).returns(T.untyped) }
1909
+ sig { params(filename: String, size: Integer, use_data_descriptor: T::Boolean).returns(T.untyped) }
1907
1910
  def add_stored_entry(filename:, size:, use_data_descriptor: false); end
1908
1911
 
1909
1912
  # Add a fake entry to the archive, to see how big it is going to be in the end.
@@ -1920,8 +1923,8 @@ end, T.untyped)
1920
1923
  sig do
1921
1924
  params(
1922
1925
  filename: String,
1923
- uncompressed_size: Fixnum,
1924
- compressed_size: Fixnum,
1926
+ uncompressed_size: Integer,
1927
+ compressed_size: Integer,
1925
1928
  use_data_descriptor: T::Boolean
1926
1929
  ).returns(T.untyped)
1927
1930
  end
@@ -1969,15 +1972,14 @@ end, T.untyped)
1969
1972
  # _@param_ `bytes` — the binary string to write (part of the uncompressed file)
1970
1973
  #
1971
1974
  # _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
1972
- sig { params(bytes: String).returns(Fixnum) }
1975
+ sig { params(bytes: String).returns(Integer) }
1973
1976
  def write(bytes); end
1974
1977
  end
1975
1978
 
1976
1979
  # Should be included into a Rails controller for easy ZIP output from any action.
1977
1980
  module RailsStreaming
1978
1981
  # Opens a {ZipKit::Streamer} and yields it to the caller. The output of the streamer
1979
- # gets automatically forwarded to the Rails response stream. When the output completes,
1980
- # the Rails response stream is going to be closed automatically.
1982
+ # will be sent through to the HTTP response body as it gets produced.
1981
1983
  #
1982
1984
  # Note that there is an important difference in how this method works, depending whether
1983
1985
  # you use it in a controller which includes `ActionController::Live` vs. one that does not.
@@ -2008,7 +2010,7 @@ end, T.untyped)
2008
2010
  type: String,
2009
2011
  use_chunked_transfer_encoding: T::Boolean,
2010
2012
  output_enumerator_options: T::Hash[T.untyped, T.untyped],
2011
- zip_streaming_blk: T.proc.params(the: ZipKit::Streamer).void
2013
+ zip_streaming_blk: T.proc.params(zip: ZipKit::Streamer).void
2012
2014
  ).returns(T::Boolean)
2013
2015
  end
2014
2016
  def zip_kit_stream(filename: "download.zip", type: "application/zip", use_chunked_transfer_encoding: false, **output_enumerator_options, &zip_streaming_blk); end
data/zip_kit.gemspec CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
27
27
  # zip_kit does not use any runtime dependencies (besides zlib). However, for testing
28
28
  # things quite a few things are used - and for a good reason.
29
29
 
30
- spec.add_development_dependency "rubyzip", "~> 1" # We test our output with _another_ ZIP library, which is the way to go here
30
+ spec.add_development_dependency "rubyzip", "~> 2" # We test our output with _another_ ZIP library, which is the way to go here
31
31
  spec.add_development_dependency "rack" # For tests where we spin up a server. Both for streaming out and for testing reads over HTTP
32
32
  spec.add_development_dependency "rake", "~> 12.2"
33
33
  spec.add_development_dependency "rspec", "~> 3"
@@ -40,6 +40,7 @@ Gem::Specification.new do |spec|
40
40
  spec.add_development_dependency "standard", "1.28.5" # Very specific version of standard for 2.6 with _known_ settings
41
41
  spec.add_development_dependency "magic_frozen_string_literal"
42
42
  spec.add_development_dependency "puma"
43
+ spec.add_development_dependency "rails", "~> 5" # For testing RailsStreaming against an actual Rails controller
43
44
  spec.add_development_dependency "actionpack", "~> 5" # For testing RailsStreaming against an actual Rails controller
44
45
  spec.add_development_dependency "nokogiri", "~> 1", ">= 1.13" # Rails 5 does by mistake use an older Nokogiri otherwise
45
46
  spec.add_development_dependency "sinatra"
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.2
4
+ version: 6.3.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-27 00:00:00.000000000 Z
15
+ date: 2024-08-11 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: bundler
@@ -34,14 +34,14 @@ dependencies:
34
34
  requirements:
35
35
  - - "~>"
36
36
  - !ruby/object:Gem::Version
37
- version: '1'
37
+ version: '2'
38
38
  type: :development
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  requirements:
42
42
  - - "~>"
43
43
  - !ruby/object:Gem::Version
44
- version: '1'
44
+ version: '2'
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: rack
47
47
  requirement: !ruby/object:Gem::Requirement
@@ -216,6 +216,20 @@ dependencies:
216
216
  - - ">="
217
217
  - !ruby/object:Gem::Version
218
218
  version: '0'
219
+ - !ruby/object:Gem::Dependency
220
+ name: rails
221
+ requirement: !ruby/object:Gem::Requirement
222
+ requirements:
223
+ - - "~>"
224
+ - !ruby/object:Gem::Version
225
+ version: '5'
226
+ type: :development
227
+ prerelease: false
228
+ version_requirements: !ruby/object:Gem::Requirement
229
+ requirements:
230
+ - - "~>"
231
+ - !ruby/object:Gem::Version
232
+ version: '5'
219
233
  - !ruby/object:Gem::Dependency
220
234
  name: actionpack
221
235
  requirement: !ruby/object:Gem::Requirement
@@ -285,10 +299,8 @@ executables: []
285
299
  extensions: []
286
300
  extra_rdoc_files: []
287
301
  files:
288
- - ".document"
289
302
  - ".github/workflows/ci.yml"
290
303
  - ".gitignore"
291
- - ".rspec"
292
304
  - ".standard.yml"
293
305
  - ".yardopts"
294
306
  - CHANGELOG.md
@@ -298,8 +310,8 @@ files:
298
310
  - IMPLEMENTATION_DETAILS.md
299
311
  - LICENSE.txt
300
312
  - README.md
313
+ - RUBYZIP_DIFFERENCES.md
301
314
  - Rakefile
302
- - bench/buffered_crc32_bench.rb
303
315
  - examples/archive_size_estimate.rb
304
316
  - examples/config.ru
305
317
  - examples/deferred_write.rb
@@ -319,6 +331,7 @@ files:
319
331
  - lib/zip_kit/rack_chunked_body.rb
320
332
  - lib/zip_kit/rack_tempfile_body.rb
321
333
  - lib/zip_kit/rails_streaming.rb
334
+ - lib/zip_kit/railtie.rb
322
335
  - lib/zip_kit/remote_io.rb
323
336
  - lib/zip_kit/remote_uncap.rb
324
337
  - lib/zip_kit/size_estimator.rb
@@ -358,7 +371,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
358
371
  - !ruby/object:Gem::Version
359
372
  version: '0'
360
373
  requirements: []
361
- rubygems_version: 3.1.6
374
+ rubygems_version: 3.5.3
362
375
  signing_key:
363
376
  specification_version: 4
364
377
  summary: Stream out ZIP files from Ruby. Successor to zip_tricks.
data/.document DELETED
@@ -1,5 +0,0 @@
1
- lib/**/*.rb
2
- bin/*
3
- -
4
- features/**/*.feature
5
- LICENSE.txt
data/.rspec DELETED
@@ -1 +0,0 @@
1
- --color
@@ -1,109 +0,0 @@
1
- require "bundler"
2
- Bundler.setup
3
-
4
- require "benchmark"
5
- require "benchmark/ips"
6
- require_relative "../lib/zip_kit"
7
-
8
- n_bytes = 5 * 1024 * 1024
9
- r = Random.new
10
- bytes = (0...n_bytes).map { r.bytes(1) }
11
- buffer_sizes = [
12
- 1,
13
- 256,
14
- 512,
15
- 1024,
16
- 8 * 1024,
17
- 16 * 1024,
18
- 32 * 1024,
19
- 64 * 1024,
20
- 128 * 1024,
21
- 256 * 1024,
22
- 512 * 1024,
23
- 1024 * 1024,
24
- 2 * 1024 * 1024
25
- ]
26
-
27
- Benchmark.ips do |x|
28
- x.config(time: 5, warmup: 2)
29
- buffer_sizes.each do |buf_size|
30
- x.report "Single-byte <<-writes of #{n_bytes} using a #{buf_size} byte buffer" do
31
- crc = ZipKit::WriteBuffer.new(ZipKit::StreamCRC32.new, buf_size)
32
- bytes.each { |b| crc << b }
33
- crc.to_i
34
- end
35
- end
36
- x.compare!
37
- end
38
-
39
- __END__
40
-
41
- Warming up --------------------------------------
42
- Single-byte <<-writes of 5242880 using a 1 byte buffer
43
- 1.000 i/100ms
44
- Single-byte <<-writes of 5242880 using a 256 byte buffer
45
- 1.000 i/100ms
46
- Single-byte <<-writes of 5242880 using a 512 byte buffer
47
- 1.000 i/100ms
48
- Single-byte <<-writes of 5242880 using a 1024 byte buffer
49
- 1.000 i/100ms
50
- Single-byte <<-writes of 5242880 using a 8192 byte buffer
51
- 1.000 i/100ms
52
- Single-byte <<-writes of 5242880 using a 16384 byte buffer
53
- 1.000 i/100ms
54
- Single-byte <<-writes of 5242880 using a 32768 byte buffer
55
- 1.000 i/100ms
56
- Single-byte <<-writes of 5242880 using a 65536 byte buffer
57
- 1.000 i/100ms
58
- Single-byte <<-writes of 5242880 using a 131072 byte buffer
59
- 1.000 i/100ms
60
- Single-byte <<-writes of 5242880 using a 262144 byte buffer
61
- 1.000 i/100ms
62
- Single-byte <<-writes of 5242880 using a 524288 byte buffer
63
- 1.000 i/100ms
64
- Single-byte <<-writes of 5242880 using a 1048576 byte buffer
65
- 1.000 i/100ms
66
- Single-byte <<-writes of 5242880 using a 2097152 byte buffer
67
- 1.000 i/100ms
68
- Calculating -------------------------------------
69
- Single-byte <<-writes of 5242880 using a 1 byte buffer
70
- 0.054 (± 0.0%) i/s - 1.000 in 18.383019s
71
- Single-byte <<-writes of 5242880 using a 256 byte buffer
72
- 0.121 (± 0.0%) i/s - 1.000 in 8.286061s
73
- Single-byte <<-writes of 5242880 using a 512 byte buffer
74
- 0.124 (± 0.0%) i/s - 1.000 in 8.038112s
75
- Single-byte <<-writes of 5242880 using a 1024 byte buffer
76
- 0.128 (± 0.0%) i/s - 1.000 in 7.828562s
77
- Single-byte <<-writes of 5242880 using a 8192 byte buffer
78
- 0.123 (± 0.0%) i/s - 1.000 in 8.121586s
79
- Single-byte <<-writes of 5242880 using a 16384 byte buffer
80
- 0.127 (± 0.0%) i/s - 1.000 in 7.872240s
81
- Single-byte <<-writes of 5242880 using a 32768 byte buffer
82
- 0.126 (± 0.0%) i/s - 1.000 in 7.911816s
83
- Single-byte <<-writes of 5242880 using a 65536 byte buffer
84
- 0.126 (± 0.0%) i/s - 1.000 in 7.917318s
85
- Single-byte <<-writes of 5242880 using a 131072 byte buffer
86
- 0.127 (± 0.0%) i/s - 1.000 in 7.897223s
87
- Single-byte <<-writes of 5242880 using a 262144 byte buffer
88
- 0.130 (± 0.0%) i/s - 1.000 in 7.675608s
89
- Single-byte <<-writes of 5242880 using a 524288 byte buffer
90
- 0.130 (± 0.0%) i/s - 1.000 in 7.679886s
91
- Single-byte <<-writes of 5242880 using a 1048576 byte buffer
92
- 0.128 (± 0.0%) i/s - 1.000 in 7.788439s
93
- Single-byte <<-writes of 5242880 using a 2097152 byte buffer
94
- 0.128 (± 0.0%) i/s - 1.000 in 7.797839s
95
-
96
- Comparison:
97
- Single-byte <<-writes of 5242880 using a 262144 byte buffer: 0.1 i/s
98
- Single-byte <<-writes of 5242880 using a 524288 byte buffer: 0.1 i/s - 1.00x slower
99
- Single-byte <<-writes of 5242880 using a 1048576 byte buffer: 0.1 i/s - 1.01x slower
100
- Single-byte <<-writes of 5242880 using a 2097152 byte buffer: 0.1 i/s - 1.02x slower
101
- Single-byte <<-writes of 5242880 using a 1024 byte buffer: 0.1 i/s - 1.02x slower
102
- Single-byte <<-writes of 5242880 using a 16384 byte buffer: 0.1 i/s - 1.03x slower
103
- Single-byte <<-writes of 5242880 using a 131072 byte buffer: 0.1 i/s - 1.03x slower
104
- Single-byte <<-writes of 5242880 using a 32768 byte buffer: 0.1 i/s - 1.03x slower
105
- Single-byte <<-writes of 5242880 using a 65536 byte buffer: 0.1 i/s - 1.03x slower
106
- Single-byte <<-writes of 5242880 using a 512 byte buffer: 0.1 i/s - 1.05x slower
107
- Single-byte <<-writes of 5242880 using a 8192 byte buffer: 0.1 i/s - 1.06x slower
108
- Single-byte <<-writes of 5242880 using a 256 byte buffer: 0.1 i/s - 1.08x slower
109
- Single-byte <<-writes of 5242880 using a 1 byte buffer: 0.1 i/s - 2.39x slower