zipstream 0.0.3 → 0.1.0
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.
- data/README.md +24 -0
- data/VERSION +1 -1
- data/lib/zipstream.rb +7 -1
- data/lib/zipstream/body.rb +10 -21
- data/lib/zipstream/fiber.rb +45 -0
- data/lib/zipstream/fiber_yielding_stream.rb +8 -0
- data/lib/zipstream/railtie.rb +24 -0
- metadata +7 -5
- data/lib/zipstream-fiber-compat.rb +0 -35
data/README.md
CHANGED
@@ -2,6 +2,28 @@
|
|
2
2
|
|
3
3
|
Create zip files to a stream.
|
4
4
|
|
5
|
+
Integration with Ruby on Rails means you can create a file, `index.zipstream`, which is a ruby file with a zip object:
|
6
|
+
|
7
|
+
@entries.each do |entry|
|
8
|
+
zip.write "entry-#{entry.id}.txt", entry.to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
Which will happily implicitly render from:
|
12
|
+
|
13
|
+
class EntriesController
|
14
|
+
def index
|
15
|
+
@entries = Entry.all
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Giving you a zip file when rendered. More to come!
|
20
|
+
|
21
|
+
## Caveats
|
22
|
+
|
23
|
+
Keep in mind that this will use one of your workers/threads/processes until the file is completely downloaded. We are using an iterated rack body which streams so if rack/web servers handle this nicely then you might be in luck.
|
24
|
+
|
25
|
+
Tested with Rails 3.1 on REE 1.8.7 and MRI 1.9.3. Specs coming soon (tm).
|
26
|
+
|
5
27
|
## Thanks
|
6
28
|
|
7
29
|
Inspired by http://pablotron.org/software/zipstream-php/
|
@@ -9,3 +31,5 @@ Inspired by http://pablotron.org/software/zipstream-php/
|
|
9
31
|
## License
|
10
32
|
|
11
33
|
Copyright (c) 2011 Samuel Cochran (sj26@sj26.com). Released under the MIT License, see [LICENSE][license] for details.
|
34
|
+
|
35
|
+
[license]: https://github.com/sj26/zipstream/blob/master/LICENSE
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/zipstream.rb
CHANGED
@@ -2,7 +2,7 @@ require 'date'
|
|
2
2
|
require 'zlib'
|
3
3
|
|
4
4
|
# Simple, streamable zip file creation
|
5
|
-
class
|
5
|
+
class Zipstream
|
6
6
|
VERSION = File.read File.expand_path '../../VERSION', __FILE__
|
7
7
|
|
8
8
|
def initialize stream, options={}
|
@@ -25,6 +25,7 @@ class ZipStream
|
|
25
25
|
crc = Zlib.crc32 data
|
26
26
|
zdata_length = zdata.length
|
27
27
|
data_length = data.length
|
28
|
+
name = name.to_s
|
28
29
|
name_length = name.length
|
29
30
|
comment = options[:comment].to_s || ""
|
30
31
|
comment_length = comment.length
|
@@ -125,3 +126,8 @@ protected
|
|
125
126
|
datetime.year << 25 | datetime.month << 21 | datetime.day << 16 | datetime.hour << 11 | datetime.min << 5 | datetime.sec >> 1
|
126
127
|
end
|
127
128
|
end
|
129
|
+
|
130
|
+
require 'zipstream/fiber'
|
131
|
+
require 'zipstream/fiber_yielding_stream'
|
132
|
+
require 'zipstream/body'
|
133
|
+
require 'zipstream/railtie' if defined? Rails
|
data/lib/zipstream/body.rb
CHANGED
@@ -1,32 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# Stream a zipfile as a rack response body
|
2
|
+
#
|
4
3
|
# We use Fibers to deep-yield data being written to the zip stream
|
5
|
-
#
|
6
|
-
class
|
4
|
+
# directly to Rack
|
5
|
+
class Zipstream::Body
|
7
6
|
def initialize &block
|
8
|
-
@stream = FiberYieldingStream.new
|
9
|
-
@fiber = Fiber.new do
|
10
|
-
|
11
|
-
block.call zip
|
12
|
-
zip.close
|
7
|
+
@stream = Zipstream::FiberYieldingStream.new
|
8
|
+
@fiber = Zipstream::Fiber.new do
|
9
|
+
Zipstream.new(@stream).tap(&block).close
|
13
10
|
# Make sure this returns nil as a sentinel
|
14
11
|
nil
|
15
12
|
end
|
16
13
|
end
|
17
14
|
|
18
15
|
def each
|
19
|
-
|
20
|
-
|
16
|
+
# Yield fiber yielded data until we hit our nil sentinel
|
17
|
+
until (yielded = @fiber.resume).nil?
|
18
|
+
yield yielded.first
|
21
19
|
end
|
22
20
|
end
|
23
|
-
|
24
|
-
# A stream that yields each write to the current fiber
|
25
|
-
class FiberYieldingStream
|
26
|
-
def write data
|
27
|
-
tap { Fiber.yield data }
|
28
|
-
end
|
29
|
-
|
30
|
-
alias << write
|
31
|
-
end
|
32
21
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
if defined? Fiber
|
2
|
+
# Use native Fibers if available
|
3
|
+
Zipstream::Fiber = Fiber
|
4
|
+
else
|
5
|
+
# Minimal compatibility layer for Fibers
|
6
|
+
# Doesn't seem very comprehensive nor resilient, but it does the job
|
7
|
+
# Credit: http://www.khjk.org/log/2010/jun/fibr.html
|
8
|
+
class Zipstream::Fiber
|
9
|
+
@@fibers = [] # a stack of fibers corresponding to calls of 'resume'
|
10
|
+
|
11
|
+
def initialize &block
|
12
|
+
# lambda makes 'return' work as expected
|
13
|
+
@body = lambda &block
|
14
|
+
end
|
15
|
+
|
16
|
+
def resume *args
|
17
|
+
@@fibers.push self
|
18
|
+
# jumping into fiber
|
19
|
+
jump *args
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.current
|
23
|
+
@@fibers.last
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.yield *args
|
27
|
+
if fiber = @@fibers.pop
|
28
|
+
# jumping out of fiber
|
29
|
+
fiber.send :jump, args
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def jump *args
|
36
|
+
callcc do |continuation|
|
37
|
+
destination, @body = @body, continuation
|
38
|
+
destination.call *args
|
39
|
+
@@fibers.pop
|
40
|
+
# return from the last 'resume'
|
41
|
+
@body.call
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Adds zip rendering support to Rails
|
2
|
+
class Zipstream::Railtie < Rails::Railtie
|
3
|
+
initializer "zipstream" do
|
4
|
+
# Register Mime::ZIP
|
5
|
+
Mime::Type.register "application/zip", :zip
|
6
|
+
|
7
|
+
# Mark our template handler as rendering zip files
|
8
|
+
Zipstream::Railtie::Template.default_format = Mime::ZIP
|
9
|
+
|
10
|
+
# Tell ActionView we can handle templates
|
11
|
+
ActionView::Template.register_template_handler :zipstream, Zipstream::Railtie::Template
|
12
|
+
end
|
13
|
+
|
14
|
+
# Create a zipstream as a rails template
|
15
|
+
class Template
|
16
|
+
class_attribute :default_format
|
17
|
+
|
18
|
+
def self.call template
|
19
|
+
"Zipstream::Body.new do |zip|
|
20
|
+
#{template.source}
|
21
|
+
end"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zipstream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70190926780580 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: 2.7.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70190926780580
|
25
25
|
description:
|
26
26
|
email: sj26@sj26.com
|
27
27
|
executables: []
|
@@ -34,7 +34,9 @@ files:
|
|
34
34
|
- LICENSE
|
35
35
|
- VERSION
|
36
36
|
- lib/zipstream/body.rb
|
37
|
-
- lib/zipstream
|
37
|
+
- lib/zipstream/fiber.rb
|
38
|
+
- lib/zipstream/fiber_yielding_stream.rb
|
39
|
+
- lib/zipstream/railtie.rb
|
38
40
|
- lib/zipstream.rb
|
39
41
|
homepage: http://github.com/sj26/zipstream
|
40
42
|
licenses: []
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# Credit: http://www.khjk.org/log/2010/jun/fibr.html
|
2
|
-
|
3
|
-
class Fiber
|
4
|
-
@@fibers = [] # a stack of fibers corresponding to calls of 'resume'
|
5
|
-
|
6
|
-
def initialize &block
|
7
|
-
@body = lambda &block # lambda makes 'return' work as expected
|
8
|
-
end
|
9
|
-
|
10
|
-
def resume *args
|
11
|
-
@@fibers.push self
|
12
|
-
jump *args # jumping into fiber
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.current
|
16
|
-
@@fibers.last
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.yield *args
|
20
|
-
if fiber = @@fibers.pop
|
21
|
-
fiber.send :jump, args # jumping out of fiber
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def jump *args
|
28
|
-
callcc do |continuation|
|
29
|
-
destination, @body = @body, continuation
|
30
|
-
destination.call *args
|
31
|
-
@@fibers.pop
|
32
|
-
@body.call # return from the last 'resume'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end if RUBY_VERSION < '1.9'
|