class Sablon::Template

Creates a template from an MS Word doc that can be easily manipulated

Attributes

document[R]

Public Class Methods

get_processors(entry_name) click to toggle source

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
new(path) click to toggle source
# File lib/sablon/template.rb, line 36
def initialize(path)
  @path = path
end
processors() click to toggle source
# File lib/sablon/template.rb, line 31
def processors
  @processors ||= Hash.new([])
end
register_processor(pattern, klass, replace_all: false) click to toggle source

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

render_to_file(output_path, context, properties = {}) click to toggle source

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
render_to_string(context, properties = {}) click to toggle source

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

create_dirs_in_zipfile(created_dirs, entry_path, output_stream) click to toggle source

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
generate_output_file(zip_out, contents) click to toggle source

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
process(env) click to toggle source

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
render(context, properties = {}) click to toggle source
# 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