class Sablon::DOM::Relationships

Adds new relationships to the entry's corresponding relationships file

Public Class Methods

extend_model(model_klass) click to toggle source

extends the Model class so it now has an “add_relationship” method

Calls superclass method Sablon::DOM::FileHandler::extend_model
# File lib/sablon/document_object_model/relationships.rb, line 10
def self.extend_model(model_klass)
  super do
    #
    # adds a relationship to the rels file for the current entry
    define_method(:add_relationship) do |rel_attr|
      # detemine name of rels file to augment
      rels_name = Relationships.rels_entry_name_for(@current_entry)

      # create the file if needed and update DOM
      create_entry_if_not_exist(rels_name, Relationships.file_template)
      @dom[rels_name].add_relationship(rel_attr)
    end
    #
    # adds file to the /word/media folder without overwriting an
    # existing file
    define_method(:add_media) do |name, data, rel_attr|
      rel_attr[:Target] = "media/#{name}"
      # This matches any characters after the last "." in the filename
      unless (extension = name.match(/.+\.(.+?$)/).to_a[1])
        raise ArgumentError, "Filename: '#{name}' has no discernable extension"
      end
      type = rel_attr[:Type].match(%r{/(\w+?)$}).to_a[1] + "/#{extension}"
      #
      if @zip_contents["word/#{rel_attr[:Target]}"]
        names = @zip_contents.keys.map { |n| File.basename(n) }
        pattern = "^(\\d+)-#{name}"
        max_val = names.collect { |n| n.match(pattern).to_a[1].to_i }.max
        rel_attr[:Target] = "media/#{max_val + 1}-#{name}"
      end
      #
      # add the content to the zip and create the relationship
      @zip_contents["word/#{rel_attr[:Target]}"] = data
      add_content_type(extension, type)
      add_relationship(rel_attr)
    end
    #
    # locates an existing rId in the approprirate rels file
    define_method(:find_relationship_by) do |attribute, value, entry = nil|
      entry = @current_entry if entry.nil?
      # find the rels file and search it if it exists
      rels_name = Relationships.rels_entry_name_for(entry)
      return unless @dom[rels_name]
      #
      @dom[rels_name].find_relationship_by(attribute, value)
    end
  end
end
file_template() click to toggle source
# File lib/sablon/document_object_model/relationships.rb, line 58
      def self.file_template
        <<-XML.gsub(/^\s+|\n/, '')
          <?xml version="1.0" encoding="UTF-8"?>
          <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
          </Relationships>
        XML
      end
new(xml_node) click to toggle source

Sets up the class instance to handle new relationships for a document. I only care about tags that have an integer component

Calls superclass method Sablon::DOM::FileHandler::new
# File lib/sablon/document_object_model/relationships.rb, line 73
def initialize(xml_node)
  super
  #
  @relationships = xml_node.root
  @max_rid = max_attribute_value('Relationship', 'Id')
end
rels_entry_name_for(entry_name) click to toggle source
# File lib/sablon/document_object_model/relationships.rb, line 66
def self.rels_entry_name_for(entry_name)
  par_dir = Pathname.new(File.dirname(entry_name))
  par_dir.join('_rels', "#{File.basename(entry_name)}.rels").to_s
end

Public Instance Methods

add_relationship(rel_attr) click to toggle source

adds a new relationship and returns the corresponding rId for it

# File lib/sablon/document_object_model/relationships.rb, line 87
def add_relationship(rel_attr)
  rel_attr['Id'] = "rId#{next_rid}"
  @relationships << relationship_tag(rel_attr)
  #
  rel_attr['Id']
end
find_relationship_by(attribute, value) click to toggle source

Reurns an XML node based on the attribute value or nil if one does not exist

# File lib/sablon/document_object_model/relationships.rb, line 96
def find_relationship_by(attribute, value)
  @relationships.css(%(Relationship[#{attribute}="#{value}"])).first
end
max_attribute_value(selector, attr_name) click to toggle source

Finds the maximum value of an attribute by converting it to an integer. Non numeric portions of values are ignored.

# File lib/sablon/document_object_model/relationships.rb, line 82
def max_attribute_value(selector, attr_name)
  super(@relationships, selector, attr_name, query_method: :css)
end

Private Instance Methods

next_rid() click to toggle source

increments the max rid and returns it

# File lib/sablon/document_object_model/relationships.rb, line 103
def next_rid
  @max_rid += 1
end
relationship_tag(rel_attr) click to toggle source

Builds the relationship WordML tag and returns it

# File lib/sablon/document_object_model/relationships.rb, line 108
def relationship_tag(rel_attr)
  attr_str = rel_attr.map { |k, v| %(#{k}="#{v}") }.join(' ')
  "<Relationship #{attr_str}/>".gsub(/&(?!amp;)/, '&amp;')
end