Skip to content

Commit

Permalink
Merge pull request #1193 from nanoc/finer-doc-collection-dependencies
Browse files Browse the repository at this point in the history
Make item/layout collection dependencies finer-grained
  • Loading branch information
denisdefreyne committed Jul 1, 2017
2 parents 29284da + 218259e commit 71584db
Show file tree
Hide file tree
Showing 12 changed files with 444 additions and 82 deletions.
25 changes: 17 additions & 8 deletions lib/nanoc/base/entities/outdatedness_reasons.rb
Expand Up @@ -46,15 +46,24 @@ def initialize(message, props = Nanoc::Int::Props.new)
Props.new(raw_content: true, compiled_content: true),
)

ItemCollectionExtended = Generic.new(
'A new item has been added to the site.',
Props.new(raw_content: true),
)
class DocumentCollectionExtended < Generic
attr_reader :objects

LayoutCollectionExtended = Generic.new(
'A new layout has been added to the site.',
Props.new(raw_content: true),
)
def initialize(objects)
super(
'New items/layouts have been added to the site.',
Props.new(raw_content: true),
)

@objects = objects
end
end

class ItemCollectionExtended < DocumentCollectionExtended
end

class LayoutCollectionExtended < DocumentCollectionExtended
end

class AttributesModified < Generic
attr_reader :attributes
Expand Down
43 changes: 33 additions & 10 deletions lib/nanoc/base/entities/props.rb
Expand Up @@ -6,11 +6,13 @@ class Props
include Nanoc::Int::ContractsSupport

attr_reader :attributes
attr_reader :raw_content

# TODO: Split raw_content for documents and collections
C_RAW_CONTENT = C::Or[C::IterOf[C::Or[String, Regexp]], C::Bool]
C_ATTRS = C::Or[C::IterOf[Symbol], C::Bool]
contract C::KeywordArgs[raw_content: C::Optional[C::Bool], attributes: C::Optional[C_ATTRS], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]] => C::Any
contract C::KeywordArgs[raw_content: C::Optional[C_RAW_CONTENT], attributes: C::Optional[C_ATTRS], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]] => C::Any
def initialize(raw_content: false, attributes: false, compiled_content: false, path: false)
@raw_content = raw_content
@compiled_content = compiled_content
@path = path

Expand All @@ -21,6 +23,14 @@ def initialize(raw_content: false, attributes: false, compiled_content: false, p
else
attributes
end

@raw_content =
case raw_content
when Enumerable
Set.new(raw_content)
else
raw_content
end
end

contract C::None => String
Expand All @@ -37,7 +47,12 @@ def inspect

contract C::None => C::Bool
def raw_content?
@raw_content
case @raw_content
when Enumerable
@raw_content.any?
else
@raw_content
end
end

contract C::None => C::Bool
Expand All @@ -63,27 +78,35 @@ def path?
contract Nanoc::Int::Props => Nanoc::Int::Props
def merge(other)
Props.new(
raw_content: raw_content? || other.raw_content?,
raw_content: merge_raw_content(other),
attributes: merge_attributes(other),
compiled_content: compiled_content? || other.compiled_content?,
path: path? || other.path?,
)
end

def merge_raw_content(other)
merge_prop(raw_content, other.raw_content)
end

def merge_attributes(other)
case attributes
merge_prop(attributes, other.attributes)
end

def merge_prop(own, other)
case own
when true
true
when false
other.attributes
other
else
case other.attributes
case other
when true
true
when false
attributes
own
else
attributes + other.attributes
own + other
end
end
end
Expand All @@ -101,7 +124,7 @@ def active
contract C::None => Hash
def to_h
{
raw_content: raw_content?,
raw_content: raw_content,
attributes: attributes,
compiled_content: compiled_content?,
path: path?,
Expand Down
13 changes: 9 additions & 4 deletions lib/nanoc/base/repos/dependency_store.rb
Expand Up @@ -59,9 +59,12 @@ def layouts=(layouts)
add_vertex_for(layouts)
end

contract C::None => C::Bool
def any_new_objects?
@new_objects.any?
def new_items
@new_objects.select { |o| o.is_a?(Nanoc::Int::Item) }
end

def new_layouts
@new_objects.select { |o| o.is_a?(Nanoc::Int::Layout) }
end

# Returns the direct dependencies for the given object.
Expand All @@ -85,8 +88,10 @@ def objects_causing_outdatedness_of(object)
refs2objs(@graph.direct_predecessors_of(obj2ref(object)))
end

C_RAW_CONTENT = C::Or[C::IterOf[C::Or[String, Regexp]], C::Bool]
C_ATTR = C::Or[C::IterOf[Symbol], C::Bool]
C_KEYWORD_PROPS = C::KeywordArgs[raw_content: C::Optional[C::Bool], attributes: C::Optional[C_ATTR], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]]
C_KEYWORD_PROPS = C::KeywordArgs[raw_content: C::Optional[C_RAW_CONTENT], attributes: C::Optional[C_ATTR], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]]

