zipline 1.0.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +5 -1
- data/Gemfile +1 -3
- data/README.md +68 -28
- data/Rakefile +10 -2
- data/lib/zipline.rb +3 -4
- data/lib/zipline/version.rb +1 -1
- data/lib/zipline/zip_generator.rb +51 -13
- data/spec/lib/zipline/zip_generator_spec.rb +140 -23
- data/spec/spec_helper.rb +0 -4
- data/zipline.gemspec +3 -3
- metadata +16 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8de63c7a8518461b8fdbb249ce857b3f06ffc2bf3a7de69d6d5d6c5111f75015
|
4
|
+
data.tar.gz: edfc26eed9a1d52987a4d47330a015d2ebb0e3129f2c0791199a51b3b5abec70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc54e592ebd7c24cad03669786938a3662430389e81322ceef258898ec5d8e9949db956a7433ab7c4d139b4671100772c062c525f8d20b6782f3a221b80ea9f3
|
7
|
+
data.tar.gz: 2482828adb931c9630c209b7a9a06c913b43d577232dea8d877b88acb1fa3b60834c35a92175608610da0d7e80ad36d6a1f8cd2379b9af5a249ce2b1f7456990
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# Zipline
|
2
|
+
[![Build Status](https://travis-ci.org/fringd/zipline.svg?branch=master)](https://travis-ci.org/fringd/zipline)
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/zipline.svg)](https://badge.fury.io/rb/zipline)
|
2
4
|
|
3
5
|
A gem to stream dynamically generated zip files from a rails application. Unlike other solutions that generate zips for user download, zipline does not wait for the entire zip file to be created (or even for the entire input file in the cloud to be downloaded) before it begins sending the zip file to the user. It does this by never seeking backwards during zip creation, and streaming the zip file over http as it is constructed. The advantages of this are:
|
4
6
|
|
@@ -28,37 +30,75 @@ supported with [shrine](https://github.com/janko-m/shrine).
|
|
28
30
|
|
29
31
|
You'll need to be using puma or some other server that supports streaming output.
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
33
|
+
```Ruby
|
34
|
+
class MyController < ApplicationController
|
35
|
+
# enable zipline
|
36
|
+
include Zipline
|
37
|
+
|
38
|
+
def index
|
39
|
+
users = User.all
|
40
|
+
# you can replace user.avatar with any stream or any object that
|
41
|
+
# responds to :url, :path or :file.
|
42
|
+
# :modification_time is an optional third argument you can use.
|
43
|
+
files = users.map{ |user| [user.avatar, "#{user.username}.png", modification_time: 1.day.ago] }
|
44
|
+
zipline(files, 'avatars.zip')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
### ActiveStorage
|
50
|
+
|
51
|
+
```Ruby
|
52
|
+
users = User.all
|
53
|
+
files = users.map{ |user| [user.avatar, user.avatar.filename] }
|
54
|
+
zipline(files, 'avatars.zip')
|
55
|
+
```
|
56
|
+
|
57
|
+
### Carrierwave
|
58
|
+
|
59
|
+
```Ruby
|
60
|
+
users = User.all
|
61
|
+
files = users.map{ |user| [user.avatar, user.avatar_identifier] }
|
62
|
+
zipline(files, 'avatars.zip')
|
63
|
+
```
|
64
|
+
|
65
|
+
### Paperclip ([deprecated](https://thoughtbot.com/blog/closing-the-trombone))
|
66
|
+
|
67
|
+
```Ruby
|
68
|
+
users = User.all
|
69
|
+
files = users.map{ |user| [user.avatar, user.avatar_file_name] }
|
70
|
+
zipline(files, 'avatars.zip')
|
71
|
+
```
|
72
|
+
|
73
|
+
### Url
|
74
|
+
|
75
|
+
If you know the URL of the remote file you want to include, you can just pass in the
|
76
|
+
URL directly in place of the attachment object.
|
77
|
+
```Ruby
|
78
|
+
avatars = [
|
79
|
+
['http://www.example.com/user1.png', 'user1.png']
|
80
|
+
['http://www.example.com/user2.png', 'user2.png']
|
81
|
+
['http://www.example.com/user3.png', 'user3.png']
|
82
|
+
]
|
83
|
+
zipline(avatars, 'avatars.zip')
|
84
|
+
```
|
85
|
+
|
86
|
+
### Directories
|
45
87
|
|
46
88
|
For directories, just give the files names like "directory/file".
|
47
89
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
zipline(file_mappings, 'avatars.zip')
|
61
|
-
|
90
|
+
|
91
|
+
```Ruby
|
92
|
+
avatars = [
|
93
|
+
# remote_url zip_path zip_tricks_options
|
94
|
+
[ 'http://www.example.com/user1.png', 'avatars/user1.png', modification_time: Time.now.utc ]
|
95
|
+
[ 'http://www.example.com/user2.png', 'avatars/user2.png', modification_time: 1.day.ago ]
|
96
|
+
[ 'http://www.example.com/user3.png', 'avatars/user3.png' ]
|
97
|
+
]
|
98
|
+
|
99
|
+
zipline(avatars, 'avatars.zip')
|
100
|
+
```
|
101
|
+
|
62
102
|
## Contributing
|
63
103
|
|
64
104
|
1. Fork it
|
data/Rakefile
CHANGED
data/lib/zipline.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
require "zipline/version"
|
2
|
-
require 'curb'
|
3
2
|
require 'zip_tricks'
|
4
3
|
require "zipline/zip_generator"
|
5
4
|
|
6
5
|
# class MyController < ApplicationController
|
7
6
|
# include Zipline
|
8
7
|
# def index
|
9
|
-
# users= User.all
|
10
|
-
# files =
|
11
|
-
# zipline(
|
8
|
+
# users = User.all
|
9
|
+
# files = users.map{ |user| [user.avatar, "#{user.username}.png", modification_time: 1.day.ago] }
|
10
|
+
# zipline(files, 'avatars.zip')
|
12
11
|
# end
|
13
12
|
# end
|
14
13
|
module Zipline
|
data/lib/zipline/version.rb
CHANGED
@@ -14,14 +14,32 @@ module Zipline
|
|
14
14
|
|
15
15
|
def each(&block)
|
16
16
|
fake_io_writer = ZipTricks::BlockWrite.new(&block)
|
17
|
-
ZipTricks
|
18
|
-
|
17
|
+
# ZipTricks outputs lots of strings in rapid succession, and with
|
18
|
+
# servers it can be beneficial to avoid doing too many tiny writes so that
|
19
|
+
# the number of syscalls is minimized. See https://github.com/WeTransfer/zip_tricks/issues/78
|
20
|
+
# There is a built-in facility for this in ZipTricks which can be used to implement
|
21
|
+
# some cheap buffering here (it exists both in version 4 and version 5). The buffer is really
|
22
|
+
# tiny and roughly equal to the medium Linux socket buffer size (16 KB). Although output
|
23
|
+
# will be not so immediate with this buffering the overall performance will be better,
|
24
|
+
# especially with multiple clients being serviced at the same time.
|
25
|
+
# Note that the WriteBuffer writes the same, retained String object - but the contents
|
26
|
+
# of that object changes between calls. This should work fine with servers where the
|
27
|
+
# contents of the string gets written to a socket immediately before the execution inside
|
28
|
+
# the WriteBuffer resumes), but if the strings get retained somewhere - like in an Array -
|
29
|
+
# this might pose a problem. Unlikely that it will be an issue here though.
|
30
|
+
write_buffer_size = 16 * 1024
|
31
|
+
write_buffer = ZipTricks::WriteBuffer.new(fake_io_writer, write_buffer_size)
|
32
|
+
ZipTricks::Streamer.open(write_buffer) do |streamer|
|
33
|
+
@files.each do |file, name, options = {}|
|
34
|
+
handle_file(streamer, file, name.to_s, options)
|
35
|
+
end
|
19
36
|
end
|
37
|
+
write_buffer.flush! # for any remaining writes
|
20
38
|
end
|
21
39
|
|
22
|
-
def handle_file(streamer, file, name)
|
40
|
+
def handle_file(streamer, file, name, options)
|
23
41
|
file = normalize(file)
|
24
|
-
write_file(streamer, file, name)
|
42
|
+
write_file(streamer, file, name, options)
|
25
43
|
end
|
26
44
|
|
27
45
|
# This extracts either a url or a local file from the provided file.
|
@@ -45,32 +63,37 @@ module Zipline
|
|
45
63
|
elsif is_io?(file)
|
46
64
|
{file: file}
|
47
65
|
elsif defined?(ActiveStorage::Blob) && file.is_a?(ActiveStorage::Blob)
|
48
|
-
{
|
66
|
+
{blob: file}
|
67
|
+
elsif is_active_storage_attachment?(file) || is_active_storage_one?(file)
|
68
|
+
{blob: file.blob}
|
49
69
|
elsif file.respond_to? :url
|
50
70
|
{url: file.url}
|
51
71
|
elsif file.respond_to? :path
|
52
72
|
{file: File.open(file.path)}
|
53
73
|
elsif file.respond_to? :file
|
54
74
|
{file: File.open(file.file)}
|
75
|
+
elsif is_url?(file)
|
76
|
+
{url: file}
|
55
77
|
else
|
56
78
|
raise(ArgumentError, 'Bad File/Stream')
|
57
79
|
end
|
58
80
|
end
|
59
81
|
|
60
|
-
def write_file(streamer, file, name)
|
61
|
-
streamer.write_deflated_file(name) do |writer_for_file|
|
82
|
+
def write_file(streamer, file, name, options)
|
83
|
+
streamer.write_deflated_file(name, options) do |writer_for_file|
|
62
84
|
if file[:url]
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
85
|
+
the_remote_uri = URI(file[:url])
|
86
|
+
|
87
|
+
Net::HTTP.get_response(the_remote_uri) do |response|
|
88
|
+
response.read_body do |chunk|
|
89
|
+
writer_for_file << chunk
|
68
90
|
end
|
69
91
|
end
|
70
|
-
c.perform
|
71
92
|
elsif file[:file]
|
72
93
|
IO.copy_stream(file[:file], writer_for_file)
|
73
94
|
file[:file].close
|
95
|
+
elsif file[:blob]
|
96
|
+
file[:blob].download { |chunk| writer_for_file << chunk }
|
74
97
|
else
|
75
98
|
raise(ArgumentError, 'Bad File/Stream')
|
76
99
|
end
|
@@ -80,5 +103,20 @@ module Zipline
|
|
80
103
|
def is_io?(io_ish)
|
81
104
|
io_ish.respond_to? :read
|
82
105
|
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def is_active_storage_attachment?(file)
|
110
|
+
defined?(ActiveStorage::Attachment) && file.is_a?(ActiveStorage::Attachment)
|
111
|
+
end
|
112
|
+
|
113
|
+
def is_active_storage_one?(file)
|
114
|
+
defined?(ActiveStorage::Attached::One) && file.is_a?(ActiveStorage::Attached::One)
|
115
|
+
end
|
116
|
+
|
117
|
+
def is_url?(url)
|
118
|
+
url = URI.parse(url) rescue false
|
119
|
+
url.kind_of?(URI::HTTP) || url.kind_of?(URI::HTTPS)
|
120
|
+
end
|
83
121
|
end
|
84
122
|
end
|
@@ -1,6 +1,23 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'tempfile'
|
3
3
|
|
4
|
+
module ActiveStorage
|
5
|
+
class Attached
|
6
|
+
class One < Attached
|
7
|
+
end
|
8
|
+
end
|
9
|
+
class Attachment; end
|
10
|
+
class Blob; end
|
11
|
+
class Filename
|
12
|
+
def initialize(name)
|
13
|
+
@name = name
|
14
|
+
end
|
15
|
+
def to_s
|
16
|
+
@name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
4
21
|
describe Zipline::ZipGenerator do
|
5
22
|
before { Fog.mock! }
|
6
23
|
let(:file_attributes){ {
|
@@ -84,29 +101,68 @@ describe Zipline::ZipGenerator do
|
|
84
101
|
end
|
85
102
|
end
|
86
103
|
end
|
87
|
-
context "ActiveStorage
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
104
|
+
context "ActiveStorage" do
|
105
|
+
context "Attached::One" do
|
106
|
+
it "get blob" do
|
107
|
+
attached = create_attached_one
|
108
|
+
allow_any_instance_of(Object).to receive(:defined?).and_return(true)
|
109
|
+
|
110
|
+
normalized = generator.normalize(attached)
|
111
|
+
|
112
|
+
expect(normalized.keys).to include(:blob)
|
113
|
+
expect(normalized[:blob]).to be_a(ActiveStorage::Blob)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "Attachment" do
|
118
|
+
it "get blob" do
|
119
|
+
attachment = create_attachment
|
120
|
+
allow_any_instance_of(Object).to receive(:defined?).and_return(true)
|
121
|
+
|
122
|
+
normalized = generator.normalize(attachment)
|
123
|
+
|
124
|
+
expect(normalized.keys).to include(:blob)
|
125
|
+
expect(normalized[:blob]).to be_a(ActiveStorage::Blob)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context "Blob" do
|
130
|
+
it "get blob" do
|
131
|
+
blob = create_blob
|
132
|
+
allow_any_instance_of(Object).to receive(:defined?).and_return(true)
|
133
|
+
|
134
|
+
normalized = generator.normalize(blob)
|
135
|
+
|
136
|
+
expect(normalized.keys).to include(:blob)
|
137
|
+
expect(normalized[:blob]).to be_a(ActiveStorage::Blob)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def create_attached_one
|
142
|
+
attached = ActiveStorage::Attached::One.new
|
143
|
+
blob = create_blob
|
144
|
+
allow(attached).to receive(:blob).and_return(blob)
|
145
|
+
attached
|
146
|
+
end
|
147
|
+
|
148
|
+
def create_attachment
|
149
|
+
attachment = ActiveStorage::Attachment.new
|
150
|
+
blob = create_blob
|
151
|
+
allow(attachment).to receive(:blob).and_return(blob)
|
152
|
+
attachment
|
153
|
+
end
|
154
|
+
|
155
|
+
def create_blob
|
156
|
+
blob = ActiveStorage::Blob.new
|
157
|
+
allow(blob).to receive(:service_url).and_return('fakeurl')
|
158
|
+
filename = create_filename
|
159
|
+
allow(blob).to receive(:filename).and_return(filename)
|
160
|
+
blob
|
161
|
+
end
|
162
|
+
|
163
|
+
def create_filename
|
164
|
+
# Rails wraps Blob#filname in this class since Rails 5.2
|
165
|
+
ActiveStorage::Filename.new('test')
|
110
166
|
end
|
111
167
|
end
|
112
168
|
context "Fog" do
|
@@ -130,4 +186,65 @@ describe Zipline::ZipGenerator do
|
|
130
186
|
end
|
131
187
|
end
|
132
188
|
|
189
|
+
describe '.write_file' do
|
190
|
+
let(:file) { StringIO.new('passthrough') }
|
191
|
+
|
192
|
+
context 'when passing an ActiveStorage::Filename object as filename' do
|
193
|
+
let(:filename) { ActiveStorage::Filename.new('test') }
|
194
|
+
|
195
|
+
let(:generator) do
|
196
|
+
Zipline::ZipGenerator.new([[file, filename]])
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'passes a string as filename to ZipTricks' do
|
200
|
+
allow(file).to receive(:url).and_return('fakeurl')
|
201
|
+
expect_any_instance_of(ZipTricks::Streamer).to receive(:write_deflated_file)
|
202
|
+
.with('test', {})
|
203
|
+
generator.each { |_| 'Test' }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe 'passing an options hash' do
|
209
|
+
let(:file) { StringIO.new('passthrough') }
|
210
|
+
|
211
|
+
context 'with optional arguments' do
|
212
|
+
let(:mtime) { 1.day.ago }
|
213
|
+
let(:generator) do
|
214
|
+
Zipline::ZipGenerator.new([[file, 'test', modification_time: mtime]])
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'passes the options hash through handle_file' do
|
218
|
+
expect(generator).to receive(:handle_file)
|
219
|
+
.with(anything, anything, anything, modification_time: mtime)
|
220
|
+
generator.each { |_| 'Test' }
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'passes the options hash to ZipTricks' do
|
224
|
+
allow(file).to receive(:url).and_return('fakeurl')
|
225
|
+
expect_any_instance_of(ZipTricks::Streamer).to receive(:write_deflated_file)
|
226
|
+
.with(anything, modification_time: mtime)
|
227
|
+
generator.each { |_| 'Test' }
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'without optional arguments' do
|
232
|
+
let(:generator) do
|
233
|
+
Zipline::ZipGenerator.new([[file, 'test']])
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'passes the options hash through handle_file' do
|
237
|
+
expect(generator).to receive(:handle_file)
|
238
|
+
.with(anything, anything, anything, {})
|
239
|
+
generator.each { |_| 'Test' }
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'passes the options hash to ZipTricks' do
|
243
|
+
allow(file).to receive(:url).and_return('fakeurl')
|
244
|
+
expect_any_instance_of(ZipTricks::Streamer).to receive(:write_deflated_file)
|
245
|
+
.with(anything, {})
|
246
|
+
generator.each { |_| 'Test' }
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
133
250
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,9 +2,7 @@ require 'rspec'
|
|
2
2
|
require 'active_support'
|
3
3
|
require 'active_support/core_ext'
|
4
4
|
require 'zipline'
|
5
|
-
require 'aws-sdk'
|
6
5
|
require 'paperclip'
|
7
|
-
require 'fog'
|
8
6
|
require 'fog-aws'
|
9
7
|
require 'carrierwave'
|
10
8
|
|
@@ -21,8 +19,6 @@ CarrierWave.configure do |config|
|
|
21
19
|
|
22
20
|
end
|
23
21
|
|
24
|
-
|
25
|
-
|
26
22
|
RSpec.configure do |config|
|
27
23
|
config.color = true
|
28
24
|
config.order = :random
|
data/zipline.gemspec
CHANGED
@@ -14,8 +14,8 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.name = "zipline"
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Zipline::VERSION
|
17
|
+
gem.licenses = ['MIT']
|
17
18
|
|
18
|
-
gem.add_dependency '
|
19
|
-
gem.add_dependency '
|
20
|
-
gem.add_dependency 'curb', ['>= 0.8.0', '< 0.10']
|
19
|
+
gem.add_dependency 'actionpack', ['>= 3.2.1', '< 7.0']
|
20
|
+
gem.add_dependency 'zip_tricks', ['>= 4.2.1', '< 6.0']
|
21
21
|
end
|
metadata
CHANGED
@@ -1,37 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zipline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ram Dobson
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 4.2.1
|
20
|
-
- - "<="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 5.0.0
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 4.2.1
|
30
|
-
- - "<="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 5.0.0
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: rails
|
14
|
+
name: actionpack
|
35
15
|
requirement: !ruby/object:Gem::Requirement
|
36
16
|
requirements:
|
37
17
|
- - ">="
|
@@ -39,7 +19,7 @@ dependencies:
|
|
39
19
|
version: 3.2.1
|
40
20
|
- - "<"
|
41
21
|
- !ruby/object:Gem::Version
|
42
|
-
version: '
|
22
|
+
version: '7.0'
|
43
23
|
type: :runtime
|
44
24
|
prerelease: false
|
45
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -49,27 +29,27 @@ dependencies:
|
|
49
29
|
version: 3.2.1
|
50
30
|
- - "<"
|
51
31
|
- !ruby/object:Gem::Version
|
52
|
-
version: '
|
32
|
+
version: '7.0'
|
53
33
|
- !ruby/object:Gem::Dependency
|
54
|
-
name:
|
34
|
+
name: zip_tricks
|
55
35
|
requirement: !ruby/object:Gem::Requirement
|
56
36
|
requirements:
|
57
37
|
- - ">="
|
58
38
|
- !ruby/object:Gem::Version
|
59
|
-
version:
|
39
|
+
version: 4.2.1
|
60
40
|
- - "<"
|
61
41
|
- !ruby/object:Gem::Version
|
62
|
-
version: '0
|
42
|
+
version: '6.0'
|
63
43
|
type: :runtime
|
64
44
|
prerelease: false
|
65
45
|
version_requirements: !ruby/object:Gem::Requirement
|
66
46
|
requirements:
|
67
47
|
- - ">="
|
68
48
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
49
|
+
version: 4.2.1
|
70
50
|
- - "<"
|
71
51
|
- !ruby/object:Gem::Version
|
72
|
-
version: '0
|
52
|
+
version: '6.0'
|
73
53
|
description: a module for streaming dynamically generated zip files
|
74
54
|
email:
|
75
55
|
- ram.dobson@solsystemscompany.com
|
@@ -90,9 +70,10 @@ files:
|
|
90
70
|
- spec/spec_helper.rb
|
91
71
|
- zipline.gemspec
|
92
72
|
homepage: http://github.com/fringd/zipline
|
93
|
-
licenses:
|
73
|
+
licenses:
|
74
|
+
- MIT
|
94
75
|
metadata: {}
|
95
|
-
post_install_message:
|
76
|
+
post_install_message:
|
96
77
|
rdoc_options: []
|
97
78
|
require_paths:
|
98
79
|
- lib
|
@@ -107,9 +88,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
88
|
- !ruby/object:Gem::Version
|
108
89
|
version: '0'
|
109
90
|
requirements: []
|
110
|
-
|
111
|
-
|
112
|
-
signing_key:
|
91
|
+
rubygems_version: 3.2.3
|
92
|
+
signing_key:
|
113
93
|
specification_version: 4
|
114
94
|
summary: stream zip files from rails
|
115
95
|
test_files:
|