class Sablon::Template
Creates a template from an MS Word doc that can be easily manipulated
Attributes
Public Class Methods
Returns the processor classes with a pattern matching the entry name. If none match nil is returned.
# File lib/sablon/template.rb, line 26 def get_processors(entry_name) key = processors.keys.detect { |pattern| entry_name =~ pattern } processors[key] end
# File lib/sablon/template.rb, line 36 def initialize(path) @path = path end
# File lib/sablon/template.rb, line 31 def processors @processors ||= Hash.new([]) end
Adds a new processor to the processors hash. The pattern
is used to select which files the processor should handle. Multiple processors can be added for the same pattern.
# File lib/sablon/template.rb, line 14 def register_processor(pattern, klass, replace_all: false) processors[pattern] = [] if replace_all # if processors[pattern].empty? processors[pattern] = [klass] else processors[pattern] << klass end end
Public Instance Methods
Same as render_to_string
but writes the processed template to output_path
.
# File lib/sablon/template.rb, line 41 def render_to_file(output_path, context, properties = {}) File.open(output_path, 'wb') do |f| f.write render_to_string(context, properties) end end
Process the template. The context
hash will be available in the template.
# File lib/sablon/template.rb, line 48 def render_to_string(context, properties = {}) render(context, properties).string end
Private Instance Methods
creates directories of the unzipped docx file in the newly created docx file e.g. in case of word/_rels/document.xml.rels it creates word/ and _rels directories to apply recursive zipping. This is a hack to fix the issue of getting a corrupted file when any referencing between the xml files happen like in the case of implementing hyperlinks. The created_dirs array is augmented in place using '<<'
# File lib/sablon/template.rb, line 103 def create_dirs_in_zipfile(created_dirs, entry_path, output_stream) entry_path_tokens = entry_path.split('/') return created_dirs unless entry_path_tokens.length > 1 # prev_dir = '' entry_path_tokens.each do |dir_name| prev_dir += dir_name + '/' next if created_dirs.include? prev_dir # output_stream.put_next_entry(prev_dir) created_dirs << prev_dir end end
IMPORTANT: Open Office does not ignore whitespace around tags. We need to render the xml without indent and whitespace.
# File lib/sablon/template.rb, line 81 def generate_output_file(zip_out, contents) # output entries to zip file created_dirs = [] contents.each do |entry_name, content| create_dirs_in_zipfile(created_dirs, File.dirname(entry_name), zip_out) zip_out.put_next_entry(entry_name) # # convert Nokogiri XML to string if content.instance_of? Nokogiri::XML::Document content = content.to_xml(indent: 0, save_with: 0) end # zip_out.write(content) end end
Processes all of te entries searching for ones that match the pattern. The hash is converted into an array first to avoid any possible modification during iteration errors (i.e. creation of a new rels file).
# File lib/sablon/template.rb, line 71 def process(env) @document.zip_contents.to_a.each do |(entry_name, content)| @document.current_entry = entry_name processors = Template.get_processors(entry_name) processors.each { |processor| processor.process(content, env) } end end
# File lib/sablon/template.rb, line 54 def render(context, properties = {}) # initialize environment @document = Sablon::DOM::Model.new(Zip::File.open(@path)) env = Sablon::Environment.new(self, context) env.section_properties = properties # # process files process(env) # Zip::OutputStream.write_buffer(StringIO.new) do |out| generate_output_file(out, @document.zip_contents) end end