nanoc-core 4.12.8 → 4.12.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/nanoc/core/checksum_collection.rb +3 -1
- data/lib/nanoc/core/checksum_store.rb +11 -1
- data/lib/nanoc/core/checksummer.rb +11 -3
- data/lib/nanoc/core/contracts_support.rb +2 -2
- data/lib/nanoc/core/dependency_props.rb +65 -9
- data/lib/nanoc/core/dependency_store.rb +59 -23
- data/lib/nanoc/core/dependency_tracker.rb +3 -2
- data/lib/nanoc/core/document.rb +5 -1
- data/lib/nanoc/core/feature.rb +2 -0
- data/lib/nanoc/core/identifiable_collection_view.rb +28 -0
- data/lib/nanoc/core/item.rb +1 -1
- data/lib/nanoc/core/layout.rb +1 -1
- data/lib/nanoc/core/mutable_document_view_mixin.rb +16 -7
- data/lib/nanoc/core/outdatedness_checker.rb +99 -31
- data/lib/nanoc/core/outdatedness_reasons.rb +9 -19
- data/lib/nanoc/core/outdatedness_rule.rb +31 -3
- data/lib/nanoc/core/outdatedness_rules/item_added.rb +18 -0
- data/lib/nanoc/core/outdatedness_rules/layout_added.rb +18 -0
- data/lib/nanoc/core/outdatedness_status.rb +10 -1
- data/lib/nanoc/core/version.rb +1 -1
- metadata +5 -5
- data/lib/nanoc/core/outdatedness_rules/item_collection_extended.rb +0 -20
- data/lib/nanoc/core/outdatedness_rules/layout_collection_extended.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3365fa09f4ff20a16df20f260562fca8c64342098ba70b4547dc38580204ea2e
|
4
|
+
data.tar.gz: 132a480e5593d19bb6c1802f6f740e3ed1d081eb88f0178fbde311d9a4e52cc0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c0190dbbad1225882d5b76891e80f45cf5e02238c6f6418071d9e8968e82cdd0263099eb5a71963b179238fb57a86f53ef7f7677592299c61cc6197be6b5dd9
|
7
|
+
data.tar.gz: 13424fbb1cc81c95e471a8ba99f172d24b6f33b1e9220a50773ed32554f5577622db7d63825734b04254e33c624b2d382b16ced1628952f5cee7e6429d96e57a
|
@@ -9,6 +9,8 @@ module Nanoc
|
|
9
9
|
|
10
10
|
def initialize(checksums)
|
11
11
|
@checksums = checksums
|
12
|
+
|
13
|
+
@_attribute_checksums = {}
|
12
14
|
end
|
13
15
|
|
14
16
|
contract c_obj => C::Maybe[String]
|
@@ -23,7 +25,7 @@ module Nanoc
|
|
23
25
|
|
24
26
|
contract c_obj => C::Maybe[C::HashOf[Symbol, String]]
|
25
27
|
def attributes_checksum_for(obj)
|
26
|
-
@checksums[[obj.reference, :each_attribute]]
|
28
|
+
@_attribute_checksums[obj] ||= @checksums[[obj.reference, :each_attribute]]
|
27
29
|
end
|
28
30
|
|
29
31
|
def to_h
|
@@ -21,6 +21,8 @@ module Nanoc
|
|
21
21
|
@objects = objects
|
22
22
|
|
23
23
|
@checksums = {}
|
24
|
+
|
25
|
+
invalidate_memoization
|
24
26
|
end
|
25
27
|
|
26
28
|
contract c_obj => C::Maybe[String]
|
@@ -50,7 +52,7 @@ module Nanoc
|
|
50
52
|
|
51
53
|
contract c_obj => C::Maybe[C::HashOf[Symbol, String]]
|
52
54
|
def attributes_checksum_for(obj)
|
53
|
-
@checksums[[obj.reference, :each_attribute]]
|
55
|
+
@_attribute_checksums[obj] ||= @checksums[[obj.reference, :each_attribute]]
|
54
56
|
end
|
55
57
|
|
56
58
|
protected
|
@@ -60,6 +62,8 @@ module Nanoc
|
|
60
62
|
end
|
61
63
|
|
62
64
|
def data=(new_data)
|
65
|
+
invalidate_memoization
|
66
|
+
|
63
67
|
references = Set.new(@objects.map(&:reference))
|
64
68
|
|
65
69
|
@checksums = {}
|
@@ -69,6 +73,12 @@ module Nanoc
|
|
69
73
|
end
|
70
74
|
end
|
71
75
|
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def invalidate_memoization
|
80
|
+
@_attribute_checksums = {}
|
81
|
+
end
|
72
82
|
end
|
73
83
|
end
|
74
84
|
end
|
@@ -81,7 +81,8 @@ module Nanoc
|
|
81
81
|
# NOTE: Other behaviors are registered elsewhere
|
82
82
|
# (search for `define_behavior`).
|
83
83
|
|
84
|
-
define_behavior(Array,
|
84
|
+
define_behavior(Array, CollectionUpdateBehavior)
|
85
|
+
define_behavior(Set, SetUpdateBehavior)
|
85
86
|
define_behavior(FalseClass, NoUpdateBehavior)
|
86
87
|
define_behavior(Hash, HashUpdateBehavior)
|
87
88
|
define_behavior(NilClass, NoUpdateBehavior)
|
@@ -96,7 +97,7 @@ module Nanoc
|
|
96
97
|
define_behavior(Nanoc::Core::Configuration, HashUpdateBehavior)
|
97
98
|
define_behavior(Nanoc::Core::Context, ContextUpdateBehavior)
|
98
99
|
define_behavior(Nanoc::Core::CodeSnippet, DataUpdateBehavior)
|
99
|
-
define_behavior(Nanoc::Core::IdentifiableCollection,
|
100
|
+
define_behavior(Nanoc::Core::IdentifiableCollection, CollectionUpdateBehavior)
|
100
101
|
define_behavior(Nanoc::Core::Identifier, ToSUpdateBehavior)
|
101
102
|
define_behavior(Nanoc::Core::Item, DocumentUpdateBehavior)
|
102
103
|
define_behavior(Nanoc::Core::ItemRep, ItemRepUpdateBehavior)
|
@@ -194,7 +195,7 @@ module Nanoc
|
|
194
195
|
end
|
195
196
|
end
|
196
197
|
|
197
|
-
class
|
198
|
+
class CollectionUpdateBehavior < UpdateBehavior
|
198
199
|
def self.update(obj, digest)
|
199
200
|
obj.each do |el|
|
200
201
|
yield(el)
|
@@ -203,6 +204,13 @@ module Nanoc
|
|
203
204
|
end
|
204
205
|
end
|
205
206
|
|
207
|
+
class SetUpdateBehavior < CollectionUpdateBehavior
|
208
|
+
def self.update(obj, digest)
|
209
|
+
# Similar to CollectionUpdateBehavior, but sorted for consistency.
|
210
|
+
super(obj.sort { |a, b| (a <=> b) || 0 }, digest)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
206
214
|
class HashUpdateBehavior < UpdateBehavior
|
207
215
|
def self.update(obj, digest)
|
208
216
|
obj.each do |key, value|
|
@@ -25,6 +25,7 @@ module Nanoc
|
|
25
25
|
Maybe = Ignorer.instance
|
26
26
|
None = Ignorer.instance
|
27
27
|
ArrayOf = Ignorer.instance
|
28
|
+
SetOf = Ignorer.instance
|
28
29
|
Or = Ignorer.instance
|
29
30
|
Func = Ignorer.instance
|
30
31
|
RespondTo = Ignorer.instance
|
@@ -96,8 +97,7 @@ module Nanoc
|
|
96
97
|
false
|
97
98
|
end
|
98
99
|
|
99
|
-
|
100
|
-
@_contracts_support__should_enable = contracts_loadable && !RUBY_VERSION.start_with?('3') && !ENV.key?('DISABLE_CONTRACTS')
|
100
|
+
@_contracts_support__should_enable = contracts_loadable && !ENV.key?('DISABLE_CONTRACTS')
|
101
101
|
|
102
102
|
if @_contracts_support__should_enable
|
103
103
|
# FIXME: ugly
|
@@ -10,9 +10,39 @@ module Nanoc
|
|
10
10
|
attr_reader :raw_content
|
11
11
|
|
12
12
|
# TODO: Split raw_content for documents and collections
|
13
|
-
C_RAW_CONTENT =
|
14
|
-
|
15
|
-
|
13
|
+
C_RAW_CONTENT =
|
14
|
+
C::Or[
|
15
|
+
C::SetOf[C::Or[String, Regexp]],
|
16
|
+
C::ArrayOf[C::Or[String, Regexp]],
|
17
|
+
C::Bool
|
18
|
+
]
|
19
|
+
|
20
|
+
C_ATTR =
|
21
|
+
C::Or[
|
22
|
+
C::SetOf[
|
23
|
+
C::Or[
|
24
|
+
Symbol, # any value
|
25
|
+
[Symbol, C::Any] # pair (specific value)
|
26
|
+
],
|
27
|
+
],
|
28
|
+
C::ArrayOf[
|
29
|
+
C::Or[
|
30
|
+
Symbol, # any value
|
31
|
+
[Symbol, C::Any] # pair (specific value)
|
32
|
+
],
|
33
|
+
],
|
34
|
+
C::Bool
|
35
|
+
]
|
36
|
+
|
37
|
+
C_ARGS =
|
38
|
+
C::KeywordArgs[
|
39
|
+
raw_content: C::Optional[C_RAW_CONTENT],
|
40
|
+
attributes: C::Optional[C_ATTR],
|
41
|
+
compiled_content: C::Optional[C::Bool],
|
42
|
+
path: C::Optional[C::Bool]
|
43
|
+
]
|
44
|
+
|
45
|
+
contract C_ARGS => C::Any
|
16
46
|
def initialize(raw_content: false, attributes: false, compiled_content: false, path: false)
|
17
47
|
@compiled_content = compiled_content
|
18
48
|
@path = path
|
@@ -21,7 +51,7 @@ module Nanoc
|
|
21
51
|
case attributes
|
22
52
|
when Set
|
23
53
|
attributes
|
24
|
-
when
|
54
|
+
when Array
|
25
55
|
Set.new(attributes)
|
26
56
|
else
|
27
57
|
attributes
|
@@ -31,7 +61,7 @@ module Nanoc
|
|
31
61
|
case raw_content
|
32
62
|
when Set
|
33
63
|
raw_content
|
34
|
-
when
|
64
|
+
when Array
|
35
65
|
Set.new(raw_content)
|
36
66
|
else
|
37
67
|
raw_content
|
@@ -46,6 +76,23 @@ module Nanoc
|
|
46
76
|
s << (attributes? ? 'a' : '_')
|
47
77
|
s << (compiled_content? ? 'c' : '_')
|
48
78
|
s << (path? ? 'p' : '_')
|
79
|
+
|
80
|
+
if @raw_content.is_a?(Set)
|
81
|
+
@raw_content.each do |elem|
|
82
|
+
s << '; raw_content('
|
83
|
+
s << elem.inspect
|
84
|
+
s << ')'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if @attributes.is_a?(Set)
|
89
|
+
@attributes.each do |elem|
|
90
|
+
s << '; attr('
|
91
|
+
s << elem.inspect
|
92
|
+
s << ')'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
49
96
|
s << ')'
|
50
97
|
end
|
51
98
|
end
|
@@ -63,8 +110,8 @@ module Nanoc
|
|
63
110
|
contract C::None => C::Bool
|
64
111
|
def raw_content?
|
65
112
|
case @raw_content
|
66
|
-
when
|
67
|
-
|
113
|
+
when Set
|
114
|
+
!@raw_content.empty?
|
68
115
|
else
|
69
116
|
@raw_content
|
70
117
|
end
|
@@ -73,8 +120,8 @@ module Nanoc
|
|
73
120
|
contract C::None => C::Bool
|
74
121
|
def attributes?
|
75
122
|
case @attributes
|
76
|
-
when
|
77
|
-
|
123
|
+
when Set
|
124
|
+
!@attributes.empty?
|
78
125
|
else
|
79
126
|
@attributes
|
80
127
|
end
|
@@ -136,6 +183,15 @@ module Nanoc
|
|
136
183
|
end
|
137
184
|
end
|
138
185
|
|
186
|
+
def attribute_keys
|
187
|
+
case @attributes
|
188
|
+
when Enumerable
|
189
|
+
@attributes.map { |a| a.is_a?(Array) ? a.first : a }
|
190
|
+
else
|
191
|
+
[]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
139
195
|
contract C::None => Hash
|
140
196
|
def to_h
|
141
197
|
{
|
@@ -6,11 +6,36 @@ module Nanoc
|
|
6
6
|
class DependencyStore < ::Nanoc::Core::Store
|
7
7
|
include Nanoc::Core::ContractsSupport
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
C_RAW_CONTENT =
|
10
|
+
C::Or[
|
11
|
+
C::ArrayOf[C::Or[String, Regexp]],
|
12
|
+
C::Bool
|
13
|
+
]
|
14
|
+
|
15
|
+
C_ATTR =
|
16
|
+
C::Or[
|
17
|
+
C::ArrayOf[Symbol],
|
18
|
+
C::HashOf[Symbol => C::Any],
|
19
|
+
C::Bool
|
20
|
+
]
|
21
|
+
|
22
|
+
C_KEYWORD_PROPS =
|
23
|
+
C::KeywordArgs[
|
24
|
+
raw_content: C::Optional[C_RAW_CONTENT],
|
25
|
+
attributes: C::Optional[C_ATTR],
|
26
|
+
compiled_content: C::Optional[C::Bool],
|
27
|
+
path: C::Optional[C::Bool]
|
28
|
+
]
|
29
|
+
|
12
30
|
C_OBJ_SRC = Nanoc::Core::Item
|
13
|
-
|
31
|
+
|
32
|
+
C_OBJ_DST =
|
33
|
+
C::Or[
|
34
|
+
Nanoc::Core::Item,
|
35
|
+
Nanoc::Core::Layout,
|
36
|
+
Nanoc::Core::Configuration,
|
37
|
+
Nanoc::Core::IdentifiableCollection
|
38
|
+
]
|
14
39
|
|
15
40
|
attr_reader :items
|
16
41
|
attr_reader :layouts
|
@@ -46,12 +71,7 @@ module Nanoc
|
|
46
71
|
Nanoc::Core::Dependency.new(
|
47
72
|
other_object,
|
48
73
|
object,
|
49
|
-
|
50
|
-
raw_content: props.fetch(:raw_content, false),
|
51
|
-
attributes: props.fetch(:attributes, false),
|
52
|
-
compiled_content: props.fetch(:compiled_content, false),
|
53
|
-
path: props.fetch(:path, false),
|
54
|
-
),
|
74
|
+
props,
|
55
75
|
)
|
56
76
|
end
|
57
77
|
end
|
@@ -116,11 +136,16 @@ module Nanoc
|
|
116
136
|
src_ref = obj2ref(src)
|
117
137
|
dst_ref = obj2ref(dst)
|
118
138
|
|
119
|
-
|
139
|
+
# Convert attributes into key-value pairs, if necessary
|
140
|
+
if attributes.is_a?(Hash)
|
141
|
+
attributes = attributes.to_a
|
142
|
+
end
|
143
|
+
|
144
|
+
existing_props = @graph.props_for(dst_ref, src_ref)
|
120
145
|
new_props = Nanoc::Core::DependencyProps.new(raw_content: raw_content, attributes: attributes, compiled_content: compiled_content, path: path)
|
121
|
-
props = existing_props.merge(new_props)
|
146
|
+
props = existing_props ? existing_props.merge(new_props) : new_props
|
122
147
|
|
123
|
-
@graph.add_edge(dst_ref, src_ref, props: props
|
148
|
+
@graph.add_edge(dst_ref, src_ref, props: props)
|
124
149
|
end
|
125
150
|
|
126
151
|
def add_vertex_for(obj)
|
@@ -163,18 +188,26 @@ module Nanoc
|
|
163
188
|
end
|
164
189
|
|
165
190
|
def props_for(from, to)
|
166
|
-
props = @graph.props_for(obj2ref(from), obj2ref(to))
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
191
|
+
props = @graph.props_for(obj2ref(from), obj2ref(to))
|
192
|
+
return props if props
|
193
|
+
|
194
|
+
# This is for backwards compatibility, in case there are no dependency
|
195
|
+
# props available yet. Pretend everything is set to `true`; it’ll be
|
196
|
+
# recompiled and correct props will be available in the next run.
|
197
|
+
#
|
198
|
+
# NOTE: This isn’t covered by tests, yet. (Not trivial to test because
|
199
|
+
# it’s not a condition that can arise in the current Nanoc version.)
|
200
|
+
Nanoc::Core::DependencyProps.new(
|
201
|
+
raw_content: true,
|
202
|
+
attributes: true,
|
203
|
+
compiled_content: true,
|
204
|
+
path: true,
|
205
|
+
)
|
173
206
|
end
|
174
207
|
|
175
208
|
def data
|
176
209
|
{
|
177
|
-
edges: @graph.edges,
|
210
|
+
edges: @graph.edges.map { |arr| [arr[0], arr[1], arr[2].to_h] },
|
178
211
|
vertices: @graph.vertices,
|
179
212
|
}
|
180
213
|
end
|
@@ -193,8 +226,11 @@ module Nanoc
|
|
193
226
|
# Load edges
|
194
227
|
new_data[:edges].each do |edge|
|
195
228
|
from_index, to_index, props = *edge
|
196
|
-
|
197
|
-
|
229
|
+
|
230
|
+
from = from_index && previous_refs[from_index]
|
231
|
+
to = to_index && previous_refs[to_index]
|
232
|
+
props = Nanoc::Core::DependencyProps.new(**props)
|
233
|
+
|
198
234
|
@graph.add_edge(from, to, props: props)
|
199
235
|
end
|
200
236
|
|
@@ -16,13 +16,14 @@ module Nanoc
|
|
16
16
|
|
17
17
|
C_RAW_CONTENT =
|
18
18
|
C::Or[
|
19
|
-
C::
|
19
|
+
C::ArrayOf[C::Or[String, Regexp]],
|
20
20
|
C::Bool
|
21
21
|
]
|
22
22
|
|
23
23
|
C_ATTR =
|
24
24
|
C::Or[
|
25
|
-
C::
|
25
|
+
C::ArrayOf[Symbol],
|
26
|
+
C::HashOf[Symbol => C::Any],
|
26
27
|
C::Bool
|
27
28
|
]
|
28
29
|
|
data/lib/nanoc/core/document.rb
CHANGED
@@ -49,6 +49,10 @@ module Nanoc
|
|
49
49
|
@checksum_data = checksum_data
|
50
50
|
@content_checksum_data = content_checksum_data
|
51
51
|
@attributes_checksum_data = attributes_checksum_data
|
52
|
+
|
53
|
+
# Precalculate for performance
|
54
|
+
@hash = [self.class, identifier].hash
|
55
|
+
reference
|
52
56
|
end
|
53
57
|
|
54
58
|
# @return [Hash]
|
@@ -107,7 +111,7 @@ module Nanoc
|
|
107
111
|
|
108
112
|
contract C::None => C::Num
|
109
113
|
def hash
|
110
|
-
|
114
|
+
@hash
|
111
115
|
end
|
112
116
|
|
113
117
|
contract C::Any => C::Bool
|
data/lib/nanoc/core/feature.rb
CHANGED
@@ -69,6 +69,34 @@ module Nanoc
|
|
69
69
|
@objects.find_all(arg).map { |i| view_class.new(i, @context) }
|
70
70
|
end
|
71
71
|
|
72
|
+
# Finds all objects that have the given attribute key/value pair.
|
73
|
+
#
|
74
|
+
# @example
|
75
|
+
#
|
76
|
+
# @items.where(kind: 'article')
|
77
|
+
# @items.where(kind: 'article', year: 2020)
|
78
|
+
#
|
79
|
+
# @return [Enumerable]
|
80
|
+
def where(**hash)
|
81
|
+
unless Nanoc::Core::Feature.enabled?(Nanoc::Core::Feature::WHERE)
|
82
|
+
raise(
|
83
|
+
Nanoc::Core::TrivialError,
|
84
|
+
'#where is experimental, and not yet available unless the corresponding feature flag is turned on. Set the `NANOC_FEATURES` environment variable to `where` to enable its usage. (Alternatively, set the environment variable to `all` to turn on all feature flags.)',
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: hash)
|
89
|
+
|
90
|
+
# IDEA: Nanoc could remember (from the previous compilation) how many
|
91
|
+
# times #where is called with a given attribute key, and memoize the
|
92
|
+
# key-to-identifiers list.
|
93
|
+
found_objects = @objects.select do |i|
|
94
|
+
hash.all? { |k, v| i.attributes[k] == v }
|
95
|
+
end
|
96
|
+
|
97
|
+
found_objects.map { |i| view_class.new(i, @context) }
|
98
|
+
end
|
99
|
+
|
72
100
|
# @overload [](string)
|
73
101
|
#
|
74
102
|
# Finds the object whose identifier matches the given string.
|
data/lib/nanoc/core/item.rb
CHANGED
data/lib/nanoc/core/layout.rb
CHANGED
@@ -26,13 +26,7 @@ module Nanoc
|
|
26
26
|
#
|
27
27
|
# @see Hash#[]=
|
28
28
|
def []=(key, value)
|
29
|
-
|
30
|
-
Nanoc::Core::Item,
|
31
|
-
Nanoc::Core::Layout,
|
32
|
-
Nanoc::Core::CompilationItemView,
|
33
|
-
Nanoc::Core::LayoutView,
|
34
|
-
])
|
35
|
-
if disallowed_value_classes.include?(value.class)
|
29
|
+
if disallowed_value_class?(value.class)
|
36
30
|
raise DisallowedAttributeValueError.new(value)
|
37
31
|
end
|
38
32
|
|
@@ -55,6 +49,21 @@ module Nanoc
|
|
55
49
|
hash.each { |k, v| _unwrap.set_attribute(k, v) }
|
56
50
|
self
|
57
51
|
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def disallowed_value_class?(klass)
|
56
|
+
# NOTE: We’re explicitly disabling Style/MultipleComparison, because
|
57
|
+
# the suggested alternative (Array#include?) carries a measurable
|
58
|
+
# performance penatly.
|
59
|
+
#
|
60
|
+
# rubocop:disable Style/MultipleComparison
|
61
|
+
klass == Nanoc::Core::Item ||
|
62
|
+
klass == Nanoc::Core::Layout ||
|
63
|
+
klass == Nanoc::Core::CompilationItemView ||
|
64
|
+
klass == Nanoc::Core::LayoutView
|
65
|
+
# rubocop:enable Style/MultipleComparison
|
66
|
+
end
|
58
67
|
end
|
59
68
|
end
|
60
69
|
end
|
@@ -13,6 +13,7 @@ module Nanoc
|
|
13
13
|
|
14
14
|
RULES_FOR_ITEM_REP =
|
15
15
|
[
|
16
|
+
Rules::ItemAdded,
|
16
17
|
Rules::RulesModified,
|
17
18
|
Rules::ContentModified,
|
18
19
|
Rules::AttributesModified,
|
@@ -23,6 +24,7 @@ module Nanoc
|
|
23
24
|
|
24
25
|
RULES_FOR_LAYOUT =
|
25
26
|
[
|
27
|
+
Rules::LayoutAdded,
|
26
28
|
Rules::RulesModified,
|
27
29
|
Rules::ContentModified,
|
28
30
|
Rules::AttributesModified,
|
@@ -34,16 +36,6 @@ module Nanoc
|
|
34
36
|
Rules::AttributesModified,
|
35
37
|
].freeze
|
36
38
|
|
37
|
-
RULES_FOR_ITEM_COLLECTION =
|
38
|
-
[
|
39
|
-
Rules::ItemCollectionExtended,
|
40
|
-
].freeze
|
41
|
-
|
42
|
-
RULES_FOR_LAYOUT_COLLECTION =
|
43
|
-
[
|
44
|
-
Rules::LayoutCollectionExtended,
|
45
|
-
].freeze
|
46
|
-
|
47
39
|
C_OBJ_MAYBE_REP = C::Or[Nanoc::Core::Item, Nanoc::Core::ItemRep, Nanoc::Core::Configuration, Nanoc::Core::Layout, Nanoc::Core::ItemCollection, Nanoc::Core::LayoutCollection]
|
48
40
|
|
49
41
|
contract C::KeywordArgs[outdatedness_checker: OutdatednessChecker, reps: Nanoc::Core::ItemRepRepo] => C::Any
|
@@ -67,10 +59,10 @@ module Nanoc
|
|
67
59
|
apply_rules(RULES_FOR_LAYOUT, obj)
|
68
60
|
when Nanoc::Core::Configuration
|
69
61
|
apply_rules(RULES_FOR_CONFIG, obj)
|
70
|
-
when Nanoc::Core::ItemCollection
|
71
|
-
|
72
|
-
|
73
|
-
apply_rules(
|
62
|
+
when Nanoc::Core::ItemCollection, Nanoc::Core::LayoutCollection
|
63
|
+
# Collections are never outdated. Objects inside them might be,
|
64
|
+
# however.
|
65
|
+
apply_rules([], obj)
|
74
66
|
else
|
75
67
|
raise Nanoc::Core::Errors::InternalInconsistency, "do not know how to check outdatedness of #{obj.inspect}"
|
76
68
|
end
|
@@ -190,31 +182,107 @@ module Nanoc
|
|
190
182
|
|
191
183
|
contract Nanoc::Core::Dependency => C::Bool
|
192
184
|
def dependency_causes_outdatedness?(dependency)
|
193
|
-
|
194
|
-
|
195
|
-
|
185
|
+
case dependency.from
|
186
|
+
when nil
|
187
|
+
true
|
188
|
+
when Nanoc::Core::ItemCollection, Nanoc::Core::LayoutCollection
|
189
|
+
all_objects = dependency.from
|
190
|
+
|
191
|
+
raw_content_prop_causes_outdatedness?(all_objects, dependency.props.raw_content) ||
|
192
|
+
attributes_prop_causes_outdatedness?(all_objects, dependency.props.attributes)
|
193
|
+
else
|
194
|
+
status = basic.outdatedness_status_for(dependency.from)
|
196
195
|
|
197
|
-
|
198
|
-
|
199
|
-
active.delete(:raw_content) if raw_content_unaffected?(status, dependency)
|
196
|
+
active = status.props.active & dependency.props.active
|
197
|
+
active.delete(:attributes) if attributes_unaffected?(status, dependency)
|
200
198
|
|
201
|
-
|
199
|
+
!active.empty?
|
200
|
+
end
|
202
201
|
end
|
203
202
|
|
204
203
|
def attributes_unaffected?(status, dependency)
|
205
204
|
reason = status.reasons.find { |r| r.is_a?(Nanoc::Core::OutdatednessReasons::AttributesModified) }
|
206
|
-
reason && dependency.props.
|
205
|
+
reason && dependency.props.attribute_keys.any? && (dependency.props.attribute_keys & reason.attributes).empty?
|
207
206
|
end
|
208
207
|
|
209
|
-
def
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
208
|
+
def raw_content_prop_causes_outdatedness?(objects, raw_content_prop)
|
209
|
+
return false unless raw_content_prop
|
210
|
+
|
211
|
+
matching_objects =
|
212
|
+
case raw_content_prop
|
213
|
+
when true
|
214
|
+
# If the `raw_content` dependency prop is `true`, then this is a
|
215
|
+
# dependency on all *objects* (items or layouts).
|
216
|
+
objects
|
217
|
+
when Enumerable
|
218
|
+
# If the `raw_content` dependency prop is a collection, then this
|
219
|
+
# is a dependency on specific objects, given by the patterns.
|
220
|
+
patterns = raw_content_prop.map { |r| Nanoc::Core::Pattern.from(r) }
|
221
|
+
patterns.flat_map { |pat| objects.select { |obj| pat.match?(obj.identifier) } }
|
222
|
+
else
|
223
|
+
raise(
|
224
|
+
Nanoc::Core::Errors::InternalInconsistency,
|
225
|
+
"Unexpected type of raw_content: #{raw_content_prop.inspect}",
|
226
|
+
)
|
227
|
+
end
|
228
|
+
|
229
|
+
# For all objects matching the `raw_content` dependency prop:
|
230
|
+
# If the object is outdated because it is newly added,
|
231
|
+
# then this dependency causes outdatedness.
|
232
|
+
#
|
233
|
+
# Note that these objects might be modified but *not* newly added,
|
234
|
+
# in which case this dependency will *not* cause outdatedness.
|
235
|
+
# However, when the object is used later (e.g. attributes are
|
236
|
+
# accessed), then another dependency will exist that will cause
|
237
|
+
# outdatedness.
|
238
|
+
matching_objects.any? do |obj|
|
239
|
+
status = basic.outdatedness_status_for(obj)
|
240
|
+
status.reasons.any? { |r| Nanoc::Core::OutdatednessReasons::DocumentAdded == r }
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def attributes_prop_causes_outdatedness?(objects, attributes_prop)
|
245
|
+
return false unless attributes_prop
|
246
|
+
|
247
|
+
unless attributes_prop.is_a?(Set)
|
248
|
+
raise(
|
249
|
+
Nanoc::Core::Errors::InternalInconsistency,
|
250
|
+
'expected attributes_prop to be a Set',
|
251
|
+
)
|
252
|
+
end
|
253
|
+
|
254
|
+
pairs = attributes_prop.select { |a| a.is_a?(Array) }.to_h
|
255
|
+
|
256
|
+
unless pairs.any?
|
257
|
+
raise(
|
258
|
+
Nanoc::Core::Errors::InternalInconsistency,
|
259
|
+
'expected attributes_prop not to be empty',
|
260
|
+
)
|
261
|
+
end
|
262
|
+
|
263
|
+
dep_checksums = pairs.transform_values { |value| Nanoc::Core::Checksummer.calc(value) }
|
264
|
+
|
265
|
+
objects.any? do |object|
|
266
|
+
# Find old and new attribute checksums for the object
|
267
|
+
old_object_checksums = checksum_store.attributes_checksum_for(object)
|
268
|
+
next false unless old_object_checksums
|
269
|
+
|
270
|
+
new_object_checksums = checksums.attributes_checksum_for(object)
|
271
|
+
|
272
|
+
dep_checksums.any? do |key, dep_value|
|
273
|
+
# Get old and new checksum for this particular attribute
|
274
|
+
old_value = old_object_checksums[key]
|
275
|
+
new_value = new_object_checksums[key]
|
276
|
+
|
277
|
+
# If the old and new checksums are identical, then the attribute is
|
278
|
+
# unchanged and can’t cause outdatedness.
|
279
|
+
next false unless old_value != new_value
|
280
|
+
|
281
|
+
# We already know that the old value and new value are different.
|
282
|
+
# This attribute will cause outdatedness if either of those
|
283
|
+
# checksums is identical to the one in the prop.
|
284
|
+
old_value == dep_value || new_value == dep_value
|
285
|
+
end
|
218
286
|
end
|
219
287
|
end
|
220
288
|
end
|
@@ -18,6 +18,10 @@ module Nanoc
|
|
18
18
|
# @param [String] message The descriptive message for this outdatedness
|
19
19
|
# reason
|
20
20
|
def initialize(message, props = Nanoc::Core::DependencyProps.new)
|
21
|
+
# TODO: Replace `DependencyProps` with its own `OutdatednessProps`
|
22
|
+
# type. For `OutdatednessProps`, the only values are true/false;
|
23
|
+
# giving a collection for `raw_content` makes no sense (anymore).
|
24
|
+
|
21
25
|
@message = message
|
22
26
|
@props = props
|
23
27
|
end
|
@@ -42,30 +46,16 @@ module Nanoc
|
|
42
46
|
Nanoc::Core::DependencyProps.new(compiled_content: true, path: true),
|
43
47
|
)
|
44
48
|
|
49
|
+
DocumentAdded = Generic.new(
|
50
|
+
'The item or layout is newly added to the site.',
|
51
|
+
Nanoc::Core::DependencyProps.new, # NOTE: empty props, because they’re not relevant
|
52
|
+
)
|
53
|
+
|
45
54
|
ContentModified = Generic.new(
|
46
55
|
'The content of this item has been modified since the last time the site was compiled.',
|
47
56
|
Nanoc::Core::DependencyProps.new(raw_content: true, compiled_content: true),
|
48
57
|
)
|
49
58
|
|
50
|
-
class DocumentCollectionExtended < Generic
|
51
|
-
attr_reader :objects
|
52
|
-
|
53
|
-
def initialize(objects)
|
54
|
-
super(
|
55
|
-
'New items/layouts have been added to the site.',
|
56
|
-
Nanoc::Core::DependencyProps.new(raw_content: true),
|
57
|
-
)
|
58
|
-
|
59
|
-
@objects = objects
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
class ItemCollectionExtended < DocumentCollectionExtended
|
64
|
-
end
|
65
|
-
|
66
|
-
class LayoutCollectionExtended < DocumentCollectionExtended
|
67
|
-
end
|
68
|
-
|
69
59
|
class AttributesModified < Generic
|
70
60
|
attr_reader :attributes
|
71
61
|
|
@@ -23,11 +23,39 @@ module Nanoc
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def self.affects_props(*names)
|
26
|
-
@
|
26
|
+
@affects_raw_content = false
|
27
|
+
@affects_attributes = false
|
28
|
+
@affects_compiled_content = false
|
29
|
+
@affects_path = false
|
30
|
+
|
31
|
+
names.each do |name|
|
32
|
+
case name
|
33
|
+
when :raw_content
|
34
|
+
@affects_raw_content = true
|
35
|
+
when :attributes
|
36
|
+
@affects_attributes = true
|
37
|
+
when :compiled_content
|
38
|
+
@affects_compiled_content = true
|
39
|
+
when :path
|
40
|
+
@affects_path = true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.affects_raw_content?
|
46
|
+
@affects_raw_content
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.affects_attributes?
|
50
|
+
@affects_attributes
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.affects_compiled_content?
|
54
|
+
@affects_compiled_content
|
27
55
|
end
|
28
56
|
|
29
|
-
def self.
|
30
|
-
@
|
57
|
+
def self.affects_path?
|
58
|
+
@affects_path
|
31
59
|
end
|
32
60
|
end
|
33
61
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
module OutdatednessRules
|
6
|
+
class ItemAdded < Nanoc::Core::OutdatednessRule
|
7
|
+
affects_props :raw_content
|
8
|
+
|
9
|
+
contract Nanoc::Core::ItemRep, C::Named['Nanoc::Core::OutdatednessChecker'] => C::Maybe[Nanoc::Core::OutdatednessReasons::Generic]
|
10
|
+
def apply(obj, outdatedness_checker)
|
11
|
+
if outdatedness_checker.dependency_store.new_items.include?(obj.item)
|
12
|
+
Nanoc::Core::OutdatednessReasons::DocumentAdded
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
module OutdatednessRules
|
6
|
+
class LayoutAdded < Nanoc::Core::OutdatednessRule
|
7
|
+
affects_props :raw_content
|
8
|
+
|
9
|
+
contract Nanoc::Core::Layout, C::Named['Nanoc::Core::OutdatednessChecker'] => C::Maybe[Nanoc::Core::OutdatednessReasons::Generic]
|
10
|
+
def apply(obj, outdatedness_checker)
|
11
|
+
if outdatedness_checker.dependency_store.new_layouts.include?(obj)
|
12
|
+
Nanoc::Core::OutdatednessReasons::DocumentAdded
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -13,7 +13,12 @@ module Nanoc
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def useful_to_apply?(rule)
|
16
|
-
|
16
|
+
return true if rule.affects_raw_content? && !@props.raw_content?
|
17
|
+
return true if rule.affects_attributes? && !@props.attributes?
|
18
|
+
return true if rule.affects_compiled_content? && !@props.compiled_content?
|
19
|
+
return true if rule.affects_path? && !@props.path?
|
20
|
+
|
21
|
+
false
|
17
22
|
end
|
18
23
|
|
19
24
|
def update(reason)
|
@@ -22,6 +27,10 @@ module Nanoc
|
|
22
27
|
props: @props.merge(reason.props),
|
23
28
|
)
|
24
29
|
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
"<#{self.class} reasons=#{@reasons.inspect} props=#{@props.inspect}>"
|
33
|
+
end
|
25
34
|
end
|
26
35
|
end
|
27
36
|
end
|
data/lib/nanoc/core/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nanoc-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.12.
|
4
|
+
version: 4.12.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Defreyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -261,8 +261,8 @@ files:
|
|
261
261
|
- lib/nanoc/core/outdatedness_rules/attributes_modified.rb
|
262
262
|
- lib/nanoc/core/outdatedness_rules/code_snippets_modified.rb
|
263
263
|
- lib/nanoc/core/outdatedness_rules/content_modified.rb
|
264
|
-
- lib/nanoc/core/outdatedness_rules/
|
265
|
-
- lib/nanoc/core/outdatedness_rules/
|
264
|
+
- lib/nanoc/core/outdatedness_rules/item_added.rb
|
265
|
+
- lib/nanoc/core/outdatedness_rules/layout_added.rb
|
266
266
|
- lib/nanoc/core/outdatedness_rules/not_written.rb
|
267
267
|
- lib/nanoc/core/outdatedness_rules/rules_modified.rb
|
268
268
|
- lib/nanoc/core/outdatedness_rules/uses_always_outdated_filter.rb
|
@@ -315,7 +315,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
315
315
|
- !ruby/object:Gem::Version
|
316
316
|
version: '0'
|
317
317
|
requirements: []
|
318
|
-
rubygems_version: 3.3.
|
318
|
+
rubygems_version: 3.3.24
|
319
319
|
signing_key:
|
320
320
|
specification_version: 4
|
321
321
|
summary: Core of Nanoc
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc
|
4
|
-
module Core
|
5
|
-
module OutdatednessRules
|
6
|
-
class ItemCollectionExtended < Nanoc::Core::OutdatednessRule
|
7
|
-
affects_props :raw_content
|
8
|
-
|
9
|
-
contract Nanoc::Core::ItemCollection, C::Named['Nanoc::Core::OutdatednessChecker'] => C::Maybe[Nanoc::Core::OutdatednessReasons::Generic]
|
10
|
-
def apply(_obj, outdatedness_checker)
|
11
|
-
new_items = outdatedness_checker.dependency_store.new_items
|
12
|
-
|
13
|
-
if new_items.any?
|
14
|
-
Nanoc::Core::OutdatednessReasons::ItemCollectionExtended.new(new_items)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc
|
4
|
-
module Core
|
5
|
-
module OutdatednessRules
|
6
|
-
class LayoutCollectionExtended < Nanoc::Core::OutdatednessRule
|
7
|
-
affects_props :raw_content
|
8
|
-
|
9
|
-
contract Nanoc::Core::LayoutCollection, C::Named['Nanoc::Core::OutdatednessChecker'] => C::Maybe[Nanoc::Core::OutdatednessReasons::Generic]
|
10
|
-
def apply(_obj, outdatedness_checker)
|
11
|
-
new_layouts = outdatedness_checker.dependency_store.new_layouts
|
12
|
-
|
13
|
-
if new_layouts.any?
|
14
|
-
Nanoc::Core::OutdatednessReasons::LayoutCollectionExtended.new(new_layouts)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|