zippy 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +19 -0
- data/lib/zippy.rb +216 -0
- data/rails/README +18 -0
- data/rails/init.rb +23 -0
- metadata +67 -0
data/README
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Zippy.create 'awsum.zip' do |zip|
|
2
|
+
zip['README'] = 'In Soviet Russia, README READSYOU'
|
3
|
+
zip['porn.mpeg'] = File.open('rick astley - never gonna give you up.mpg')
|
4
|
+
end
|
5
|
+
|
6
|
+
Zippy.list('awsum.zip') #=> ['README', 'porn.mpeg']
|
7
|
+
|
8
|
+
Zippy.open('awsum.zip') do |zip|
|
9
|
+
zip['bin/hello_world'] = "#!/usr/bin/env ruby\n\nputs 'hello, zip world'"
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
#Your params as a zip
|
15
|
+
#It's SAAS!
|
16
|
+
require 'sinatra'
|
17
|
+
get '/' do
|
18
|
+
Zippy.new{|z| params.each{|k,v| z[k] = v } }.data
|
19
|
+
end
|
data/lib/zippy.rb
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'zip/zip'
|
2
|
+
|
3
|
+
class Zippy
|
4
|
+
|
5
|
+
include Enumerable
|
6
|
+
#extend Enumerable
|
7
|
+
|
8
|
+
|
9
|
+
#Make an archive
|
10
|
+
#Filename is optional; if none is provided, a generated, temporary
|
11
|
+
#filename will be used.
|
12
|
+
#If a block is provided, the archive is yielded
|
13
|
+
#Takes an optional second parameter which is a hash of entries that will
|
14
|
+
#be added after initialization
|
15
|
+
def initialize(entries_and_options={})
|
16
|
+
entries_and_options.each{|k,v| send("#{k}=", v) if respond_to?("#{k}=") && k.is_a?(Symbol) }
|
17
|
+
without_autocommit do
|
18
|
+
entries_and_options.each{|k,v| self[k] = v if k.is_a?(String) }
|
19
|
+
end
|
20
|
+
yield self if block_given?
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def each
|
25
|
+
zipfile.each{|e| yield e.name }
|
26
|
+
end
|
27
|
+
|
28
|
+
def size
|
29
|
+
zipfile.size
|
30
|
+
end
|
31
|
+
|
32
|
+
def empty?
|
33
|
+
size.zero?
|
34
|
+
end
|
35
|
+
|
36
|
+
#Returns the full path to all entries in the archive
|
37
|
+
def paths
|
38
|
+
map
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
#Read an entry
|
43
|
+
def [](entry)
|
44
|
+
return nil unless include?(entry)
|
45
|
+
zipfile.read(entry)
|
46
|
+
end
|
47
|
+
|
48
|
+
#Add or change an entry with the name +entry+
|
49
|
+
#+contents+ can be a string or an IO
|
50
|
+
def []=(entry, contents)
|
51
|
+
zipfile.get_output_stream entry do |s|
|
52
|
+
if contents.is_a?(String)
|
53
|
+
s.write contents
|
54
|
+
elsif contents.respond_to?(:read)
|
55
|
+
s.write contents.read(1024) until contents.eof?
|
56
|
+
elsif contents.respond_to?(:to_s)
|
57
|
+
s.write contents.to_s
|
58
|
+
else#Not sure these last two are different
|
59
|
+
s.write "#{contents}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
zipfile.commit if autocommit?
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
#Delete an entry
|
68
|
+
def delete(*entries)
|
69
|
+
entries.each do |entry|
|
70
|
+
zipfile.remove(entry)
|
71
|
+
end
|
72
|
+
zipfile.commit if autocommit?
|
73
|
+
entries
|
74
|
+
end
|
75
|
+
|
76
|
+
#Rename an entry
|
77
|
+
def rename(old_name, new_name)
|
78
|
+
zipfile.rename(old_name, new_name)
|
79
|
+
zipfile.commit if autocommit?
|
80
|
+
old_name
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
#Close the archive for writing
|
85
|
+
def close
|
86
|
+
write(filename)
|
87
|
+
zipfile.close
|
88
|
+
end
|
89
|
+
|
90
|
+
#Write the archive to +filename+
|
91
|
+
#If a filename is not provided, it will write
|
92
|
+
#to the default filename (self.filename)
|
93
|
+
def write(filename)
|
94
|
+
return false if empty?
|
95
|
+
zipfile.commit
|
96
|
+
unless filename == self.filename
|
97
|
+
FileUtils.cp(self.filename, filename)
|
98
|
+
end
|
99
|
+
true
|
100
|
+
end
|
101
|
+
|
102
|
+
#Returns the entire archive as a string
|
103
|
+
def data
|
104
|
+
return nil if empty?
|
105
|
+
zipfile.commit
|
106
|
+
File.read(filename)
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
def filename
|
111
|
+
@filename ||= random_filename
|
112
|
+
end
|
113
|
+
|
114
|
+
def filename=(filename)
|
115
|
+
rename_file(filename)
|
116
|
+
@filename = filename
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
def zipfile
|
121
|
+
@zipfile ||= Zip::ZipFile.new(filename, true)
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
#Create a new archive with the name +filename+, populate it
|
126
|
+
#and then close it
|
127
|
+
#
|
128
|
+
#Warning: Will overwrite existing file
|
129
|
+
def self.create(filename, options_and_entries={}, &b)
|
130
|
+
File.unlink(filename) if File.exists?(filename)
|
131
|
+
z = new({:filename => filename}.merge(options_and_entries), &b)
|
132
|
+
z.close
|
133
|
+
z
|
134
|
+
end
|
135
|
+
|
136
|
+
#Works the same as new, but require's an explicit filename
|
137
|
+
#If a block is provided, it will be closed at the end of the block
|
138
|
+
def self.open(filename, options_and_entries={})
|
139
|
+
raise(ArgumentError, "file \"#{filename}\" does not exist") unless File.exists?(filename)
|
140
|
+
z = new({:filename => filename}.merge(options_and_entries))
|
141
|
+
if block_given?
|
142
|
+
yield z
|
143
|
+
z.close
|
144
|
+
end
|
145
|
+
z
|
146
|
+
end
|
147
|
+
|
148
|
+
#Iterate each entry name _and_ its contents in the archive +filename+
|
149
|
+
def self.each(filename)
|
150
|
+
open(filename) do |zip|
|
151
|
+
zip.each do |name|
|
152
|
+
yield name, zip[name]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
#Returns an array of entry names from the archive +filename+
|
158
|
+
#
|
159
|
+
#Zippy.list('my.zip') #=> ['foo', 'bar']
|
160
|
+
def self.list(filename)
|
161
|
+
list = nil
|
162
|
+
open(filename){|z| list = z.paths }
|
163
|
+
list
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
#Read the contents of a single entry in +filename+
|
168
|
+
def self.read(filename, entry)
|
169
|
+
content = nil
|
170
|
+
open(filename){|z| content = z[entry] }
|
171
|
+
content
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
def self.[](filename, entry=nil)
|
176
|
+
entry ? read(filename, entry) : list(filename)
|
177
|
+
end
|
178
|
+
|
179
|
+
def self.[]=(filename, entry, content)
|
180
|
+
open(filename){|z| z[entry] = content }
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
def random_filename
|
187
|
+
File.join(Dir.tmpdir, "zippy_#{Time.now.to_f.to_s}.zip")
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
def rename_file(new_name)
|
192
|
+
if @filename && @zipfile && File.exists?(@filename)
|
193
|
+
zipfile.close
|
194
|
+
File.rename(@filename, new_name)
|
195
|
+
end
|
196
|
+
@zipfile = nil #Force reload
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
def autocommit?
|
201
|
+
@autocommit.nil? ? true : @autocommit
|
202
|
+
end
|
203
|
+
|
204
|
+
def autocommit=(b)
|
205
|
+
@autocommit = !!b
|
206
|
+
end
|
207
|
+
|
208
|
+
def without_autocommit
|
209
|
+
ac = autocommit?
|
210
|
+
self.autocommit = false
|
211
|
+
yield
|
212
|
+
self.autocommit = ac
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
end
|
data/rails/README
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
This plugin adds a template handler for the extension "zipper", so you
|
2
|
+
could for example have a view show.zip.zipper which returns a zip file.
|
3
|
+
The view file is evaluated as Ruby, inside a Zippy.new{|zip|} block.
|
4
|
+
|
5
|
+
Example controller:
|
6
|
+
def show
|
7
|
+
@gallery = Gallery.find(params[:id])
|
8
|
+
respond_to do |format|
|
9
|
+
format.html
|
10
|
+
format.zip
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Example view:
|
15
|
+
zip['description.txt'] = @gallery.description
|
16
|
+
@gallery.photos.each do |photo|
|
17
|
+
zip["photo_#{photo.id}.png"] = File.open(photo.url)
|
18
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'zippy'
|
2
|
+
|
3
|
+
Mime::Type.register 'application/zip', :zip
|
4
|
+
|
5
|
+
module ::ActionView
|
6
|
+
module TemplateHandlers
|
7
|
+
class Zipper < TemplateHandler
|
8
|
+
include Compilable
|
9
|
+
|
10
|
+
def compile(template)
|
11
|
+
"Zippy.new do |zip|" +
|
12
|
+
(template.respond_to?(:source) ? template.source : template) +
|
13
|
+
"end.data"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if defined? ::ActionView::Template and ::ActionView::Template.respond_to? :register_template_handler
|
20
|
+
::ActionView::Template
|
21
|
+
else
|
22
|
+
::ActionView::Base
|
23
|
+
end.register_template_handler(:zipper, ::ActionView::TemplateHandlers::Zipper)
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zippy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tore Darell
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-07-25 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rubyzip
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.9.1
|
24
|
+
version:
|
25
|
+
description: Zippy reads and writes zip files
|
26
|
+
email: toredarell@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- lib/zippy.rb
|
35
|
+
- README
|
36
|
+
- rails/init.rb
|
37
|
+
- rails/README
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/toretore/zippy
|
40
|
+
licenses: []
|
41
|
+
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.5
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: rubyzip for dummies
|
66
|
+
test_files: []
|
67
|
+
|