module Nanoc::RuleDSL # Calculates rule memories for objects that can be run through a rule (item # representations and layouts). # # @api private class RuleMemoryCalculator extend Nanoc::Int::Memoization class UnsupportedObjectTypeException < ::Nanoc::Error def initialize(obj) super("Do not know how to calculate the rule memory for #{obj.inspect}") end end class NoRuleMemoryForLayoutException < ::Nanoc::Error def initialize(layout) super("There is no layout rule specified for #{layout.inspect}") end end class NoRuleMemoryForItemRepException < ::Nanoc::Error def initialize(item) super("There is no compilation rule specified for #{item.inspect}") end end # @api private attr_accessor :rules_collection # @param [Nanoc::Int::Site] site # @param [Nanoc::RuleDSL::RulesCollection] rules_collection def initialize(site:, rules_collection:) @site = site @rules_collection = rules_collection end # @param [#reference] obj # # @return [Nanoc::Int::RuleMemory] def [](obj) case obj when Nanoc::Int::ItemRep new_rule_memory_for_rep(obj) when Nanoc::Int::Layout new_rule_memory_for_layout(obj) else raise UnsupportedObjectTypeException.new(obj) end end memoize :[] # @param [Nanoc::Int::ItemRep] rep The item representation for which to fetch # the list of snapshots # # @return [Array] A list of snapshots, represented as arrays where the # first element is the snapshot name (a Symbol) and the last element is # a Boolean indicating whether the snapshot is final or not def snapshots_defs_for(rep) self[rep].snapshot_actions.map do |a| Nanoc::Int::SnapshotDef.new(a.snapshot_name, a.final?) end end # @param [Nanoc::Int::ItemRep] rep The item representation to get the rule # memory for # # @return [Nanoc::Int::RuleMemory] def new_rule_memory_for_rep(rep) dependency_tracker = Nanoc::Int::DependencyTracker::Null.new view_context = @site.compiler.create_view_context(dependency_tracker) executor = Nanoc::RuleDSL::RecordingExecutor.new(rep, @rules_collection, @site) rule = @rules_collection.compilation_rule_for(rep) unless rule raise NoRuleMemoryForItemRepException.new(rep) end executor.snapshot(rep, :raw) executor.snapshot(rep, :pre, final: false) rule.apply_to(rep, executor: executor, site: @site, view_context: view_context) if executor.rule_memory.any_layouts? executor.snapshot(rep, :post) end unless executor.rule_memory.snapshot_actions.any? { |sa| sa.snapshot_name == :last } executor.snapshot(rep, :last) end executor.rule_memory end # @param [Nanoc::Int::ItemRep] rep The item representation to get the rule # memory for # # @return [Hash] Pairs of snapshot name and path def paths_for_rep(rep) snapshot_actions = new_rule_memory_for_rep(rep).snapshot_actions snapshot_actions.each_with_object({}) do |action, paths| paths[action.snapshot_name] = action.path end end # @param [Nanoc::Int::Layout] layout # # @return [Nanoc::Int::RuleMemory] def new_rule_memory_for_layout(layout) res = @rules_collection.filter_for_layout(layout) unless res raise NoRuleMemoryForLayoutException.new(layout) end Nanoc::Int::RuleMemory.new(layout).tap do |rm| rm.add_filter(res[0], res[1]) end end end end