contract C::Maybe[C_OBJ_SRC], C::Maybe[C_OBJ_DST], C_KEYWORD_PROPS => C::Any
# Records a dependency from `src` to `dst` in the dependency graph. When
# `dst` is oudated, `src` will also become outdated.
Expand Down
3 changes: 2 additions & 1 deletion lib/nanoc/base/services/dependency_tracker.rb
Expand Up @@ -6,8 +6,9 @@ class DependencyTracker
include Nanoc::Int::ContractsSupport

C_OBJ = C::Or[Nanoc::Int::Item, Nanoc::Int::Layout, Nanoc::Int::Configuration, Nanoc::Int::IdentifiableCollection]
C_RAW_CONTENT = C::Or[C::IterOf[C::Or[String, Regexp]], C::Bool]
C_ATTR = C::Or[C::IterOf[Symbol], C::Bool]
C_ARGS = C::KeywordArgs[raw_content: C::Optional[C::Bool], attributes: C::Optional[C_ATTR], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]]
C_ARGS = C::KeywordArgs[raw_content: C::Optional[C_RAW_CONTENT], attributes: C::Optional[C_ATTR], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]]

class Null
include Nanoc::Int::ContractsSupport
Expand Down
22 changes: 15 additions & 7 deletions lib/nanoc/base/services/outdatedness_checker.rb
Expand Up @@ -191,19 +191,27 @@ def dependency_causes_outdatedness?(dependency)
status = basic.outdatedness_status_for(dependency.from)

active = status.props.active & dependency.props.active
if attributes_unaffected?(status, dependency)
active.delete(:attributes)
end
active.delete(:attributes) if attributes_unaffected?(status, dependency)
active.delete(:raw_content) if raw_content_unaffected?(status, dependency)

active.any?
end

def attributes_unaffected?(status, dependency)
attr_reason = status.reasons.find do |r|
r.is_a?(Nanoc::Int::OutdatednessReasons::AttributesModified)
end
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

attr_reason && dependency.props.attributes.is_a?(Enumerable) && (dependency.props.attributes & attr_reason.attributes).empty?
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) } }
end
end
end
end
Expand Up @@ -6,8 +6,10 @@ class ItemCollectionExtended < Nanoc::Int::OutdatednessRule

contract Nanoc::Int::ItemCollection, C::Named['Nanoc::Int::OutdatednessChecker'] => C::Maybe[Nanoc::Int::OutdatednessReasons::Generic]
def apply(_obj, outdatedness_checker)
if outdatedness_checker.dependency_store.any_new_objects?
Nanoc::Int::OutdatednessReasons::ItemCollectionExtended
new_items = outdatedness_checker.dependency_store.new_items

if new_items.any?
Nanoc::Int::OutdatednessReasons::ItemCollectionExtended.new(new_items)
end
end
end
Expand Down
Expand Up @@ -6,8 +6,10 @@ class LayoutCollectionExtended < Nanoc::Int::OutdatednessRule

contract Nanoc::Int::LayoutCollection, C::Named['Nanoc::Int::OutdatednessChecker'] => C::Maybe[Nanoc::Int::OutdatednessReasons::Generic]
def apply(_obj, outdatedness_checker)
if outdatedness_checker.dependency_store.any_new_objects?
Nanoc::Int::OutdatednessReasons::LayoutCollectionExtended
new_layouts = outdatedness_checker.dependency_store.new_layouts

if new_layouts.any?
Nanoc::Int::OutdatednessReasons::LayoutCollectionExtended.new(new_layouts)
end
end
end
Expand Down
24 changes: 22 additions & 2 deletions lib/nanoc/base/views/identifiable_collection_view.rb
Expand Up @@ -47,7 +47,17 @@ def size
#
# @return [Enumerable]
def find_all(arg)
@context.dependency_tracker.bounce(unwrap, raw_content: true)
prop_attribute =
case arg
when String, Nanoc::Identifier
[arg.to_s]
when Regexp
[arg]
else
true
end

@context.dependency_tracker.bounce(unwrap, raw_content: prop_attribute)
@objects.find_all(arg).map { |i| view_class.new(i, @context) }
end

Expand All @@ -74,7 +84,17 @@ def find_all(arg)
#
# @return [#identifier] if an object was found
def [](arg)
@context.dependency_tracker.bounce(unwrap, raw_content: true)
prop_attribute =
case arg
when String, Nanoc::Identifier
[arg.to_s]
when Regexp
[arg]
else
true
end

@context.dependency_tracker.bounce(unwrap, raw_content: prop_attribute)
res = @objects[arg]
res && view_class.new(res, @context)
end
Expand Down

0 comments on commit 71584db

Please sign in to comment.