Sneaky Abstractions

Subscribe to my Feed, follow me on , recommend me on Working With Rails or see my code on GitHub

Zippy: rubyzip for dummies

Posted on July 30, 2008 08:21 Tagged with zippy, zip, rubyzip, ruby.

Ok, so I had to dynamically create zip files the other day. No biggie, rubyzip handles that very well. It’s just that 90% of the time it took was spent reading through the docs to figure out exactly which spells I had to cast to make it do what I wanted. And I’ve done it before, too. Now, it says right there on the first page – almost like a disclaimer – that “the basic API is modeled after the classes in java.util.zip from the Java SDK”, but seeing things like ZipOutputStream and ZipStreamableStream gives me flashbacks to Programming 101 and travelling salesmen; why couldn’t it be more like, say, Hash? This is Ruby damnit, we don’t actually want to program, we want to tell the computer what to do and then it just does it. Kind of like this:

Zippy.create 'funny.zip' do |zip|
  zip['README'] = 'Fun pics 4 u'
  Dir['pictures/*.jpg'].each do |filename|
    zip[filename] = File.open(filename)
  end
end

You can probably guess by now that I’m not just making this stuff up as I go. Zippy is a (thin) wrapper around rubyzip which has a more Ruby-like interface. It happily ignores edge cases – you know, like handling directories – and focuses on the most common operations.

Zippy.open 'funny.zip' do |zip|
  log "Changing README, was \"#{zip['README']}\""
  zip['README'] = 'Amusing photographs of cats'
end

Zippy.create('reports.zip', 'report.pdf' => generate_pdf, 'README' => 'Latest reports')
puts Zippy['reports.zip', 'README']
Zippy['reports.zip', 'another_report.pdf'] = generate_another_pdf

One of the things I had to deal with was having to give rubyzip a filename, although I wasn’t going to save the file to disk but send it as a response to a request in a Rails app. Zippy doesn’t need an explicit filename (it will still save it to a temporary file):

Zippy.new('foo.txt' => 'bar').data

In fact, if you add it as a gem dependency in your Rails app,

config.gem "zippy", :source => "http://gems.github.com", :lib => "zippy"

it has a little plugin which registers a template handler for the extension zipper, so you can generate zips on the fly:

#galleries_ontroller.rb
class GalleriesController < ActionController::Base
  def show
    @gallery = Gallery[params[:id]]
    respond_to do |format|
      format.html
      format.zip
    end
  end
end

#galleries/show.zip.zipper
zip['gallery.txt'] = "#{@gallery.title}\n\n#{@gallery.description}"
@gallery.photos.each do |photo|
  zip["photos/#{photo.to_param}.jpg"] = File.open(photo.filename)
end

If you're raking the leaves and it gets all over your driveway, just hose it off dummy!