lib/nanoc/base/repos/dependency_store.rb in nanoc-4.4.0 vs lib/nanoc/base/repos/dependency_store.rb in nanoc-4.4.1
- old
+ new
@@ -1,8 +1,52 @@
module Nanoc::Int
# @api private
class DependencyStore < ::Nanoc::Int::Store
+ # A dependency between two items/layouts.
+ class Dependency
+ include Nanoc::Int::ContractsSupport
+
+ contract C::None => C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]
+ attr_reader :from
+
+ contract C::None => C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]
+ attr_reader :to
+
+ contract C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], C::KeywordArgs[raw_content: C::Optional[C::Bool], attributes: C::Optional[C::Bool], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]] => C::Any
+ def initialize(from, to, raw_content:, attributes:, compiled_content:, path:)
+ @from = from
+ @to = to
+
+ @raw_content = raw_content
+ @attributes = attributes
+ @compiled_content = compiled_content
+ @path = path
+ end
+
+ contract C::None => C::Bool
+ def raw_content?
+ @raw_content
+ end
+
+ contract C::None => C::Bool
+ def attributes?
+ @attributes
+ end
+
+ contract C::None => C::Bool
+ def compiled_content?
+ @compiled_content
+ end
+
+ contract C::None => C::Bool
+ def path?
+ @path
+ end
+ end
+
+ include Nanoc::Int::ContractsSupport
+
# @return [Array<Nanoc::Int::Item, Nanoc::Int::Layout>]
attr_accessor :objects
# @param [Array<Nanoc::Int::Item, Nanoc::Int::Layout>] objects
def initialize(objects, env_name: nil)
@@ -10,10 +54,26 @@
@objects = objects
@graph = Nanoc::Int::DirectedGraph.new([nil] + @objects)
end
+ contract C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] => C::ArrayOf[Dependency]
+ def dependencies_causing_outdatedness_of(object)
+ objects_causing_outdatedness_of(object).map do |other_object|
+ props = @graph.props_for(other_object, object) || {}
+
+ Dependency.new(
+ other_object,
+ object,
+ raw_content: props.fetch(:raw_content, false),
+ attributes: props.fetch(:attributes, false),
+ compiled_content: props.fetch(:compiled_content, false),
+ path: props.fetch(:path, false),
+ )
+ end
+ end
+
# Returns the direct dependencies for the given object.
#
# The direct dependencies of the given object include the items and
# layouts that, when outdated will cause the given object to be marked as
# outdated. Indirect dependencies will not be returned (e.g. if A depends
@@ -48,10 +108,11 @@
# the given object
def objects_outdated_due_to(object)
@graph.direct_successors_of(object).compact
end
+ contract C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], C::KeywordArgs[raw_content: C::Optional[C::Bool], attributes: C::Optional[C::Bool], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]] => C::Any
# Records a dependency from `src` to `dst` in the dependency graph. When
# `dst` is oudated, `src` will also become outdated.
#
# @param [Nanoc::Int::Item, Nanoc::Int::Layout] src The source of the dependency,
# i.e. the object that will become outdated if dst is outdated
@@ -59,13 +120,17 @@
# @param [Nanoc::Int::Item, Nanoc::Int::Layout] dst The destination of the
# dependency, i.e. the object that will cause the source to become
# outdated if the destination is outdated
#
# @return [void]
- def record_dependency(src, dst)
+ def record_dependency(src, dst, raw_content: false, attributes: false, compiled_content: false, path: false)
+ existing_props = @graph.props_for(dst, src) || {}
+ new_props = { raw_content: raw_content, attributes: attributes, compiled_content: compiled_content, path: path }
+ props = merge_props(existing_props, new_props)
+
# Warning! dst and src are *reversed* here!
- @graph.add_edge(dst, src) unless src == dst
+ @graph.add_edge(dst, src, props: props) unless src == dst
end
# Empties the list of dependencies for the given object. This is necessary
# before recompiling the given object, because otherwise old dependencies
# will stick around and new dependencies will appear twice. This function
@@ -79,10 +144,17 @@
@graph.delete_edges_to(object)
end
protected
+ def merge_props(p1, p2)
+ keys = (p1.keys + p2.keys).uniq
+ keys.each_with_object({}) do |key, memo|
+ memo[key] = p1.fetch(key, false) || p2.fetch(key, false)
+ end
+ end
+
def data
{
edges: @graph.edges,
vertices: @graph.vertices.map { |obj| obj && obj.reference },
}
@@ -97,13 +169,13 @@
@objects.find { |obj| reference == obj.reference }
end
# Load edges
new_data[:edges].each do |edge|
- from_index, to_index = *edge
+ from_index, to_index, props = *edge
from = from_index && previous_objects[from_index]
to = to_index && previous_objects[to_index]
- @graph.add_edge(from, to)
+ @graph.add_edge(from, to, props: props)
end
# Record dependency from all items on new items
new_objects = (@objects - previous_objects)
new_objects.each do |new_obj|