lib/nanoc/base/services/outdatedness_checker.rb in nanoc-4.11.0 vs lib/nanoc/base/services/outdatedness_checker.rb in nanoc-4.11.1

- old
+ new

@@ -1,217 +1,219 @@ # frozen_string_literal: true -module Nanoc::Int - # Responsible for determining whether an item or a layout is outdated. - # - # @api private - class OutdatednessChecker - class Basic - DDMemoize.activate(self) +module Nanoc + module Int + # Responsible for determining whether an item or a layout is outdated. + # + # @api private + class OutdatednessChecker + class Basic + DDMemoize.activate(self) - include Nanoc::Int::ContractsSupport + include Nanoc::Core::ContractsSupport - Rules = Nanoc::Int::OutdatednessRules + Rules = Nanoc::Int::OutdatednessRules - RULES_FOR_ITEM_REP = - [ - Rules::RulesModified, - Rules::ContentModified, - Rules::AttributesModified, - Rules::NotWritten, - Rules::CodeSnippetsModified, - Rules::UsesAlwaysOutdatedFilter, - ].freeze + RULES_FOR_ITEM_REP = + [ + Rules::RulesModified, + Rules::ContentModified, + Rules::AttributesModified, + Rules::NotWritten, + Rules::CodeSnippetsModified, + Rules::UsesAlwaysOutdatedFilter, + ].freeze - RULES_FOR_LAYOUT = - [ - Rules::RulesModified, - Rules::ContentModified, - Rules::AttributesModified, - Rules::UsesAlwaysOutdatedFilter, - ].freeze + RULES_FOR_LAYOUT = + [ + Rules::RulesModified, + Rules::ContentModified, + Rules::AttributesModified, + Rules::UsesAlwaysOutdatedFilter, + ].freeze - RULES_FOR_CONFIG = - [ - Rules::AttributesModified, - ].freeze + RULES_FOR_CONFIG = + [ + Rules::AttributesModified, + ].freeze - RULES_FOR_ITEM_COLLECTION = - [ - Rules::ItemCollectionExtended, - ].freeze + RULES_FOR_ITEM_COLLECTION = + [ + Rules::ItemCollectionExtended, + ].freeze - RULES_FOR_LAYOUT_COLLECTION = - [ - Rules::LayoutCollectionExtended, - ].freeze + RULES_FOR_LAYOUT_COLLECTION = + [ + Rules::LayoutCollectionExtended, + ].freeze - C_OBJ_MAYBE_REP = C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Configuration, Nanoc::Int::Layout, Nanoc::Int::ItemCollection, Nanoc::Int::LayoutCollection] + C_OBJ_MAYBE_REP = C::Or[Nanoc::Core::Item, Nanoc::Core::ItemRep, Nanoc::Core::Configuration, Nanoc::Core::Layout, Nanoc::Core::ItemCollection, Nanoc::Core::LayoutCollection] - contract C::KeywordArgs[outdatedness_checker: OutdatednessChecker, reps: Nanoc::Int::ItemRepRepo] => C::Any - def initialize(outdatedness_checker:, reps:) - @outdatedness_checker = outdatedness_checker - @reps = reps - end + contract C::KeywordArgs[outdatedness_checker: OutdatednessChecker, reps: Nanoc::Int::ItemRepRepo] => C::Any + def initialize(outdatedness_checker:, reps:) + @outdatedness_checker = outdatedness_checker + @reps = reps + end - contract C_OBJ_MAYBE_REP => C::Maybe[OutdatednessStatus] - memoized def outdatedness_status_for(obj) - case obj - when Nanoc::Int::ItemRep - apply_rules(RULES_FOR_ITEM_REP, obj) - when Nanoc::Int::Item - apply_rules_multi(RULES_FOR_ITEM_REP, @reps[obj]) - when Nanoc::Int::Layout - apply_rules(RULES_FOR_LAYOUT, obj) - when Nanoc::Int::Configuration - apply_rules(RULES_FOR_CONFIG, obj) - when Nanoc::Int::ItemCollection - apply_rules(RULES_FOR_ITEM_COLLECTION, obj) - when Nanoc::Int::LayoutCollection - apply_rules(RULES_FOR_LAYOUT_COLLECTION, obj) - else - raise Nanoc::Int::Errors::InternalInconsistency, "do not know how to check outdatedness of #{obj.inspect}" + contract C_OBJ_MAYBE_REP => C::Maybe[OutdatednessStatus] + memoized def outdatedness_status_for(obj) + case obj + when Nanoc::Core::ItemRep + apply_rules(RULES_FOR_ITEM_REP, obj) + when Nanoc::Core::Item + apply_rules_multi(RULES_FOR_ITEM_REP, @reps[obj]) + when Nanoc::Core::Layout + apply_rules(RULES_FOR_LAYOUT, obj) + when Nanoc::Core::Configuration + apply_rules(RULES_FOR_CONFIG, obj) + when Nanoc::Core::ItemCollection + apply_rules(RULES_FOR_ITEM_COLLECTION, obj) + when Nanoc::Core::LayoutCollection + apply_rules(RULES_FOR_LAYOUT_COLLECTION, obj) + else + raise Nanoc::Int::Errors::InternalInconsistency, "do not know how to check outdatedness of #{obj.inspect}" + end end - end - private + private - contract C::ArrayOf[Class], C_OBJ_MAYBE_REP, OutdatednessStatus => C::Maybe[OutdatednessStatus] - def apply_rules(rules, obj, status = OutdatednessStatus.new) - rules.inject(status) do |acc, rule| - if !acc.useful_to_apply?(rule) - acc - else - reason = rule.instance.call(obj, @outdatedness_checker) - if reason - acc.update(reason) - else + contract C::ArrayOf[Class], C_OBJ_MAYBE_REP, OutdatednessStatus => C::Maybe[OutdatednessStatus] + def apply_rules(rules, obj, status = OutdatednessStatus.new) + rules.inject(status) do |acc, rule| + if !acc.useful_to_apply?(rule) acc + else + reason = rule.instance.call(obj, @outdatedness_checker) + if reason + acc.update(reason) + else + acc + end end end end - end - contract C::ArrayOf[Class], C::ArrayOf[C_OBJ_MAYBE_REP] => C::Maybe[OutdatednessStatus] - def apply_rules_multi(rules, objs) - objs.inject(OutdatednessStatus.new) { |acc, elem| apply_rules(rules, elem, acc) } + contract C::ArrayOf[Class], C::ArrayOf[C_OBJ_MAYBE_REP] => C::Maybe[OutdatednessStatus] + def apply_rules_multi(rules, objs) + objs.inject(OutdatednessStatus.new) { |acc, elem| apply_rules(rules, elem, acc) } + end end - end - DDMemoize.activate(self) + DDMemoize.activate(self) - include Nanoc::Int::ContractsSupport + include Nanoc::Core::ContractsSupport - attr_reader :checksum_store - attr_reader :checksums - attr_reader :dependency_store - attr_reader :action_sequence_store - attr_reader :action_sequences - attr_reader :site + attr_reader :checksum_store + attr_reader :checksums + attr_reader :dependency_store + attr_reader :action_sequence_store + attr_reader :action_sequences + attr_reader :site - Reasons = Nanoc::Int::OutdatednessReasons + Reasons = Nanoc::Int::OutdatednessReasons - C_OBJ = C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Configuration, Nanoc::Int::Layout, Nanoc::Int::ItemCollection] - C_ITEM_OR_REP = C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep] - C_ACTION_SEQUENCES = C::HashOf[C_OBJ => Nanoc::Int::ActionSequence] + C_OBJ = C::Or[Nanoc::Core::Item, Nanoc::Core::ItemRep, Nanoc::Core::Configuration, Nanoc::Core::Layout, Nanoc::Core::ItemCollection] + C_ITEM_OR_REP = C::Or[Nanoc::Core::Item, Nanoc::Core::ItemRep] + C_ACTION_SEQUENCES = C::HashOf[C_OBJ => Nanoc::Int::ActionSequence] - contract C::KeywordArgs[site: Nanoc::Int::Site, checksum_store: Nanoc::Int::ChecksumStore, checksums: Nanoc::Int::ChecksumCollection, dependency_store: Nanoc::Int::DependencyStore, action_sequence_store: Nanoc::Int::ActionSequenceStore, action_sequences: C_ACTION_SEQUENCES, reps: Nanoc::Int::ItemRepRepo] => C::Any - def initialize(site:, checksum_store:, checksums:, dependency_store:, action_sequence_store:, action_sequences:, reps:) - @site = site - @checksum_store = checksum_store - @checksums = checksums - @dependency_store = dependency_store - @action_sequence_store = action_sequence_store - @action_sequences = action_sequences - @reps = reps + contract C::KeywordArgs[site: Nanoc::Int::Site, checksum_store: Nanoc::Int::ChecksumStore, checksums: Nanoc::Int::ChecksumCollection, dependency_store: Nanoc::Int::DependencyStore, action_sequence_store: Nanoc::Int::ActionSequenceStore, action_sequences: C_ACTION_SEQUENCES, reps: Nanoc::Int::ItemRepRepo] => C::Any + def initialize(site:, checksum_store:, checksums:, dependency_store:, action_sequence_store:, action_sequences:, reps:) + @site = site + @checksum_store = checksum_store + @checksums = checksums + @dependency_store = dependency_store + @action_sequence_store = action_sequence_store + @action_sequences = action_sequences + @reps = reps - @objects_outdated_due_to_dependencies = {} - end + @objects_outdated_due_to_dependencies = {} + end - def action_sequence_for(rep) - @action_sequences.fetch(rep) - end + def action_sequence_for(rep) + @action_sequences.fetch(rep) + end - contract C_OBJ => C::Bool - def outdated?(obj) - outdatedness_reasons_for(obj).any? - end + contract C_OBJ => C::Bool + def outdated?(obj) + outdatedness_reasons_for(obj).any? + end - contract C_OBJ => C::IterOf[Reasons::Generic] - def outdatedness_reasons_for(obj) - reasons = basic.outdatedness_status_for(obj).reasons - if reasons.any? - reasons - elsif outdated_due_to_dependencies?(obj) - [Reasons::DependenciesOutdated] - else - [] + contract C_OBJ => C::IterOf[Reasons::Generic] + def outdatedness_reasons_for(obj) + reasons = basic.outdatedness_status_for(obj).reasons + if reasons.any? + reasons + elsif outdated_due_to_dependencies?(obj) + [Reasons::DependenciesOutdated] + else + [] + end end - end - private + private - contract C::None => Basic - def basic - @_basic ||= Basic.new(outdatedness_checker: self, reps: @reps) - end + contract C::None => Basic + def basic + @_basic ||= Basic.new(outdatedness_checker: self, reps: @reps) + end - contract C_ITEM_OR_REP, Hamster::Set => C::Bool - def outdated_due_to_dependencies?(obj, processed = Hamster::Set.new) - # Convert from rep to item if necessary - obj = obj.item if obj.is_a?(Nanoc::Int::ItemRep) + contract C_ITEM_OR_REP, Hamster::Set => C::Bool + def outdated_due_to_dependencies?(obj, processed = Hamster::Set.new) + # Convert from rep to item if necessary + obj = obj.item if obj.is_a?(Nanoc::Core::ItemRep) - # Get from cache - if @objects_outdated_due_to_dependencies.key?(obj) - return @objects_outdated_due_to_dependencies[obj] - end + # Get from cache + if @objects_outdated_due_to_dependencies.key?(obj) + return @objects_outdated_due_to_dependencies[obj] + end - # Check processed - # Don’t return true; the false will be or’ed into a true if there - # really is a dependency that is causing outdatedness. - return false if processed.include?(obj) + # Check processed + # Don’t return true; the false will be or’ed into a true if there + # really is a dependency that is causing outdatedness. + return false if processed.include?(obj) - # Calculate - is_outdated = dependency_store.dependencies_causing_outdatedness_of(obj).any? do |dep| - dependency_causes_outdatedness?(dep) || - (dep.props.compiled_content? && - outdated_due_to_dependencies?(dep.from, processed.merge([obj]))) - end + # Calculate + is_outdated = dependency_store.dependencies_causing_outdatedness_of(obj).any? do |dep| + dependency_causes_outdatedness?(dep) || + (dep.props.compiled_content? && + outdated_due_to_dependencies?(dep.from, processed.merge([obj]))) + end - # Cache - @objects_outdated_due_to_dependencies[obj] = is_outdated + # Cache + @objects_outdated_due_to_dependencies[obj] = is_outdated - # Done - is_outdated - end + # Done + is_outdated + end - contract Nanoc::Int::Dependency => C::Bool - def dependency_causes_outdatedness?(dependency) - return true if dependency.from.nil? + contract Nanoc::Int::Dependency => C::Bool + def dependency_causes_outdatedness?(dependency) + return true if dependency.from.nil? - status = basic.outdatedness_status_for(dependency.from) + status = basic.outdatedness_status_for(dependency.from) - active = status.props.active & dependency.props.active - active.delete(:attributes) if attributes_unaffected?(status, dependency) - active.delete(:raw_content) if raw_content_unaffected?(status, dependency) + active = status.props.active & dependency.props.active + active.delete(:attributes) if attributes_unaffected?(status, dependency) + active.delete(:raw_content) if raw_content_unaffected?(status, dependency) - active.any? - end + active.any? + end - def attributes_unaffected?(status, dependency) - reason = status.reasons.find { |r| r.is_a?(Nanoc::Int::OutdatednessReasons::AttributesModified) } - reason && dependency.props.attributes.is_a?(Enumerable) && (dependency.props.attributes & reason.attributes).empty? - end + def attributes_unaffected?(status, dependency) + reason = status.reasons.find { |r| r.is_a?(Nanoc::Int::OutdatednessReasons::AttributesModified) } + reason && dependency.props.attributes.is_a?(Enumerable) && (dependency.props.attributes & reason.attributes).empty? + end - def raw_content_unaffected?(status, dependency) - reason = status.reasons.find { |r| r.is_a?(Nanoc::Int::OutdatednessReasons::DocumentCollectionExtended) } - if reason.nil? - false - elsif !dependency.props.raw_content.is_a?(Enumerable) - false - else - patterns = dependency.props.raw_content.map { |r| Nanoc::Int::Pattern.from(r) } - patterns.none? { |pat| reason.objects.any? { |obj| pat.match?(obj.identifier) } } + def raw_content_unaffected?(status, dependency) + reason = status.reasons.find { |r| r.is_a?(Nanoc::Int::OutdatednessReasons::DocumentCollectionExtended) } + if reason.nil? + false + elsif !dependency.props.raw_content.is_a?(Enumerable) + false + else + patterns = dependency.props.raw_content.map { |r| Nanoc::Core::Pattern.from(r) } + patterns.none? { |pat| reason.objects.any? { |obj| pat.match?(obj.identifier) } } + end end end end end