class Webgen::Path

About ↑

A Path object provides information about a path that is used to create one or more nodes as well as methods for accessing/modifying the path's content. Path objects are created by Source classes but can also be created during the rendering phase (see Webgen::PathHandler#create_secondary_nodes).

So a Path object always refers to a path from which nodes are created! In contrast, destination paths are just strings and specify the location where a specific node should be written to (see Node#destination_path).

A Path object can represent one of three different things: a directory, a file or a fragment. If the path ends with a slash character, then the path object represents a directory, if the path contains a hash character anywhere, then the path object represents a fragment and else it represents a file. Have a look at the user documentation to see the exact format that can be used for a path string!

Utility methods ↑

The Path class also provides some general methods for working with path strings which are also used, for example, by the Node class:

Attributes

path[R]

The original path string from which this Path object was created.

Public Class Methods

absolute?(uri) click to toggle source

Return true if the given URI is an absolute one, i.e. if it include a scheme.

# File lib/webgen/path.rb, line 59
def self.absolute?(uri)
  uri =~ /\A[\w+.-]+:/
end
append(base, path) click to toggle source

Append the path to the base path.

  • The base parameter has to be an acn/alcn/absolute path (i.e. starting with a slash).

  • If base represents a directory, it needs to have a trailing slash!

  • The path parameter doesn't need to be absolute and may contain path patterns.

# File lib/webgen/path.rb, line 68
def self.append(base, path)
  result = url(base) + url(path, false)
  (result.fragment.nil? ? result.path : "#{result.path}##{result.fragment}").encode!(path.encoding)
end
lcn(cn, lang) click to toggle source

Construct a localized canonical name from a given canonical name and a language.

# File lib/webgen/path.rb, line 87
def self.lcn(cn, lang)
  if lang.nil?
    cn
  else
    cn.split('.').insert((cn.start_with?('.') ? 2 : 1), lang.to_s).join('.')
  end
end
matches_pattern?(path, pattern, options = File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME) click to toggle source

Return true if the given path string matches the given non-empty path pattern.

If a fragment path (i.e. one which has a hash character somewhere) should be matched, the pattern needs to have a hash character as well.

For information on which patterns are supported, have a look at the API documentation of File.fnmatch.

# File lib/webgen/path.rb, line 80
def self.matches_pattern?(path, pattern, options = File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME)
  path = path.to_s
  pattern += '/' if path[-1] == ?/ && pattern[-1] != ?/
  (path.include?('#') ? pattern.include?('#') : true) && File.fnmatch(pattern, path, options)
end
new(path, meta_info = {}, &ioblock) click to toggle source

Create a new Path object for path (a string).

The optional block needs to return an IO object for getting the content of the path (see io and data).

The path string needs to be in a well defined format which can be looked up in the webgen user documentation.

# File lib/webgen/path.rb, line 105
def initialize(path, meta_info = {}, &ioblock)
  @path = path.freeze
  @meta_info = meta_info.dup
  @ioblock = block_given? ? ioblock : nil
end
url(path, make_absolute = true) click to toggle source

Construct an internal URL for the given path.

If the parameter make_absolute is true, then the path will be made absolute by prepending the special URL 'webgen://lh'

# File lib/webgen/path.rb, line 47
def self.url(path, make_absolute = true)
  URL_CACHE[[path, make_absolute]] ||= begin
                                         if absolute?(path) || !make_absolute
                                           URI.parse(URI::DEFAULT_PARSER.escape(path, URL_UNSAFE_PATTERN))
                                         else
                                           URI.parse(URI::DEFAULT_PARSER.escape("webgen://lh#{path[0] != ?/ ? '/' : ''}#{path}",
                                                                                URL_UNSAFE_PATTERN))
                                         end
                                       end.freeze
end

Public Instance Methods

<=>(other) click to toggle source

Compare the path of this object to 'other.path'.

# File lib/webgen/path.rb, line 277
def <=>(other)
  @path <=> other.to_str
end
==(other) click to toggle source

Equality – Return true if other is a Path object with the same path or if other is a String equal to the path. Else return false.

# File lib/webgen/path.rb, line 265
def ==(other)
  if other.kind_of?(Path)
    other.path == @path
  elsif other.kind_of?(String)
    other == @path
  else
    false
  end
end
Also aliased as: eql?
[](key) click to toggle source

Get the value of the meta information key.

This method has to be used to get meta information without triggering analyzation of the path string!

# File lib/webgen/path.rb, line 131
def [](key)
  @meta_info[key]
end
[]=(key, value) click to toggle source

Set the meta information key to value.

This method has to be used to set meta information without triggering analyzation of the path string!

# File lib/webgen/path.rb, line 139
def []=(key, value)
  @meta_info[key] = value
end
acn() click to toggle source

The absolute canonical name of this path.

Triggers analyzation of the path if invoked.

# File lib/webgen/path.rb, line 196
def acn
  if @path.include?('#')
    self.class.new(parent_path).acn << cn
  else
    parent_path + cn
  end
end
alcn() click to toggle source

The absolute localized canonical name of this path.

Triggers analyzation of the path if invoked.

# File lib/webgen/path.rb, line 207
def alcn
  if @path.include?('#')
    self.class.new(parent_path).alcn << lcn
  else
    parent_path + lcn
  end
end
basename() click to toggle source

The canonical name of the path without the extension.

Triggers analyzation of the path if invoked.

# File lib/webgen/path.rb, line 153
def basename
  defined?(@basename) ? @basename : (analyse; @basename)
end
cn() click to toggle source

The canonical name created from the path (namely from the parts basename and extension as well as the meta information version).

Triggers analyzation of the path if invoked.

# File lib/webgen/path.rb, line 176
def cn
  if meta_info['cn']
    tmp_cn = custom_cn
  else
    tmp_cn = basename.dup << (use_version_for_cn? ? "-#{meta_info['version']}" : '') <<
      (ext.length > 0 ? ".#{ext}" : '')
  end
  tmp_cn << (@path =~ /.\/$/ ? '/' : '')
end
data(mode = nil) click to toggle source

Return the content of the IO object of the path as string.

For a description of the parameter mode see io.

An error is raised, if no IO object is associated with the Path instance.

# File lib/webgen/path.rb, line 253
def data(mode = nil)
  mode ||= @meta_info['io_open_mode'] || 'r'
  io(mode) {|io| io.read}
end
eql?(other)
Alias for: ==
ext() click to toggle source

The extension of the path.

Triggers analyzation of the path if invoked.

# File lib/webgen/path.rb, line 160
def ext
  defined?(@ext) ? @ext : (analyse; @ext)
end
ext=(value) click to toggle source

Set the extension of the path.

Triggers analyzation of the path if invoked.

# File lib/webgen/path.rb, line 167
def ext=(value)
  defined?(@ext) || analyse
  @ext = value
end
io(mode = 'r') { |io| ... } click to toggle source

Provide access to the IO object of the path by yielding it.

After the method block returns, the IO object is automatically closed. An error is raised, if no IO object is associated with the Path instance.

The parameter mode specifies the mode in which the IO object should be opened. This can be used, for example, to specify a certain input encoding or to use binary mode.

# File lib/webgen/path.rb, line 240
def io(mode = 'r') # :yields: io
  raise "No IO object defined for the path #{self}" if @ioblock.nil?
  io = @ioblock.call(mode)
  yield(io)
ensure
  io.close if io
end
lcn() click to toggle source

The localized canonical name created from the path.

Triggers analyzation of the path if invoked.

# File lib/webgen/path.rb, line 189
def lcn
  self.class.lcn(cn, meta_info['lang'])
end
meta_info() click to toggle source

Meta information about the path.

Triggers analyzation of the path if invoked. See []= to setting meta information without triggering analyzation.

# File lib/webgen/path.rb, line 123
def meta_info
  defined?(@basename) ? @meta_info : (analyse; @meta_info)
end
mount_at(mp, prefix = nil) click to toggle source

Mount this path at the mount point mp, optionally stripping prefix from the parent path, and return the new Path object.

The parameters mp and prefix have to be absolute directory paths, ie. they have to start and end with a slash and must not contain any hash characters!

Also note that mounting a path is not possible once it is fully initialized, i.e. once some information extracted from the path string is accessed.

# File lib/webgen/path.rb, line 224
def mount_at(mp, prefix = nil)
  raise(ArgumentError, "Can't mount a fully initialized path") if defined?(@basename)
  raise(ArgumentError, "The mount point (#{mp}) must be a valid directory path") if mp =~ /^[^\/]|#|[^\/]$/
  raise(ArgumentError, "The strip prefix (#{prefix}) must be a valid directory path") if !prefix.nil? && prefix =~ /^[^\/]|#|[^\/]$/

  temp = self.class.new(File.join(mp, @path.sub(/^#{Regexp.escape(prefix.to_s)}/, '')), @meta_info, &@ioblock)
  temp
end
parent_path() click to toggle source

The string specifying the parent path.

Triggers analyzation of the path if invoked.

# File lib/webgen/path.rb, line 146
def parent_path
  defined?(@parent_path) ? @parent_path : (analyse; @parent_path)
end
set_io(&block) click to toggle source

Set the IO block to the provided block.

# File lib/webgen/path.rb, line 259
def set_io(&block)
  @ioblock = block
end

Private Instance Methods

analyse() click to toggle source

Analyse the path and extract the needed information.

# File lib/webgen/path.rb, line 299
def analyse
  if @path.include?('#')
    analyse_fragment
  elsif @path[-1] == ?/
    analyse_directory
  else
    analyse_file
  end
  @meta_info['title'] ||= begin
                            name = @basename.tr('_-', ' ')
                            name[0] = name[0].upcase
                            name
                          end
  @ext ||= ''
  raise "The basename of a path may not be empty: #{@path}" if @basename.empty? || @basename == '#'
  raise "The parent path must start with a slash: #{@path}" if @path[0] != ?/
end
analyse_directory() click to toggle source

Analyse the path assuming it is a directory.

# File lib/webgen/path.rb, line 318
def analyse_directory
  @parent_path = (@path == '/' ? '' : File.join(File.dirname(@path), '/'))
  @basename = File.basename(@path)
end
analyse_file() click to toggle source

Analyse the path assuming it is a file.

# File lib/webgen/path.rb, line 326
def analyse_file
  @parent_path = File.join(File.dirname(@path), '/')
  match_data = FILENAME_RE.match(File.basename(@path))

  if !match_data[1].nil? && match_data[3].nil? && match_data[4].nil?
    # handle special case of sort_info.basename as basename.ext
    @basename = match_data[1]
    @ext = match_data[2]
  elsif !match_data[1].nil? && match_data[3].nil? && !match_data[4].nil? &&
      (lang = Webgen::LanguageManager.language_for_code(match_data[2]))
    # handle special case of sort_info.basename.ext as basename.lang.ext if basename is a lang
    @basename = match_data[1]
    @meta_info['lang'] = lang
    @ext = match_data[4]
  else
    @meta_info['sort_info'] ||= match_data[1].to_i unless match_data[1].nil?
    @basename               = match_data[2]
    @meta_info['lang']      ||= Webgen::LanguageManager.language_for_code(match_data[3]) if match_data[3]
    @ext                    = (@meta_info['lang'].nil? && !match_data[3].nil? ? match_data[3] << '.' : '') << match_data[4].to_s
  end
end
analyse_fragment() click to toggle source

Analyse the path assuming it is a fragment.

# File lib/webgen/path.rb, line 349
def analyse_fragment
  @parent_path, @basename =  @path.scan(/^(.*?)(#.*?)$/).first
  raise "The parent path of a fragment path must be a file path and not a directory path: #{@path}" if @parent_path[-1] == ?/
  raise "A fragment path must only contain one hash character: #{path}" if @path.count("#") > 1
end
custom_cn() click to toggle source

Construct a custom canonical name given by the 'cn' meta information.

# File lib/webgen/path.rb, line 363
def custom_cn
  replace_segment = lambda do |match|
    case match
    when "<basename>"
      basename
    when "<ext>"
      ext.empty? ? '' : '.' << ext
    when "<version>"
      use_version_for_cn? ? meta_info['version'] : ''
    when /\((.*)\)/
      inner = $1
      replaced = inner.gsub(CN_SEGMENTS, &replace_segment)
      removed = inner.gsub(CN_SEGMENTS, "")
      replaced == removed ? '' : replaced
    else
      ''
    end
  end
  self.meta_info['cn'].to_s.gsub(CN_SEGMENTS, &replace_segment).gsub(/\/+$/, '')
end
use_version_for_cn?() click to toggle source

Whether the version information should be added to the cn?

# File lib/webgen/path.rb, line 356
def use_version_for_cn?
  meta_info['version'] && meta_info['version'] != 'default'
end