Skip to content

Instantly share code, notes, and snippets.

@noniq
Last active June 9, 2016 15:04
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 noniq/50083b746a5eb80a618e43e35a1c2c98 to your computer and use it in GitHub Desktop.
Save noniq/50083b746a5eb80a618e43e35a1c2c98 to your computer and use it in GitHub Desktop.
Zip file generator in ruby, suitable for templating OOXML documents (DOCX, XLSX, …)
# This is a simple example which uses rubyzip to recursively generate a zip file from the contents of a specified directory. The
# directory itself is not included in the archive, rather just its contents.
#
# The generator has been extended to support ERB templates: Files with an extension ending in `.erb` will be processed by ERB
# before they are added to the archive (the filename in the archive will have `.erb` stripped).
#
# Suitable for templating OOXML documents (eg. DOCX or AXSLX): Just create the template document in the office application of your
# choice, rename the extension to ".zip" and unzip the file. Now add ERB code to individual files as needed (for DOCX you’ll most
# likely want to edit `word/document.xml`). Don't forget to also add an additonial `.erb` extension to those files! Then run
# ErbZipGenerator on the top level directory and with a suitable output filename – done!
#
# Usage:
# directoryToZip = "/tmp/input/document"
# outputFile = "/tmp/document.docx"
# zf = ZipFileGenerator.new(directoryToZip, outputFile, binding)
# zf.write()
#
# Based on https://github.com/rubyzip/rubyzip/blob/05916bf89181e1955118fd3ea059f18acac28cc8/samples/example_recursive.rb
require 'zip'
class ErbZipFileGenerator
# Initialize with the directory to zip and the location of the output archive.
def initialize(input_dir, output_file, erb_binding)
@input_dir = input_dir
@output_file = output_file
@erb_binding = erb_binding
end
# Zip the input directory.
def write
entries = Dir.entries(@input_dir) - %w(. ..)
::Zip::File.open(@output_file, ::Zip::File::CREATE) do |io|
write_entries entries, '', io
end
end
private
# A helper method to make the recursion work.
def write_entries(entries, path, io)
entries.each do |e|
zip_file_path = path == '' ? e : File.join(path, e)
disk_file_path = File.join(@input_dir, zip_file_path)
if File.directory? disk_file_path
recursively_deflate_directory(disk_file_path, io, zip_file_path)
else
put_into_archive(disk_file_path, io, zip_file_path)
end
end
end
def recursively_deflate_directory(disk_file_path, io, zip_file_path)
io.mkdir zip_file_path
subdir = Dir.entries(disk_file_path) - %w(. ..)
write_entries subdir, zip_file_path, io
end
def put_into_archive(disk_file_path, io, zip_file_path)
io.get_output_stream(zip_file_path.sub(/\.erb$/, '')) do |f|
contents = if disk_file_path.end_with?('.erb')
ERB.new(File.read(disk_file_path)).result(@erb_binding)
else
File.open(disk_file_path, 'rb').read
end
f.puts(contents)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment