module Webgen::PathHandler::Base

This module provides the helper methods needed by most, if not all, path handlers.

About ↑

It provides default implementations of all methods expected by Webgen::PathHandler except create_nodes, namely initialize, parse_meta_info! and content.

The most important method used when implementing a path handler is probably create_node which should be used in create_nodes to create an actual Webgen::Node object from a Webgen::Path object.

The following utility methods are also provided:

Constants

DEST_PATH_PARENT_SEGMENTS

Public Class Methods

new(website) click to toggle source

Initialize the path handler with the given Website object.

# File lib/webgen/path_handler/base.rb, line 72
def initialize(website)
  @website = website
end

Public Instance Methods

parse_meta_info!(path) click to toggle source

Update path.meta_info with meta information found in the content of the path.

This default parse_meta_info! method does nothing and should be overridden in path handlers that know that additional meta information can be found in the content of the path itself.

Note that the return values of this method are given as extra parameters to the create_nodes method. If you don't handle extra parameters, return an empty array.

# File lib/webgen/path_handler/base.rb, line 84
def parse_meta_info!(path)
  []
end

Protected Instance Methods

create_node(path) { |node| ... } click to toggle source

Create a node from path, if possible, and yield the fully initialized node if a block is given as well as return it.

Note that the block should be used when the newly created node need to be modified because the returned node can also be a reused node (in case the information in the supplied path applies uniquely to an already existing node)!

The node class to be used for the to-be-created node can be specified via `path.meta_info`. This is normally used by specific path handlers to provide custom node classes.

The default base node class can be changed by setting `path.meta_info`. Note that the `node_class` key takes precedence over this key!

The parent node under which the new node should be created can optionally be specified via 'path.meta_info'. This node processing information has to be set to the alcn of an existing node.

If no node can be created (e.g. when 'path.meta_info' is set), nil is returned.

On the created node, the node information :path is set to the given path and :path_handler to the path handler instance.

# File lib/webgen/path_handler/base.rb, line 110
def create_node(path)
  return nil if path.meta_info['draft']
  parent = parent_node(path)
  dest_path = self.dest_path(parent, path)

  if node = node_exists?(path, dest_path)
    node_path = node.node_info[:path]
    if node_path != path
      raise Webgen::NodeCreationError.new("Another node <#{node}> with the same alcn or destination path already exists")
    elsif node_path.meta_info == path.meta_info
      @website.blackboard.dispatch_msg(:reused_existing_node, node)
      return node
    else
      node.tree.delete_node(node)
    end
  end

  if !path.meta_info['modified_at'].kind_of?(Time)
    @website.logger.debug do
      "Meta information 'modified_at' set to current time in <#{path}> since its value #{path.meta_info['modified_at'].inspect} was of type #{path.meta_info['modified_at'].class}"
    end
    path.meta_info['modified_at'] = Time.now
  end

  node = node_class(path).new(parent, path.cn, dest_path, path.meta_info.dup)
  node.node_info[:path] = path
  node.node_info[:path_handler] = self

  yield(node) if block_given?
  node
end
dest_path(parent, path) click to toggle source

Construct the destination path for the given path and parent node.

See the user documentation for how a destination path is constructed and which configuration options are used!

First it is checked if a node with the constructed destination path already exists. If it exists, the language part is forced to be in the destination path and the resulting destination path is returned.

# File lib/webgen/path_handler/base.rb, line 162
def dest_path(parent, path)
  path.meta_info['dest_path'] ||= '<parent><basename>(-<version>)(-<modified_at>)(.<lang>)<ext>'
  dpath = construct_dest_path(parent, path, false)
  if (node = node_exists?(path, dpath)) && node.lang != path.meta_info['lang']
    dpath = construct_dest_path(parent, path, true)
  end
  dpath
end
node_class(path) click to toggle source

Retrieve the node class that should be used for the given path.

# File lib/webgen/path_handler/base.rb, line 267
def node_class(path)
  if String === (klass = path.meta_info['node_class'])
    Webgen::Utils.const_for_name(klass) rescue Node
  elsif String === (klass = path.meta_info['base_node_class'])
    Webgen::Utils.const_for_name(klass) rescue Node
  else
    Node
  end
end
node_exists?(path, dest_path) click to toggle source

