Skip to content

Instantly share code, notes, and snippets.

@aortbals
Last active September 24, 2015 02:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aortbals/8c9d65fa212855c07c8d to your computer and use it in GitHub Desktop.
Save aortbals/8c9d65fa212855c07c8d to your computer and use it in GitHub Desktop.
Zip a directory in memory with ruby
require 'find'
require 'zip'
module Zippable
def to_zip
return zipped_file_path if File.exists? zipped_file_path
validate_file_exists
::Zip::File.open(zipped_file_path, ::Zip::File::CREATE) do |zipfile|
if File.directory? file_path
Find.find(file_path).each do |file|
zipfile.add(file.sub(file_path + '/', ''), file) if File.file? file
end
else
zipfile.add(file_name, file_path)
end
end
::File.chmod(0664, zipped_file_path)
zipped_file_path
end
private
def file_path
raise NotImplementedError, "#{self.class} does not implement the file_path method"
end
def file_name
File.basename(file_path)
end
def zipped_file_path
@zipped_file_path ||= "#{ENV['ZIPPED_FILES_DIR']}/#{file_name}.zip"
end
def validate_file_exists
unless File.exists? file_path
raise InvalidFileError, "this instance of #{self.class} has an invalid file_path"
end
end
end
require 'rails_helper'
class IncludesZippable
include Zippable
attr_reader :name, :dir
def initialize(name, dir)
@name = name
@dir = dir
end
def file_path
File.join(dir, name)
end
end
describe Zippable do
let(:base_dir) { File.expand_path("../../fixtures/files", __FILE__) }
let(:file) { "zippable_file.mp3" }
let(:dir) { "zippable_dir" }
let(:brackets) { "Dir.with.dots [123]" }
subject { IncludesZippable.new(name, base_dir) }
before :all do
`mkdir -p "#{ENV['ZIPPED_FILES_DIR']}"`
end
before do
delete_tmp_file(name)
end
shared_examples_for "the zip file exists" do
it {
subject.to_zip
expect(File.exists? zipped_file_path(name)).to be true
}
end
context "zipping a file" do
let(:name) { file }
it_behaves_like "the zip file exists"
it "returns a zipped file" do
expect(subject.to_zip).to eql("#{ENV['ZIPPED_FILES_DIR']}/zippable_file.mp3.zip")
end
end
context "zipping a directory" do
let(:name) { dir }
it_behaves_like "the zip file exists"
it "returns a zipped file" do
expect(subject.to_zip).to eql("#{ENV['ZIPPED_FILES_DIR']}/zippable_dir.zip")
end
end
context "the zipped file exists" do
let(:name) { file }
before do
File.stub(:exists?).with("#{ENV['ZIPPED_FILES_DIR']}/#{name}.zip").and_return(true)
end
it_behaves_like "the zip file exists"
it "returns the existing zipped file" do
expect(subject.to_zip).to eql("#{ENV['ZIPPED_FILES_DIR']}/zippable_file.mp3.zip")
end
end
context "zipping a missing file" do
let(:name) { "bogus" }
it { expect { subject.to_zip }.to raise_error(InvalidFileError,
"this instance of IncludesZippable has an invalid file_path")
}
end
context "zipping a directory with dots and brackets" do
let(:name) { brackets }
it_behaves_like "the zip file exists"
it "returns a zipped file" do
expect(subject.to_zip).to eql("#{ENV['ZIPPED_FILES_DIR']}/Dir.with.dots [123].zip")
end
end
end
def delete_tmp_file(name)
File.delete(zipped_file_path(name)) if File.exist?(zipped_file_path(name))
end
def zipped_file_path(name)
"#{ENV['ZIPPED_FILES_DIR']}/#{name}.zip"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment