rubyzipin-memoryrack-test

How to iterate through an in-memory zip file in Ruby


I am writing a unit test, and one of them is returning a zip file and I want to check the content of this zip file, grab some values from it, and pass the values to the next tests.

I'm using Rack Test, so I know the content of my zip file is inside last_response.body. I have looked through the documentation of RubyZip but it seems that it's always expecting a file. Since I'm running a unit test, I prefer to have everything done in the memory as not to pollute any folder with test zip files, if possible.


Solution

  • See @bronson’s answer for a more up to date version of this answer using the newer RubyZip API.

    The Rubyzip docs you linked to look a bit old. The latest release (0.9.9) can handle IO objects, so you can use a StringIO (with a little tweaking).

    Even though the api will accept an IO, it still seems to assumes it’s a file and tries to call path on it, so first monkey patch StringIO to add a path method (it doesn’t need to actually do anything):

    require 'stringio'
    class StringIO
      def path
      end
    end
    

    Then you can do something like:

    require 'zip/zip'
    Zip::ZipInputStream.open_buffer(StringIO.new(last_response.body)) do |io|
      while (entry = io.get_next_entry)
        # deal with your zip contents here, e.g.
        puts "Contents of #{entry.name}: '#{io.read}'"
      end
    end
    

    and everything will be done in memory.