Object
Represents a file, a directory or a fragment. A node always belongs to a Tree.
All needed meta and processing information is associated with a Node. The meta information is available throught the #[] and # accessors, the processing information through the # accessor.
Although node information should be changed by code, it is not advised to change meta information values in code since this may lead to unwanted behaviour!
Create a new Node instance.
The parent node under which this nodes should be created.
The full output path for this node. If this node is a directory, the path must have a trailing slash (dir/). If it is a fragment, the hash sign must be the first character of the path (#). This can also be an absolute path like myhost.com/.
The canonical name for this node. Needs to be of the form basename.ext or basename where basename does not contain any dots. Also, the basename must not include a language part!
A hash with meta information for the new node.
The language of a node is taken from the meta information lang and the entry is deleted from the meta information hash. The language cannot be changed afterwards! If no lang key is found, the node is language neutral.
# File lib/webgen/node.rb, line 78 78: def initialize(parent, path, cn, meta_info = {}) 79: @parent = parent 80: @cn = cn.freeze 81: @children = [] 82: reinit(path, meta_info) 83: init_rest 84: end
Construct an internal URL for the given name which can be an acn/alcn/path. If the parameter make_absolute is true, then a relative URL will be made absolute by prepending the special URL webgen:://webgen.localhost/.
# File lib/webgen/node.rb, line 228 228: def self.url(name, make_absolute = true) 229: url = URI::parse(URI::escape(name, URL_UNSAFE_PATTERN)) 230: url = URI::parse('webgen://webgen.localhost/') + url unless url.absolute? || !make_absolute 231: url 232: end
Sort nodes by using the meta info sort_info (or title if sort_info is not set) of both involved nodes.
# File lib/webgen/node.rb, line 211 211: def <=>(other) 212: self_so = (@meta_info['sort_info'] && @meta_info['sort_info'].to_s) || @meta_info['title'] || '' 213: other_so = (other['sort_info'] && other['sort_info'].to_s) || other['title'] || '' 214: if self_so !~ /\D/ && other_so !~ /\D/ 215: self_so = self_so.to_i 216: other_so = other_so.to_i 217: end 218: self_so <=> other_so 219: end
Return true if the alcn matches the pattern. See Webgen::Path.match for more information.
# File lib/webgen/node.rb, line 205 205: def =~(pattern) 206: Webgen::Path.match(@alcn, pattern) 207: end
Return the meta information item for key.
# File lib/webgen/node.rb, line 104 104: def [](key) 105: @meta_info[key] 106: end
Assign value to the meta information item for key.
# File lib/webgen/node.rb, line 109 109: def []=(key, value) 110: @meta_info[key] = value 111: end
Return true if the node has changed since the last webgen run. If it has changed, dirty is set to true.
Sends the message :node_changed? with self as argument unless the node is already dirty. A listener to this message should set the flag :dirty on the passed node if he thinks it is dirty.
# File lib/webgen/node.rb, line 162 162: def changed? 163: if_not_checked(:node) do 164: flag(:dirty) if meta_info_changed? || user_nodes_changed? || 165: node_info[:used_nodes].any? {|n| n != @alcn && (!tree[n] || tree[n].changed?)} || 166: node_info[:used_meta_info_nodes].any? {|n| n != @alcn && (!tree[n] || tree[n].meta_info_changed?)} 167: website.blackboard.dispatch_msg(:node_changed?, self) unless flagged?(:dirty) 168: end 169: flagged?(:dirty) 170: end
# File lib/webgen/node.rb, line 360 360: def find(opts = {}) 361: if opts[:alcn] 362: opts[:alcn] = Path.make_absolute(is_directory? ? alcn : parent.alcn.sub(/#.*$/, ''), opts[:alcn].to_s) 363: end 364: opts[:levels] = 100000 unless opts.has_key?(:levels) 365: 366: result = find_nodes(opts, nil, 1) 367: result.flatten! if result && (opts[:limit] || opts[:offset]) 368: result.sort!(opts[:sort]) if result 369: result.children = result.children[(opts[:offset].to_s.to_i)..(opts[:limit] ? opts[:offset].to_s.to_i + opts[:limit].to_s.to_i - 1 : 1)] 370: result 371: end
Flag the node with the keys and dispatch the message :node_flagged with self and keys as arguments. See # for valid keys.
# File lib/webgen/node.rb, line 144 144: def flag(*keys) 145: @flags += keys 146: website.blackboard.dispatch_msg(:node_flagged, self, keys) 147: end
Check if the node is flagged with one of the following:
Has the node been created or has it been read from the cache?
Does the node need to be reinitialized?
Set by other objects to true if they think the object has changed since the last run. Must not be set to false once it is true!
Set by other objects to true if the meta information of the node has changed since the last run. Must not be set to false once it is true!
# File lib/webgen/node.rb, line 138 138: def flagged?(key) 139: @flags.include?(key) 140: end
Return the node with the same canonical name but in language lang or, if no such node exists, an unlocalized version of the node. If no such node is found either, nil is returned.
# File lib/webgen/node.rb, line 246 246: def in_lang(lang) 247: avail = @tree.node_access[:acn][@acn] 248: avail.find do |n| 249: n = n.parent while n.is_fragment? 250: n.lang == lang 251: end || avail.find do |n| 252: n = n.parent while n.is_fragment? 253: n.lang.nil? 254: end 255: end
Check if the this node is in the subtree which is spanned by node. The check is performed using only the parent information of the involved nodes, NOT the actual path/alcn values!
# File lib/webgen/node.rb, line 237 237: def in_subtree_of?(node) 238: temp = self 239: temp = temp.parent while temp != tree.dummy_root && temp != node 240: temp != tree.dummy_root 241: end
Return an informative representation of the node.
# File lib/webgen/node.rb, line 200 200: def inspect 201: "<##{self.class.name}: alcn=#{@alcn}>" 202: end
Check if the node is a directory.
# File lib/webgen/node.rb, line 119 119: def is_directory?; @path[1] == // && !is_fragment?; end
Check if the node is a file.
# File lib/webgen/node.rb, line 122 122: def is_file?; !is_directory? && !is_fragment?; end
Check if the node is a fragment.
# File lib/webgen/node.rb, line 125 125: def is_fragment?; @cn[0] == ## end
Check if the node is the root node.
# File lib/webgen/node.rb, line 128 128: def is_root?; self == tree.root; end
Return a HTML link from this node to the node or, if this node and node are the same and the parameter website.link_to_current_page is false, a span element with the link text.
You can optionally specify additional attributes for the HTML element in the attr Hash. Also, the meta information link_attrs of the given node is used, if available, to set attributes. However, the attr parameter takes precedence over the link_attrs meta information. Be aware that all key-value pairs with Symbol keys are removed before the attributes are written. Therefore you always need to specify general attributes with Strings!
If the special value :link_text is present in the attributes, it will be used as the link text; otherwise the title of the node will be used.
If the special value :lang is present in the attributes, it will be used as parameter to the node.routing_node call for getting the linked-to node instead of this node’s lang attribute. Note: this is only useful when linking to a directory.
# File lib/webgen/node.rb, line 348 348: def link_to(node, attr = {}) 349: attr = node['link_attrs'].merge(attr) if node['link_attrs'].kind_of?(Hash) 350: rnode = node.routing_node(attr[:lang] || @lang) 351: link_text = attr[:link_text] || (rnode != node && rnode['routed_title']) || node['title'] 352: attr.delete_if {|k,v| k.kind_of?(Symbol)} 353: 354: use_link = (rnode != self || website.config['website.link_to_current_page']) 355: attr['href'] = self.route_to(rnode) if use_link 356: attrs = attr.collect {|name,value| "#{name.to_s}=\"#{value}\"" }.sort.unshift('').join(' ') 357: (use_link ? "<a#{attrs}>#{link_text}</a>" : "<span#{attrs}>#{link_text}</span>") 358: end
Return true if the meta information of the node has changed.
Sends the message :node_meta_info_changed? with self as argument unless the meta information of the node is already dirty. A listener to this message should set the flag :dirt_meta_info on the passed node if he thinks that the node’s meta information is dirty.
# File lib/webgen/node.rb, line 187 187: def meta_info_changed? 188: if_not_checked(:meta_info) do 189: website.blackboard.dispatch_msg(:node_meta_info_changed?, self) unless flagged?(:dirty_meta_info) 190: end 191: flagged?(:dirty_meta_info) 192: end
Return the node information hash which contains information for processing the node.
# File lib/webgen/node.rb, line 114 114: def node_info 115: tree.node_info[@alcn] ||= {} 116: end
Re-initializes an already initialized node and resets it to its pristine state.
# File lib/webgen/node.rb, line 87 87: def reinit(path, meta_info = {}) 88: old_path = @path if defined?(@path) 89: @path = path.freeze 90: @lang = Webgen::LanguageManager.language_for_code(meta_info.delete('lang')) 91: @lang = nil unless is_file? 92: @meta_info = meta_info 93: @flags = Set.new([:dirty, :created]) 94: if defined?(@tree) 95: @tree.node_access[:path].delete(old_path) if old_path 96: @tree.register_path(self) 97: self.node_info.clear 98: self.node_info[:used_nodes] = Set.new 99: self.node_info[:used_meta_info_nodes] = Set.new 100: end 101: end
Return the node representing the given path which can be an acn/alcn. The path can be absolute (i.e. starting with a slash) or relative to the current node. If no node exists for the given path or if the path is invalid, nil is returned.
If the path is an alcn and a node is found, it is returned. If the path is an acn, the correct localized node according to lang is returned or if no such node exists but an unlocalized version does, the unlocalized node is returned.
# File lib/webgen/node.rb, line 264 264: def resolve(path, lang = nil, use_passive_sources = true) 265: orig_path = path 266: url = self.class.url(@alcn) + self.class.url(path, false) 267: 268: path = url.path + (url.fragment.nil? ? '' : '#' + url.fragment) 269: return nil if path =~ /^\/\.\./ 270: 271: node = @tree[path, :alcn] 272: if !node || node.acn == path 273: (node = (@tree[path, :acn] || @tree[path + '/', :acn])) && (node = node.in_lang(lang)) 274: end 275: if !node && use_passive_sources && !website.config['passive_sources'].empty? 276: nodes = website.blackboard.invoke(:create_nodes_from_paths, [path]) 277: node = resolve(orig_path, lang, false) 278: node.node_info[:used_meta_info_nodes] += nodes.collect {|n| n.alcn} if node 279: end 280: node 281: end
Return the relative path to the given path other. The parameter other can be a Node or a String.
# File lib/webgen/node.rb, line 285 285: def route_to(other) 286: my_url = self.class.url(@path) 287: other_url = if other.kind_of?(Node) 288: self.class.url(other.routing_node(@lang).path) 289: elsif other.kind_of?(String) 290: my_url + other 291: else 292: raise ArgumentError, "improper class for argument" 293: end 294: 295: # resolve any '.' and '..' paths in the target url 296: if other_url.path =~ /\/\.\.?\// && other_url.scheme == 'webgen' 297: other_url.path = Pathname.new(other_url.path).cleanpath.to_s 298: end 299: route = my_url.route_to(other_url).to_s 300: (route == '' ? File.basename(self.path) : route) 301: end
Return the routing node in language lang which is the node that is used when routing to this node. The returned node can differ from the node itself in case of a directory where the routing node is the directory index node. If show_warning is true and this node is a directory node, then a warning is logged if no associated index file is found.
# File lib/webgen/node.rb, line 307 307: def routing_node(lang, log_warning = true) 308: if !is_directory? 309: self 310: else 311: key = [alcn, :index_node, lang] 312: vcache = website.cache.volatile 313: return vcache[key] if vcache.has_key?(key) 314: 315: index_path = self.meta_info['index_path'] 316: if index_path.nil? 317: vcache[key] = self 318: else 319: index_node = resolve(index_path, lang) 320: if index_node 321: vcache[key] = index_node 322: log(:info) { "Directory index path for <#{alcn}> => <#{index_node}>" } 323: elsif log_warning 324: vcache[key] = self 325: log(:warn) { "No directory index path found for directory <#{alcn}>" } 326: end 327: end 328: vcache[key] || self 329: end 330: end
Return the string representation of the node which is just the alcn.
# File lib/webgen/node.rb, line 195 195: def to_s 196: @alcn 197: end
Remove the flags keys from the node and dispatch the message :node_unflagged with self and keys as arguments.
# File lib/webgen/node.rb, line 151 151: def unflag(*keys) 152: @flags.subtract(keys) 153: website.blackboard.dispatch_msg(:node_unflagged, self, keys) 154: end
# File lib/webgen/node.rb, line 373 373: def find_nodes(opts, parent, level) 374: result = ProxyNode.new(parent, self) 375: 376: children.each do |child| 377: c_result = child.find_nodes(opts, result, level + 1) 378: result.children << c_result unless c_result.nil? 379: end if opts[:levels] && level <= opts[:levels] 380: 381: (!result.children.empty? || find_match?(opts) ? result : nil) 382: end
# File lib/webgen/node.rb, line 385 385: def find_match?(opts) 386: (!opts[:alcn] || self =~ opts[:alcn]) 387: end
Only run the code in the block if this node has not already been checked. Different checks are supported by setting a different type value.
# File lib/webgen/node.rb, line 413 413: def if_not_checked(type) 414: array = (website.cache.volatile[:node_change_checking] ||= {})[type] ||= [] 415: if !array.include?(self) 416: array << self 417: yield 418: array.delete(self) 419: end 420: end
Do the rest of the initialization.
# File lib/webgen/node.rb, line 395 395: def init_rest 396: @lcn = Path.lcn(@cn, @lang) 397: @acn = (@parent.kind_of?(Tree) ? '' : @parent.acn.sub(/#.*$/, '') + @cn) 398: @alcn = (@parent.kind_of?(Tree) ? '' : @parent.alcn.sub(/#.*$/, '') + @lcn) 399: 400: @level = 1 401: @tree = @parent 402: (@level += 1; @tree = @tree.parent) while !@tree.kind_of?(Tree) 403: 404: @tree.register_node(self) 405: @parent.children << self unless @parent == @tree 406: 407: self.node_info[:used_nodes] = Set.new 408: self.node_info[:used_meta_info_nodes] = Set.new 409: end
Delegate missing methods to a processor. The current node is placed into the argument array as the first argument before the method name is invoked on the processor.
# File lib/webgen/node.rb, line 424 424: def method_missing(name, *args, &block) 425: if node_info[:processor] 426: website.cache.instance(node_info[:processor]).send(name, *([self] + args), &block) 427: else 428: super 429: end 430: end
Return true if any node matching a pattern from the meta information used_nodes has changed.
# File lib/webgen/node.rb, line 173 173: def user_nodes_changed? 174: pattern = [@meta_info['used_nodes']].flatten.compact.collect {|pat| Webgen::Path.make_absolute(parent.alcn, pat)} 175: tree.node_access[:alcn].any? do |path, n| 176: pattern.any? {|pat| n =~ pat && n.changed?} 177: end if pattern.length > 0 178: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.