Check if the node alcn or the destination path, which would be created by create_node for the given paths, exists.

# File lib/webgen/path_handler/base.rb, line 261
def node_exists?(path, dest_path)
  @website.tree[path.alcn] || (!path.meta_info['no_output'] && @website.tree.node(dest_path, :dest_path))
end
parent_node(path) click to toggle source

Return the parent node for the given path.

# File lib/webgen/path_handler/base.rb, line 144
def parent_node(path)
  parent_alcn = path.meta_info['parent_alcn'] ||
    (path.parent_path == '' ? '' : Webgen::Path.new(path.parent_path).alcn)
  if !(parent = @website.tree[parent_alcn])
    raise Webgen::NodeCreationError.new("The needed parent node <#{parent_alcn}> does not exist")
  end
  parent
end

Private Instance Methods

adjust_index(index) click to toggle source

Consider the number index to be 1-based and convert it to a 0-based index needed for Ruby arrays.

An error is raised if the index is equal to 0.

# File lib/webgen/path_handler/base.rb, line 248
def adjust_index(index)
  if index > 0
    index - 1
  elsif index == 0
    raise Webgen::NodeCreationError.new("Invalid meta info 'dest_path', index into parent segments must not be 0")
  else
    index
  end
end
construct_dest_path(parent, path, force_lang_part) click to toggle source

Construct the destination path from the parent node and the path.

# File lib/webgen/path_handler/base.rb, line 176
def construct_dest_path(parent, path, force_lang_part)
  unless path.meta_info['dest_path'].kind_of?(String)
    raise Webgen::NodeCreationError.new("Invalid meta info 'dest_path', must be a string")
  end
  dest_path = path.meta_info['dest_path'].dup

  if dest_path.start_with?('webgen:')
    dest_path.gsub!(/^webgen:/, '')
  elsif dest_path !~ /^[\w+.-]+:/
    parent = parent.parent while parent.is_fragment?
    parent_segments = parent.dest_path.split('/')[1..-1] || []
    use_lang_part = if path.meta_info['lang'].nil? # unlocalized files never get a lang in the filename!
                      false
                    elsif force_lang_part
                      true
                    elsif @website.config['path_handler.lang_code_in_dest_path'] == 'except_default'
                      @website.config['website.lang'] != path.meta_info['lang']
                    else
                      @website.config['path_handler.lang_code_in_dest_path']
                    end
    use_version_part = if @website.config['path_handler.version_in_dest_path'] == 'except_default'
                         path.meta_info['version'] != 'default'
                       else
                         @website.config['path_handler.version_in_dest_path']
                       end

    replace_segment = lambda do |match|
      case match
      when DEST_PATH_PARENT_SEGMENTS
        nr1 = adjust_index($1.to_i)
        (nr2 = adjust_index($2.to_i)) if $2
        [parent_segments[nr2 ? nr1..nr2 : nr1]].flatten.compact.join('/')
      when "<parent>"
        parent.dest_path
      when "<basename>"
        path.basename
      when "<ext>"
        path.ext.empty? ? '' : '.' << path.ext
      when "<lang>"
        use_lang_part ? path.meta_info['lang'] : ''
      when "<version>"
        use_version_part ? path.meta_info['version'] : ''
      when "<modified_at>"
        path.meta_info['modified_at_in_dest_path'] ? path.meta_info['modified_at'].strftime('%Y%m%d%H%M%S') : ''
      when /<(year|month|day)>/
        ctime = path.meta_info['created_at']
        if !ctime.kind_of?(Time)
          raise Webgen::NodeCreationError.new("Invalid meta info 'created_at', needed for destination path creation")
        end
        ctime.send($1).to_s.rjust(2, '0')
      when /\((.*)\)/
        inner = $1
        replaced = inner.gsub(DEST_PATH_SEGMENTS, &replace_segment)
        removed = inner.gsub(DEST_PATH_SEGMENTS, "")
        replaced == removed ? '' : replaced
      else
        raise Webgen::NodeCreationError.new("Unknown destination path segment name: #{match}")
      end
    end
    dest_path.gsub!(DEST_PATH_SEGMENTS, &replace_segment)
    dest_path += '/' if path.path =~ /\/$/
    dest_path.gsub!(/\/\/+/, '/')
  end

  dest_path
end