require 'zip' require 'nokogiri' require 'combine_pdf' module Letters def self.apply_template(io, params) Zip::OutputStream.write_buffer do |out| Zip::File.open(io) do |zip| zip.each do |entry| out.put_next_entry(entry.name) if entry.name == "content.xml" out.write apply_template_xml(entry.get_input_stream.read, params) elsif !entry.directory? out.write entry.get_input_stream.read end end end end end def self.apply_template_xml(xml, params) doc = Nokogiri::XML(xml) doc.xpath("//*[contains(text(), 'DISPLAY_NAME')]").each do |node| node.content = node.content.gsub("DISPLAY_NAME", params["DISPLAY_NAME"]) end address_lines = params['ADDRESS'].split("\n") doc.xpath("//*[contains(text(), 'ADDRESS')]").each do |node| newnodes = [node] + address_lines[1..].map do |line| node.clone.tap do |c| c.content = c.content.gsub("ADDRESS", line) end end node.content = node.content.gsub("ADDRESS", address_lines.first) newnodes.each_cons(2) do |p, n| p.add_next_sibling(n) end end doc.to_xml(save_with: 0) end def self.generate(template, members) Dir.mktmpdir do |directory| members.each do |member| odt = apply_template(template, { "DISPLAY_NAME" => member.display_name, "ADDRESS" => member.address, }) File.open("#{directory}/#{member.number}.odt", "wb") { |out| out.write(odt.string) } end `libreoffice --convert-to pdf --outdir #{directory} #{directory}/*.odt` pdf = CombinePDF.new Dir["#{directory}/*.pdf"].each do |file| pdf << CombinePDF.load(file) end pdf.to_pdf end end end