# -*- encoding: utf-8 -*- require 'webgen/item_tracker' module Webgen class ItemTracker # This class is used to track changes to a (nested) list of nodes. # # An item for this tracker has to consist of the following fields: # # * An array consisting of [class/module name, method name] or a string/symbol specifying a # method name # * Options argument (use an array or hash for multiple arguments) # * Either :content or :meta_info, depending on whether the content or the meta info of # the found nodes should be tracked. # # The list of nodes is retrieved in one of two ways, depending on the type of the first field: # # * If it is a string/symbol, it specifies the name of a method on this class. This method has # to take the options hash as the only parameter. # # * If it is an array, the array has to contain a class/module name and a method name. The # method is invoked with the current Webgen::Website object as first and the options hash as # second parameter. # # For example, consider the following statement: # # website.ext.item_tracker.add(some_node, :nodes, # ["MyModule::MyClass", "my_method"], {:some => 'options'}, :content) # # The method will be invoked like this for retrieving the nodes: # # MyModule::MyClass.my_method(website, {:some => 'options'}) # class Nodes def initialize(website) #:nodoc: @website = website end def item_id(method_name, options, type) #:nodoc: [method_name, options, type] end def item_data(method_name, options, type) #:nodoc: nodes_to_alcn(node_list(method_name, options)) end def item_changed?(iid, old_data) #:nodoc: method_name, options, type = *iid nodes = node_list(method_name, options) old_data != nodes_to_alcn(nodes) || nodes.flatten.any? {|n| type == :content ? @website.ext.item_tracker.node_changed?(n) : @website.ext.item_tracker.item_changed?(:node_meta_info, n)} end def referenced_nodes(iid, alcn_list) #:nodoc: alcn_list.flatten end def item_description(iid, data) #:nodoc: method, _, type = *iid str = (type == :content ? "Content" : "Meta info") << " from these nodes" str << " (result of #{[method].flatten.join('.')}):" data_mapper = lambda do |item| if item.kind_of?(Array) [item[0], item[1].map(&data_mapper).map {|inner| [inner].flatten.map {|l| " #{l}"}}] else item end end [str] + data.map(&data_mapper).flatten end # Use Webgen::NodeFinder to generate a (nested) list of nodes. The options hash has to contain # two keys: # # * :opts → the node finder option set # * :ref_alcn → the alcn of the reference node # def node_finder_option_set(options) @website.ext.node_finder.find(options[:opts], @website.tree[options[:ref_alcn]]) end # Return the list of nodes. def node_list(method_name, options) if method_name.kind_of?(Array) Webgen::Utils.const_for_name(method_name.first).send(method_name.last, @website, options) else send(method_name, options) end rescue Exception [] end private :node_list # Map the (nested) list of nodes to a (nested) list of alcn. def nodes_to_alcn(nodes) #:nodoc: nodes.map {|node, children| children.nil? ? node.alcn : [node.alcn, nodes_to_alcn(children)]} end private :nodes_to_alcn end end end