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
72 def initialize(website)
73   @website = website
74 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
84 def parse_meta_info!(path)
85   []
86 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
110 def create_node(path)
111   return nil if path.meta_info['draft']
112   parent = parent_node(path)
113   dest_path = self.dest_path(parent, path)
114 
115   if node = node_exists?(path, dest_path)
116     node_path = node.node_info[:path]
117     if node_path != path
118       raise Webgen::NodeCreationError.new("Another node <#{node}> with the same alcn or destination path already exists")
119     elsif node_path.meta_info == path.meta_info
120       @website.blackboard.dispatch_msg(:reused_existing_node, node)
121       return node
122     else
123       node.tree.delete_node(node)
124     end
125   end
126 
127   if !path.meta_info['modified_at'].kind_of?(Time)
128     @website.logger.debug do
129       "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}"
130     end
131     path.meta_info['modified_at'] = Time.now
132   end
133 
134   node = node_class(path).new(parent, path.cn, dest_path, path.meta_info.dup)
135   node.node_info[:path] = path
136   node.node_info[:path_handler] = self
137 
138   yield(node) if block_given?
139   node
140 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
162 def dest_path(parent, path)
163   path.meta_info['dest_path'] ||= '<parent><basename>(-<version>)(-<modified_at>)(.<lang>)<ext>'
164   dpath = construct_dest_path(parent, path, false)
165   if (node = node_exists?(path, dpath)) && node.lang != path.meta_info['lang']
166     dpath = construct_dest_path(parent, path, true)
167   end
168   dpath
169 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
267 def node_class(path)
268   if String === (klass = path.meta_info['node_class'])
269     Webgen::Utils.const_for_name(klass) rescue Node
270   elsif String === (klass = path.meta_info['base_node_class'])
271     Webgen::Utils.const_for_name(klass) rescue Node
272   else
273     Node
274   end
275 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
261 def node_exists?(path, dest_path)
262   @website.tree[path.alcn] || (!path.meta_info['no_output'] && @website.tree.node(dest_path, :dest_path))
263 end
parent_node(path) click to toggle source

Return the parent node for the given path.

    # File lib/webgen/path_handler/base.rb
144 def parent_node(path)
145   parent_alcn = path.meta_info['parent_alcn'] ||
146     (path.parent_path == '' ? '' : Webgen::Path.new(path.parent_path).alcn)
147   if !(parent = @website.tree[parent_alcn])
148     raise Webgen::NodeCreationError.new("The needed parent node <#{parent_alcn}> does not exist")
149   end
150   parent
151 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
248 def adjust_index(index)
249   if index > 0
250     index - 1
251   elsif index == 0
252     raise Webgen::NodeCreationError.new("Invalid meta info 'dest_path', index into parent segments must not be 0")
253   else
254     index
255   end
256 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
176 def construct_dest_path(parent, path, force_lang_part)
177   unless path.meta_info['dest_path'].kind_of?(String)
178     raise Webgen::NodeCreationError.new("Invalid meta info 'dest_path', must be a string")
179   end
180   dest_path = path.meta_info['dest_path'].dup
181 
182   if dest_path.start_with?('webgen:')
183     dest_path.gsub!(/^webgen:/, '')
184   elsif dest_path !~ /^[\w+.-]+:/
185     parent = parent.parent while parent.is_fragment?
186     parent_segments = parent.dest_path.split('/')[1..-1] || []
187     use_lang_part = if path.meta_info['lang'].nil? # unlocalized files never get a lang in the filename!
188                       false
189                     elsif force_lang_part
190                       true
191                     elsif @website.config['path_handler.lang_code_in_dest_path'] == 'except_default'
192                       @website.config['website.lang'] != path.meta_info['lang']
193                     else
194                       @website.config['path_handler.lang_code_in_dest_path']
195                     end
196     use_version_part = if @website.config['path_handler.version_in_dest_path'] == 'except_default'
197                          path.meta_info['version'] != 'default'
198                        else
199                          @website.config['path_handler.version_in_dest_path']
200                        end
201 
202     replace_segment = lambda do |match|
203       case match
204       when DEST_PATH_PARENT_SEGMENTS
205         nr1 = adjust_index($1.to_i)
206         (nr2 = adjust_index($2.to_i)) if $2
207         [parent_segments[nr2 ? nr1..nr2 : nr1]].flatten.compact.join('/')
208       when "<parent>"
209         parent.dest_path
210       when "<basename>"
211         path.basename
212       when "<ext>"
213         path.ext.empty? ? '' : '.' << path.ext
214       when "<lang>"
215         use_lang_part ? path.meta_info['lang'] : ''
216       when "<version>"
217         use_version_part ? path.meta_info['version'] : ''
218       when "<modified_at>"
219         path.meta_info['modified_at_in_dest_path'] ? path.meta_info['modified_at'].strftime('%Y%m%d%H%M%S') : ''
220       when /<(year|month|day)>/
221         ctime = path.meta_info['created_at']
222         if !ctime.kind_of?(Time)
223           raise Webgen::NodeCreationError.new("Invalid meta info 'created_at', needed for destination path creation")
224         end
225         ctime.send($1).to_s.rjust(2, '0')
226       when /\((.*)\)/
227         inner = $1
228         replaced = inner.gsub(DEST_PATH_SEGMENTS, &replace_segment)
229         removed = inner.gsub(DEST_PATH_SEGMENTS, "")
230         replaced == removed ? '' : replaced
231       else
232         raise Webgen::NodeCreationError.new("Unknown destination path segment name: #{match}")
233       end
234     end
235     dest_path.gsub!(DEST_PATH_SEGMENTS, &replace_segment)
236     dest_path += '/' if path.path =~ /\/$/
237     dest_path.gsub!(/\/\/+/, '/')
238   end
239 
240   dest_path
241 end