nanoc-core 4.11.8 → 4.11.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eba8e5453c73cc3e17520767764cb248aaa81e3bd5a6bfebc622a0df4f6085c1
4
- data.tar.gz: 3fe67279f02a1dc8e49ca35a8d31a62e9a880f7672fc30523e9225b4f750dbcd
3
+ metadata.gz: b0c47871b0eb4f46b025c03db997f1b12971c30ca2a0ce5d5c00a6ad346bacd5
4
+ data.tar.gz: 558b36a88d1e4b943154368f7e2ee820dcf8ae8606cb5bb67b45dfaf2ba7cd07
5
5
  SHA512:
6
- metadata.gz: 87209d422a9a8da4ee3cbf6f99895a52b3b947d463fd84a94acf15b22de44b590256ec34f8863b3f7524d178871d2346603c8ca2835617ff05e13bdb05b1d8c0
7
- data.tar.gz: b897dc708603f243c69cf613b1d2fe617e9352dd3280ade6d6390cb3f3d71c48e0df10525e387496bbe638a8c7b2cdf707f014b02b37e6e3d66430f54845ded0
6
+ metadata.gz: 701578c317c2879ceca2e40efc2029f2b43cde150f53bd80c65383c18d0c8f80580e130e191082968302f68d5d148fd995e04f98893e3e57f24f310eb65ef4d4
7
+ data.tar.gz: f8511f35512c5dc0e041482691ddd0283a9d686e101aac99336653aa5b404cfaebad74dc33487d887daadce850d946b9c33d427d3afa8dab2a7e6d6822122224
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # Stores action sequences for objects that can be run through a rule (item
6
+ # representations and layouts).
7
+ #
8
+ # @api private
9
+ class ActionSequenceStore < ::Nanoc::Core::Store
10
+ include Nanoc::Core::ContractsSupport
11
+
12
+ contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
13
+ def initialize(config:)
14
+ super(Nanoc::Core::Store.tmp_path_for(config: config, store_name: 'rule_memory'), 1)
15
+
16
+ @action_sequences = {}
17
+ end
18
+
19
+ # @param [Nanoc::Core::ItemRep, Nanoc::Core::Layout] obj The item representation or
20
+ # the layout to get the action sequence for
21
+ #
22
+ # @return [Array] The action sequence for the given object
23
+ def [](obj)
24
+ @action_sequences[obj.reference]
25
+ end
26
+
27
+ # @param [Nanoc::Core::ItemRep, Nanoc::Core::Layout] obj The item representation or
28
+ # the layout to set the action sequence for
29
+ #
30
+ # @param [Array] action_sequence The new action sequence to be stored
31
+ #
32
+ # @return [void]
33
+ def []=(obj, action_sequence)
34
+ @action_sequences[obj.reference] = action_sequence
35
+ end
36
+
37
+ protected
38
+
39
+ # @see Nanoc::Core::Store#data
40
+ def data
41
+ @action_sequences
42
+ end
43
+
44
+ # @see Nanoc::Core::Store#data=
45
+ def data=(new_data)
46
+ @action_sequences = new_data
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # Represents a cache than can be used to store already compiled content,
6
+ # to prevent it from being needlessly recompiled.
7
+ #
8
+ # @api private
9
+ class BinaryCompiledContentCache < ::Nanoc::Core::Store
10
+ include Nanoc::Core::ContractsSupport
11
+
12
+ contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
13
+ def initialize(config:)
14
+ super(Nanoc::Core::Store.tmp_path_for(config: config, store_name: 'binary_content'), 1)
15
+
16
+ @cache = {}
17
+ end
18
+
19
+ contract Nanoc::Core::ItemRep => C::Maybe[C::HashOf[Symbol => Nanoc::Core::Content]]
20
+ # Returns the cached compiled content for the given item representation.
21
+ #
22
+ # This cached compiled content is a hash where the keys are the snapshot
23
+ # names, and the values the compiled content at the given snapshot.
24
+ def [](rep)
25
+ item_cache = @cache[rep.item.identifier] || {}
26
+
27
+ rep_cache = item_cache[rep.name]
28
+ return nil if rep_cache.nil?
29
+
30
+ rep_cache.transform_values do |filename|
31
+ Nanoc::Core::Content.create(filename, binary: true)
32
+ end
33
+ end
34
+
35
+ contract Nanoc::Core::ItemRep => C::Bool
36
+ def include?(rep)
37
+ item_cache = @cache[rep.item.identifier] || {}
38
+ item_cache.key?(rep.name)
39
+ end
40
+
41
+ contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::BinaryContent] => C::HashOf[Symbol => Nanoc::Core::Content]
42
+ # Sets the compiled content for the given representation.
43
+ #
44
+ # This cached compiled content is a hash where the keys are the snapshot
45
+ # names, and the values the compiled content at the given snapshot.
46
+ def []=(rep, content)
47
+ @cache[rep.item.identifier] ||= {}
48
+ @cache[rep.item.identifier][rep.name] ||= {}
49
+ rep_cache = @cache[rep.item.identifier][rep.name]
50
+
51
+ content.each do |snapshot, binary_content|
52
+ filename = build_filename(rep, snapshot)
53
+ rep_cache[snapshot] = filename
54
+
55
+ # Avoid reassigning the same content if this binary cached content was
56
+ # already used, because it was available and the item wasn’t oudated.
57
+ next if binary_content.filename == filename
58
+
59
+ # Copy
60
+ #
61
+ # NOTE: hardlinking is not an option in this case, because hardlinking
62
+ # would make it possible for the content to be (inadvertently)
63
+ # changed outside of Nanoc.
64
+ FileUtils.mkdir_p(File.dirname(filename))
65
+ FileUtils.cp(binary_content.filename, filename)
66
+ end
67
+ end
68
+
69
+ def prune(items:)
70
+ item_identifiers = Set.new(items.map(&:identifier))
71
+
72
+ @cache.each_key do |key|
73
+ # TODO: remove unused item reps
74
+ next if item_identifiers.include?(key)
75
+
76
+ @cache.delete(key)
77
+ path = dirname_for_item_identifier(key)
78
+ FileUtils.rm_rf(path)
79
+ end
80
+ end
81
+
82
+ def data
83
+ @cache
84
+ end
85
+
86
+ def data=(new_data)
87
+ @cache = {}
88
+
89
+ new_data.each_pair do |item_identifier, content_per_rep|
90
+ @cache[item_identifier] ||= content_per_rep
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def dirname
97
+ filename + '_data'
98
+ end
99
+
100
+ def string_to_path_component(string)
101
+ string.gsub(/[^a-zA-Z0-9]+/, '_') +
102
+ '-' +
103
+ Digest::SHA1.hexdigest(string)[0..9]
104
+ end
105
+
106
+ def dirname_for_item_identifier(item_identifier)
107
+ File.join(
108
+ dirname,
109
+ string_to_path_component(item_identifier.to_s),
110
+ )
111
+ end
112
+
113
+ def dirname_for_item_rep(rep)
114
+ File.join(
115
+ dirname_for_item_identifier(rep.item.identifier),
116
+ string_to_path_component(rep.name.to_s),
117
+ )
118
+ end
119
+
120
+ def build_filename(rep, snapshot_name)
121
+ File.join(
122
+ dirname_for_item_rep(rep),
123
+ string_to_path_component(snapshot_name.to_s),
124
+ )
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # Stores checksums for objects in order to be able to detect whether a file
6
+ # has changed since the last site compilation.
7
+ #
8
+ # @api private
9
+ class ChecksumStore < ::Nanoc::Core::Store
10
+ include Nanoc::Core::ContractsSupport
11
+
12
+ attr_writer :checksums
13
+ attr_accessor :objects
14
+
15
+ c_obj = C::Or[Nanoc::Core::Item, Nanoc::Core::Layout, Nanoc::Core::Configuration, Nanoc::Core::CodeSnippet]
16
+
17
+ contract C::KeywordArgs[config: Nanoc::Core::Configuration, objects: C::IterOf[c_obj]] => C::Any
18
+ def initialize(config:, objects:)
19
+ super(Nanoc::Core::Store.tmp_path_for(config: config, store_name: 'checksums'), 2)
20
+
21
+ @objects = objects
22
+
23
+ @checksums = {}
24
+ end
25
+
26
+ contract c_obj => C::Maybe[String]
27
+ def [](obj)
28
+ @checksums[obj.reference]
29
+ end
30
+
31
+ contract c_obj => self
32
+ def add(obj)
33
+ if obj.is_a?(Nanoc::Core::Document)
34
+ @checksums[[obj.reference, :content]] = Nanoc::Core::Checksummer.calc_for_content_of(obj)
35
+ end
36
+
37
+ if obj.is_a?(Nanoc::Core::Document) || obj.is_a?(Nanoc::Core::Configuration)
38
+ @checksums[[obj.reference, :each_attribute]] = Nanoc::Core::Checksummer.calc_for_each_attribute_of(obj)
39
+ end
40
+
41
+ @checksums[obj.reference] = Nanoc::Core::Checksummer.calc(obj)
42
+
43
+ self
44
+ end
45
+
46
+ contract c_obj => C::Maybe[String]
47
+ def content_checksum_for(obj)
48
+ @checksums[[obj.reference, :content]]
49
+ end
50
+
51
+ contract c_obj => C::Maybe[C::HashOf[Symbol, String]]
52
+ def attributes_checksum_for(obj)
53
+ @checksums[[obj.reference, :each_attribute]]
54
+ end
55
+
56
+ protected
57
+
58
+ def data
59
+ @checksums
60
+ end
61
+
62
+ def data=(new_data)
63
+ references = Set.new(@objects.map(&:reference))
64
+
65
+ @checksums = {}
66
+ new_data.each_pair do |key, checksum|
67
+ if references.include?(key) || references.include?(key.first)
68
+ @checksums[key] = checksum
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # Represents a cache than can be used to store already compiled content,
6
+ # to prevent it from being needlessly recompiled.
7
+ #
8
+ # @api private
9
+ class CompiledContentCache < ::Nanoc::Core::Store
10
+ include Nanoc::Core::ContractsSupport
11
+
12
+ contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
13
+ def initialize(config:)
14
+ @textual_cache = Nanoc::Core::TextualCompiledContentCache.new(config: config)
15
+ @binary_cache = Nanoc::Core::BinaryCompiledContentCache.new(config: config)
16
+
17
+ @wrapped_caches = [@textual_cache, @binary_cache]
18
+ end
19
+
20
+ contract Nanoc::Core::ItemRep => C::Maybe[C::HashOf[Symbol => Nanoc::Core::Content]]
21
+ # Returns the cached compiled content for the given item representation.
22
+ #
23
+ # This cached compiled content is a hash where the keys are the snapshot
24
+ # names. and the values the compiled content at the given snapshot.
25
+ def [](rep)
26
+ textual_content_map = @textual_cache[rep]
27
+ binary_content_map = @binary_cache[rep]
28
+
29
+ # If either the textual or the binary content cache is nil, assume the
30
+ # cache is entirely absent.
31
+ #
32
+ # This is necessary to support the case where only textual content is
33
+ # cached (which was the case in older versions of Nanoc).
34
+ return nil if [textual_content_map, binary_content_map].any?(&:nil?)
35
+
36
+ textual_content_map.merge(binary_content_map)
37
+ end
38
+
39
+ contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::Content] => C::Any
40
+ # Sets the compiled content for the given representation.
41
+ #
42
+ # This cached compiled content is a hash where the keys are the snapshot
43
+ # names and the values the compiled content at the given snapshot.
44
+ def []=(rep, content)
45
+ @textual_cache[rep] = content.select { |_key, c| c.textual? }
46
+ @binary_cache[rep] = content.select { |_key, c| c.binary? }
47
+ end
48
+
49
+ def prune(*args)
50
+ @wrapped_caches.each { |w| w.prune(*args) }
51
+ end
52
+
53
+ # True if there is cached compiled content available for this item, and
54
+ # all entries are present (either textual or binary).
55
+ def full_cache_available?(rep)
56
+ @textual_cache.include?(rep) && @binary_cache.include?(rep)
57
+ end
58
+
59
+ def load(*args)
60
+ @wrapped_caches.each { |w| w.load(*args) }
61
+ end
62
+
63
+ def store(*args)
64
+ @wrapped_caches.each { |w| w.store(*args) }
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # @api private
6
+ class CompiledContentStore
7
+ include Nanoc::Core::ContractsSupport
8
+
9
+ def initialize
10
+ @contents = Hash.new { |hash, rep| hash[rep] = {} }
11
+ @current_content = {}
12
+ end
13
+
14
+ contract Nanoc::Core::ItemRep, Symbol => C::Maybe[Nanoc::Core::Content]
15
+ def get(rep, snapshot_name)
16
+ @contents[rep][snapshot_name]
17
+ end
18
+
19
+ contract Nanoc::Core::ItemRep => C::Maybe[Nanoc::Core::Content]
20
+ def get_current(rep)
21
+ @current_content[rep]
22
+ end
23
+
24
+ contract Nanoc::Core::ItemRep, Symbol, Nanoc::Core::Content => C::Any
25
+ def set(rep, snapshot_name, contents)
26
+ @contents[rep][snapshot_name] = contents
27
+ end
28
+
29
+ contract Nanoc::Core::ItemRep, Nanoc::Core::Content => C::Any
30
+ def set_current(rep, content)
31
+ @current_content[rep] = content
32
+ end
33
+
34
+ contract Nanoc::Core::ItemRep => C::HashOf[Symbol => Nanoc::Core::Content]
35
+ def get_all(rep)
36
+ @contents[rep]
37
+ end
38
+
39
+ contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::Content] => C::Any
40
+ def set_all(rep, contents_per_snapshot)
41
+ @contents[rep] = contents_per_snapshot
42
+ end
43
+
44
+ contract C::KeywordArgs[rep: Nanoc::Core::ItemRep, snapshot: C::Optional[C::Maybe[Symbol]]] => Nanoc::Core::Content
45
+ def raw_compiled_content(rep:, snapshot: nil)
46
+ # Get name of last pre-layout snapshot
47
+ has_pre = rep.snapshot_defs.any? { |sd| sd.name == :pre }
48
+ snapshot_name = snapshot || (has_pre ? :pre : :last)
49
+
50
+ # Check existance of snapshot
51
+ snapshot_def = rep.snapshot_defs.reverse.find { |sd| sd.name == snapshot_name }
52
+ unless snapshot_def
53
+ raise Nanoc::Core::Errors::NoSuchSnapshot.new(rep, snapshot_name)
54
+ end
55
+
56
+ # Return content if it is available
57
+ content = get(rep, snapshot_name)
58
+ return content if content
59
+
60
+ # Content is unavailable; notify and try again
61
+ Fiber.yield(Nanoc::Core::Errors::UnmetDependency.new(rep, snapshot_name))
62
+ get(rep, snapshot_name)
63
+ end
64
+
65
+ contract C::KeywordArgs[rep: Nanoc::Core::ItemRep, snapshot: C::Optional[C::Maybe[Symbol]]] => String
66
+ def compiled_content(rep:, snapshot: nil)
67
+ snapshot_content = raw_compiled_content(rep: rep, snapshot: snapshot)
68
+
69
+ if snapshot_content.binary?
70
+ raise Nanoc::Core::Errors::CannotGetCompiledContentOfBinaryItem.new(rep)
71
+ end
72
+
73
+ snapshot_content.string
74
+ end
75
+ end
76
+ end
77
+ end
@@ -78,6 +78,18 @@
78
78
  "checks": {
79
79
  "type": "object",
80
80
  "properties": {
81
+ "all": {
82
+ "type": "object",
83
+ "additionalProperties": false,
84
+ "properties": {
85
+ "exclude_files": {
86
+ "type": "array",
87
+ "items": {
88
+ "type": "string"
89
+ }
90
+ }
91
+ }
92
+ },
81
93
  "internal_links": {
82
94
  "type": "object",
83
95
  "additionalProperties": false,
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # @api private
6
+ class DependencyStore < ::Nanoc::Core::Store
7
+ include Nanoc::Core::ContractsSupport
8
+
9
+ C_ATTR = C::Or[C::IterOf[Symbol], C::Bool]
10
+ C_RAW_CONTENT = C::Or[C::IterOf[C::Or[String, Regexp]], C::Bool]
11
+ 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]]
12
+ C_OBJ_SRC = Nanoc::Core::Item
13
+ C_OBJ_DST = C::Or[Nanoc::Core::Item, Nanoc::Core::Layout, Nanoc::Core::Configuration, Nanoc::Core::IdentifiableCollection]
14
+
15
+ attr_reader :items
16
+ attr_reader :layouts
17
+
18
+ contract Nanoc::Core::ItemCollection, Nanoc::Core::LayoutCollection, Nanoc::Core::Configuration => C::Any
19
+ def initialize(items, layouts, config)
20
+ super(Nanoc::Core::Store.tmp_path_for(config: config, store_name: 'dependencies'), 5)
21
+
22
+ @items = items
23
+ @layouts = layouts
24
+
25
+ @refs2objs = {}
26
+ items.each { |o| add_vertex_for(o) }
27
+ layouts.each { |o| add_vertex_for(o) }
28
+ add_vertex_for(config)
29
+ add_vertex_for(items)
30
+ add_vertex_for(layouts)
31
+
32
+ @new_objects = []
33
+ @graph = Nanoc::Core::DirectedGraph.new([nil] + objs2refs(@items) + objs2refs(@layouts))
34
+ end
35
+
36
+ contract C_OBJ_SRC => C::ArrayOf[Nanoc::Core::Dependency]
37
+ def dependencies_causing_outdatedness_of(object)
38
+ objects_causing_outdatedness_of(object).map do |other_object|
39
+ props = props_for(other_object, object)
40
+
41
+ Nanoc::Core::Dependency.new(
42
+ other_object,
43
+ object,
44
+ Nanoc::Core::DependencyProps.new(
45
+ raw_content: props.fetch(:raw_content, false),
46
+ attributes: props.fetch(:attributes, false),
47
+ compiled_content: props.fetch(:compiled_content, false),
48
+ path: props.fetch(:path, false),
49
+ ),
50
+ )
51
+ end
52
+ end
53
+
54
+ def items=(items)
55
+ @items = items
56
+ items.each { |o| @refs2objs[obj2ref(o)] = o }
57
+ add_vertex_for(items)
58
+ end
59
+
60
+ def layouts=(layouts)
61
+ @layouts = layouts
62
+ layouts.each { |o| @refs2objs[obj2ref(o)] = o }
63
+ add_vertex_for(layouts)
64
+ end
65
+
66
+ def new_items
67
+ @new_objects.select { |o| o.is_a?(Nanoc::Core::Item) }
68
+ end
69
+
70
+ def new_layouts
71
+ @new_objects.select { |o| o.is_a?(Nanoc::Core::Layout) }
72
+ end
73
+
74
+ # Returns the direct dependencies for the given object.
75
+ #
76
+ # The direct dependencies of the given object include the items and
77
+ # layouts that, when outdated will cause the given object to be marked as
78
+ # outdated. Indirect dependencies will not be returned (e.g. if A depends
79
+ # on B which depends on C, then the direct dependencies of A do not
80
+ # include C).
81
+ #
82
+ # The direct predecessors can include nil, which indicates an item that is
83
+ # no longer present in the site.
84
+ #
85
+ # @param [Nanoc::Core::Item, Nanoc::Core::Layout] object The object for
86
+ # which to fetch the direct predecessors
87
+ #
88
+ # @return [Array<Nanoc::Core::Item, Nanoc::Core::Layout, nil>] The direct
89
+ # predecessors of
90
+ # the given object
91
+ def objects_causing_outdatedness_of(object)
92
+ refs2objs(@graph.direct_predecessors_of(obj2ref(object)))
93
+ end
94
+
95
+ contract C::Maybe[C_OBJ_SRC], C::Maybe[C_OBJ_DST], C_KEYWORD_PROPS => C::Any
96
+ # Records a dependency from `src` to `dst` in the dependency graph. When
97
+ # `dst` is oudated, `src` will also become outdated.
98
+ #
99
+ # @param [Nanoc::Core::Item, Nanoc::Core::Layout] src The source of the dependency,
100
+ # i.e. the object that will become outdated if dst is outdated
101
+ #
102
+ # @param [Nanoc::Core::Item, Nanoc::Core::Layout] dst The destination of the
103
+ # dependency, i.e. the object that will cause the source to become
104
+ # outdated if the destination is outdated
105
+ #
106
+ # @return [void]
107
+ def record_dependency(src, dst, raw_content: false, attributes: false, compiled_content: false, path: false)
108
+ return if src == dst
109
+
110
+ add_vertex_for(src)
111
+ add_vertex_for(dst)
112
+
113
+ src_ref = obj2ref(src)
114
+ dst_ref = obj2ref(dst)
115
+
116
+ existing_props = Nanoc::Core::DependencyProps.new(@graph.props_for(dst_ref, src_ref) || {})
117
+ new_props = Nanoc::Core::DependencyProps.new(raw_content: raw_content, attributes: attributes, compiled_content: compiled_content, path: path)
118
+ props = existing_props.merge(new_props)
119
+
120
+ @graph.add_edge(dst_ref, src_ref, props: props.to_h)
121
+ end
122
+
123
+ def add_vertex_for(obj)
124
+ @refs2objs[obj2ref(obj)] = obj
125
+ end
126
+
127
+ # Empties the list of dependencies for the given object. This is necessary
128
+ # before recompiling the given object, because otherwise old dependencies
129
+ # will stick around and new dependencies will appear twice. This function
130
+ # removes all incoming edges for the given vertex.
131
+ #
132
+ # @param [Nanoc::Core::Item, Nanoc::Core::Layout] object The object for which to
133
+ # forget all dependencies
134
+ #
135
+ # @return [void]
136
+ def forget_dependencies_for(object)
137
+ @graph.delete_edges_to(obj2ref(object))
138
+ end
139
+
140
+ protected
141
+
142
+ def obj2ref(obj)
143
+ obj&.reference
144
+ end
145
+
146
+ def ref2obj(reference)
147
+ if reference
148
+ @refs2objs[reference]
149
+ else
150
+ nil
151
+ end
152
+ end
153
+
154
+ def objs2refs(objs)
155
+ objs.map { |o| obj2ref(o) }
156
+ end
157
+
158
+ def refs2objs(refs)
159
+ refs.map { |r| ref2obj(r) }
160
+ end
161
+
162
+ def props_for(from, to)
163
+ props = @graph.props_for(obj2ref(from), obj2ref(to)) || {}
164
+
165
+ if props.values.any? { |v| v }
166
+ props
167
+ else
168
+ { raw_content: true, attributes: true, compiled_content: true, path: true }
169
+ end
170
+ end
171
+
172
+ def data
173
+ {
174
+ edges: @graph.edges,
175
+ vertices: @graph.vertices,
176
+ }
177
+ end
178
+
179
+ def data=(new_data)
180
+ objects = Set.new(@items.to_a + @layouts.to_a)
181
+ refs = objs2refs(objects)
182
+
183
+ # Create new graph
184
+ @graph = Nanoc::Core::DirectedGraph.new([nil] + refs)
185
+
186
+ # Load vertices
187
+ previous_refs = new_data[:vertices]
188
+ previous_objects = Set.new(refs2objs(previous_refs))
189
+
190
+ # Load edges
191
+ new_data[:edges].each do |edge|
192
+ from_index, to_index, props = *edge
193
+ from = from_index && previous_refs[from_index]
194
+ to = to_index && previous_refs[to_index]
195
+ @graph.add_edge(from, to, props: props)
196
+ end
197
+
198
+ # Record dependency from all items on new items
199
+ @new_objects = objects - previous_objects
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # @api private
6
+ class DependencyTracker
7
+ include Nanoc::Core::ContractsSupport
8
+
9
+ C_OBJ = C::Or[Nanoc::Core::Item, Nanoc::Core::Layout, Nanoc::Core::Configuration, Nanoc::Core::IdentifiableCollection]
10
+ C_RAW_CONTENT = C::Or[C::IterOf[C::Or[String, Regexp]], C::Bool]
11
+ C_ATTR = C::Or[C::IterOf[Symbol], C::Bool]
12
+ 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]]
13
+
14
+ class Null
15
+ include Nanoc::Core::ContractsSupport
16
+
17
+ contract C_OBJ, C_ARGS => C::Any
18
+ def enter(_obj, raw_content: false, attributes: false, compiled_content: false, path: false); end
19
+
20
+ contract C_OBJ => C::Any
21
+ def exit; end
22
+
23
+ contract C_OBJ, C_ARGS => C::Any
24
+ def bounce(_obj, raw_content: false, attributes: false, compiled_content: false, path: false); end
25
+ end
26
+
27
+ attr_reader :dependency_store
28
+
29
+ def initialize(dependency_store)
30
+ @dependency_store = dependency_store
31
+ @stack = []
32
+ end
33
+
34
+ contract C_OBJ, C_ARGS => C::Any
35
+ def enter(obj, raw_content: false, attributes: false, compiled_content: false, path: false)
36
+ unless @stack.empty?
37
+ Nanoc::Core::NotificationCenter.post(:dependency_created, @stack.last, obj)
38
+ @dependency_store.record_dependency(
39
+ @stack.last,
40
+ obj,
41
+ raw_content: raw_content,
42
+ attributes: attributes,
43
+ compiled_content: compiled_content,
44
+ path: path,
45
+ )
46
+ end
47
+
48
+ @stack.push(obj)
49
+ end
50
+
51
+ contract C_OBJ => C::Any
52
+ def exit
53
+ @stack.pop
54
+ end
55
+
56
+ contract C_OBJ, C_ARGS => C::Any
57
+ def bounce(obj, raw_content: false, attributes: false, compiled_content: false, path: false)
58
+ enter(obj, raw_content: raw_content, attributes: attributes, compiled_content: compiled_content, path: path)
59
+ exit
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module Errors
6
+ # Error that is raised when the compiled content at a non-existing snapshot
7
+ # is requested.
8
+ class NoSuchSnapshot < ::Nanoc::Core::Error
9
+ # @return [Nanoc::Core::ItemRep] The item rep from which the compiled content
10
+ # was requested
11
+ attr_reader :item_rep
12
+
13
+ # @return [Symbol] The requested snapshot
14
+ attr_reader :snapshot
15
+
16
+ # @param [Nanoc::Core::ItemRep] item_rep The item rep from which the compiled
17
+ # content was requested
18
+ #
19
+ # @param [Symbol] snapshot The requested snapshot
20
+ def initialize(item_rep, snapshot)
21
+ @item_rep = item_rep
22
+ @snapshot = snapshot
23
+ super("The “#{item_rep.inspect}” item rep does not have a snapshot “#{snapshot.inspect}”")
24
+ end
25
+ end
26
+
27
+ # Error that is raised when an rep cannot be compiled because it depends
28
+ # on other representations.
29
+ class UnmetDependency < ::Nanoc::Core::Error
30
+ # @return [Nanoc::Core::ItemRep] The item representation that cannot yet be
31
+ # compiled
32
+ attr_reader :rep
33
+
34
+ # @return [Symbol] The name of the snapshot that cannot yet be compiled
35
+ attr_reader :snapshot_name
36
+
37
+ # @param [Nanoc::Core::ItemRep] rep The item representation that cannot yet be
38
+ # compiled
39
+ def initialize(rep, snapshot_name)
40
+ @rep = rep
41
+ @snapshot_name = snapshot_name
42
+
43
+ super("The current item cannot be compiled yet because of an unmet dependency on the “#{rep.item.identifier}” item (rep “#{rep.name}”, snapshot “#{snapshot_name}”).")
44
+ end
45
+ end
46
+
47
+ # Error that is raised when the compiled content of a binary item is attempted to be accessed.
48
+ class CannotGetCompiledContentOfBinaryItem < ::Nanoc::Core::Error
49
+ # @param [Nanoc::Core::ItemRep] rep The binary item representation whose compiled content was attempted to be accessed
50
+ def initialize(rep)
51
+ super("You cannot access the compiled content of a binary item representation (but you can access the path). The offending item rep is #{rep}.")
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # Stores item reps (in memory).
6
+ #
7
+ # @api private
8
+ class ItemRepRepo
9
+ include Enumerable
10
+
11
+ def initialize
12
+ @reps = []
13
+ @reps_by_item = {}
14
+ end
15
+
16
+ def <<(rep)
17
+ @reps << rep
18
+
19
+ @reps_by_item[rep.item] ||= []
20
+ @reps_by_item[rep.item] << rep
21
+ end
22
+
23
+ def to_a
24
+ @reps
25
+ end
26
+
27
+ def each(&block)
28
+ @reps.each(&block)
29
+ self
30
+ end
31
+
32
+ def [](item)
33
+ @reps_by_item.fetch(item, [])
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # Module that contains all outdatedness reasons.
6
+ #
7
+ # @api private
8
+ module OutdatednessReasons
9
+ # A generic outdatedness reason. An outdatedness reason is basically a
10
+ # descriptive message that explains why a given object is outdated.
11
+ class Generic
12
+ # @return [String] A descriptive message for this outdatedness reason
13
+ attr_reader :message
14
+
15
+ # @return [Nanoc::Core::DependencyProps]
16
+ attr_reader :props
17
+
18
+ # @param [String] message The descriptive message for this outdatedness
19
+ # reason
20
+ def initialize(message, props = Nanoc::Core::DependencyProps.new)
21
+ @message = message
22
+ @props = props
23
+ end
24
+ end
25
+
26
+ CodeSnippetsModified = Generic.new(
27
+ 'The code snippets have been modified since the last time the site was compiled.',
28
+ Nanoc::Core::DependencyProps.new(raw_content: true, attributes: true, compiled_content: true, path: true),
29
+ )
30
+
31
+ DependenciesOutdated = Generic.new(
32
+ 'This item uses content or attributes that have changed since the last time the site was compiled.',
33
+ )
34
+
35
+ NotWritten = Generic.new(
36
+ 'This item representation has not yet been written to the output directory (but it does have a path).',
37
+ Nanoc::Core::DependencyProps.new(raw_content: true, attributes: true, compiled_content: true, path: true),
38
+ )
39
+
40
+ RulesModified = Generic.new(
41
+ 'The rules file has been modified since the last time the site was compiled.',
42
+ Nanoc::Core::DependencyProps.new(compiled_content: true, path: true),
43
+ )
44
+
45
+ ContentModified = Generic.new(
46
+ 'The content of this item has been modified since the last time the site was compiled.',
47
+ Nanoc::Core::DependencyProps.new(raw_content: true, compiled_content: true),
48
+ )
49
+
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
+ class AttributesModified < Generic
70
+ attr_reader :attributes
71
+
72
+ def initialize(attributes)
73
+ super(
74
+ 'The attributes of this item have been modified since the last time the site was compiled.',
75
+ Nanoc::Core::DependencyProps.new(attributes: true, compiled_content: true),
76
+ )
77
+
78
+ @attributes = attributes
79
+ end
80
+ end
81
+
82
+ UsesAlwaysOutdatedFilter = Generic.new(
83
+ 'This item rep uses one or more filters that cannot track dependencies, and will thus always be considered as outdated.',
84
+ Nanoc::Core::DependencyProps.new(raw_content: true, attributes: true, compiled_content: true),
85
+ )
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # @api private
6
+ class OutdatednessRule
7
+ include Nanoc::Core::ContractsSupport
8
+ include Singleton
9
+
10
+ def call(obj, outdatedness_checker)
11
+ Nanoc::Core::Instrumentor.call(:outdatedness_rule_ran, self.class) do
12
+ apply(obj, outdatedness_checker)
13
+ end
14
+ end
15
+
16
+ def apply(_obj, _outdatedness_checker)
17
+ raise NotImplementedError.new('Nanoc::Core::OutdatednessRule subclasses must implement #apply')
18
+ end
19
+
20
+ contract C::None => String
21
+ def inspect
22
+ "#{self.class.name}(#{reason})"
23
+ end
24
+
25
+ def self.affects_props(*names)
26
+ @affected_props = Set.new(names)
27
+ end
28
+
29
+ def self.affected_props
30
+ @affected_props
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # @api private
6
+ class OutdatednessStatus
7
+ attr_reader :reasons
8
+ attr_reader :props
9
+
10
+ def initialize(reasons: [], props: Nanoc::Core::DependencyProps.new)
11
+ @reasons = reasons
12
+ @props = props
13
+ end
14
+
15
+ def useful_to_apply?(rule)
16
+ (rule.affected_props - @props.active).any?
17
+ end
18
+
19
+ def update(reason)
20
+ self.class.new(
21
+ reasons: @reasons + [reason],
22
+ props: @props.merge(reason.props),
23
+ )
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # @api private
6
+ class OutdatednessStore < ::Nanoc::Core::Store
7
+ include Nanoc::Core::ContractsSupport
8
+
9
+ contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
10
+ def initialize(config:)
11
+ super(Nanoc::Core::Store.tmp_path_for(config: config, store_name: 'outdatedness'), 1)
12
+
13
+ @outdated_refs = Set.new
14
+ end
15
+
16
+ contract Nanoc::Core::ItemRep => C::Bool
17
+ def include?(obj)
18
+ @outdated_refs.include?(obj.reference)
19
+ end
20
+
21
+ contract Nanoc::Core::ItemRep => self
22
+ def add(obj)
23
+ @outdated_refs << obj.reference
24
+ self
25
+ end
26
+
27
+ contract Nanoc::Core::ItemRep => self
28
+ def remove(obj)
29
+ @outdated_refs.delete(obj.reference)
30
+ self
31
+ end
32
+
33
+ contract C::None => C::Bool
34
+ def empty?
35
+ @outdated_refs.empty?
36
+ end
37
+
38
+ contract C::None => self
39
+ def clear
40
+ @outdated_refs = Set.new
41
+ self
42
+ end
43
+
44
+ protected
45
+
46
+ def data
47
+ @outdated_refs
48
+ end
49
+
50
+ def data=(new_data)
51
+ @outdated_refs = Set.new(new_data)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ class PrefixedDataSource < Nanoc::Core::DataSource
6
+ def initialize(data_source, items_prefix, layouts_prefix)
7
+ super({}, '/', '/', {})
8
+
9
+ @data_source = data_source
10
+ @items_prefix = items_prefix
11
+ @layouts_prefix = layouts_prefix
12
+ end
13
+
14
+ def items
15
+ @data_source.items.map { |d| d.with_identifier_prefix(@items_prefix) }
16
+ end
17
+
18
+ def layouts
19
+ @data_source.layouts.map { |d| d.with_identifier_prefix(@layouts_prefix) }
20
+ end
21
+
22
+ def item_changes
23
+ @data_source.item_changes
24
+ end
25
+
26
+ def layout_changes
27
+ @data_source.layout_changes
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # An abstract superclass for classes that need to store data to the
6
+ # filesystem, such as checksums, cached compiled content and dependency
7
+ # graphs.
8
+ #
9
+ # Each store has a version number. When attempting to load data from a store
10
+ # that has an incompatible version number, no data will be loaded, but
11
+ # {#version_mismatch_detected} will be called.
12
+ #
13
+ # @abstract Subclasses must implement {#data} and {#data=}, and may
14
+ # implement {#no_data_found} and {#version_mismatch_detected}.
15
+ #
16
+ # @api private
17
+ class Store
18
+ include Nanoc::Core::ContractsSupport
19
+
20
+ # @return [String] The name of the file where data will be loaded from and
21
+ # stored to.
22
+ attr_reader :filename
23
+
24
+ # @return [Numeric] The version number corresponding to the file format
25
+ # the data is in. When the file format changes, the version number
26
+ # should be incremented.
27
+ attr_reader :version
28
+
29
+ # Creates a new store for the given filename.
30
+ #
31
+ # @param [String] filename The name of the file where data will be loaded
32
+ # from and stored to.
33
+ #
34
+ # @param [Numeric] version The version number corresponding to the file
35
+ # format the data is in. When the file format changes, the version
36
+ # number should be incremented.
37
+ def initialize(filename, version)
38
+ @filename = filename
39
+ @version = version
40
+ end
41
+
42
+ # Logic for building tmp path from active environment and store name
43
+ # @api private
44
+ contract C::KeywordArgs[config: Nanoc::Core::Configuration, store_name: String] => C::AbsolutePathString
45
+ def self.tmp_path_for(store_name:, config:)
46
+ File.absolute_path(
47
+ File.join(tmp_path_prefix(config.output_dir), store_name),
48
+ config.dir,
49
+ )
50
+ end
51
+
52
+ def self.tmp_path_prefix(output_dir)
53
+ dir = Digest::SHA1.hexdigest(output_dir)[0..12]
54
+ File.join('tmp', 'nanoc', dir)
55
+ end
56
+
57
+ # @group Loading and storing data
58
+
59
+ # @return The data that should be written to the disk
60
+ #
61
+ # @abstract This method must be implemented by the subclass.
62
+ def data
63
+ raise NotImplementedError.new('Nanoc::Core::Store subclasses must implement #data and #data=')
64
+ end
65
+
66
+ # @param new_data The data that has been loaded from the disk
67
+ #
68
+ # @abstract This method must be implemented by the subclass.
69
+ #
70
+ # @return [void]
71
+ def data=(new_data) # rubocop:disable Lint/UnusedMethodArgument
72
+ raise NotImplementedError.new('Nanoc::Core::Store subclasses must implement #data and #data=')
73
+ end
74
+
75
+ # Loads the data from the filesystem into memory. This method will set the
76
+ # loaded data using the {#data=} method.
77
+ #
78
+ # @return [void]
79
+ def load
80
+ return unless File.file?(filename)
81
+
82
+ begin
83
+ pstore.transaction do
84
+ return if pstore[:version] != version
85
+
86
+ self.data = pstore[:data]
87
+ end
88
+ rescue
89
+ FileUtils.rm_f(filename)
90
+ load
91
+ end
92
+ end
93
+
94
+ # Stores the data contained in memory to the filesystem. This method will
95
+ # use the {#data} method to fetch the data that should be written.
96
+ #
97
+ # @return [void]
98
+ def store
99
+ FileUtils.mkdir_p(File.dirname(filename))
100
+
101
+ pstore.transaction do
102
+ pstore[:data] = data
103
+ pstore[:version] = version
104
+ end
105
+ end
106
+
107
+ private
108
+
109
+ def pstore
110
+ @pstore ||= PStore.new(filename)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ # Represents a cache than can be used to store already compiled content,
6
+ # to prevent it from being needlessly recompiled.
7
+ #
8
+ # @api private
9
+ class TextualCompiledContentCache < ::Nanoc::Core::Store
10
+ include Nanoc::Core::ContractsSupport
11
+
12
+ contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
13
+ def initialize(config:)
14
+ super(Nanoc::Core::Store.tmp_path_for(config: config, store_name: 'compiled_content'), 2)
15
+
16
+ @cache = {}
17
+ end
18
+
19
+ contract Nanoc::Core::ItemRep => C::Maybe[C::HashOf[Symbol => Nanoc::Core::Content]]
20
+ # Returns the cached compiled content for the given item representation.
21
+ #
22
+ # This cached compiled content is a hash where the keys are the snapshot
23
+ # names, and the values the compiled content at the given snapshot.
24
+ def [](rep)
25
+ item_cache = @cache[rep.item.identifier] || {}
26
+ item_cache[rep.name]
27
+ end
28
+
29
+ contract Nanoc::Core::ItemRep => C::Bool
30
+ def include?(rep)
31
+ item_cache = @cache[rep.item.identifier] || {}
32
+ item_cache.key?(rep.name)
33
+ end
34
+
35
+ contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::Content] => C::Any
36
+ # Sets the compiled content for the given representation.
37
+ #
38
+ # This cached compiled content is a hash where the keys are the snapshot
39
+ # names, and the values the compiled content at the given snapshot.
40
+ def []=(rep, content)
41
+ # FIXME: once the binary content cache is properly enabled (no longer
42
+ # behind a feature flag), change contract to be TextualContent, rather
43
+ # than Content.
44
+
45
+ @cache[rep.item.identifier] ||= {}
46
+ @cache[rep.item.identifier][rep.name] = content
47
+ end
48
+
49
+ def prune(items:)
50
+ item_identifiers = Set.new(items.map(&:identifier))
51
+
52
+ @cache.each_key do |key|
53
+ # TODO: remove unused item reps
54
+ next if item_identifiers.include?(key)
55
+
56
+ @cache.delete(key)
57
+ end
58
+ end
59
+
60
+ # True if there is cached compiled content available for this item, and
61
+ # all entries are textual.
62
+ def full_cache_available?(rep)
63
+ cache = self[rep]
64
+ cache ? cache.none? { |_snapshot_name, content| content.binary? } : false
65
+ end
66
+
67
+ protected
68
+
69
+ def data
70
+ @cache
71
+ end
72
+
73
+ def data=(new_data)
74
+ @cache = {}
75
+
76
+ new_data.each_pair do |item_identifier, content_per_rep|
77
+ @cache[item_identifier] ||= content_per_rep
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Nanoc
4
4
  module Core
5
- VERSION = '4.11.8'
5
+ VERSION = '4.11.9'
6
6
  end
7
7
  end
data/lib/nanoc/core.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Ruby stdlib
4
+ require 'pstore'
4
5
  require 'singleton'
5
6
  require 'tmpdir'
6
7
 
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.11.8
4
+ version: 4.11.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Defreyne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-08 00:00:00.000000000 Z
11
+ date: 2019-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ddmemoize
@@ -121,11 +121,16 @@ files:
121
121
  - lib/nanoc/core/action_provider.rb
122
122
  - lib/nanoc/core/action_sequence.rb
123
123
  - lib/nanoc/core/action_sequence_builder.rb
124
+ - lib/nanoc/core/action_sequence_store.rb
124
125
  - lib/nanoc/core/aggregate_data_source.rb
126
+ - lib/nanoc/core/binary_compiled_content_cache.rb
125
127
  - lib/nanoc/core/binary_content.rb
126
128
  - lib/nanoc/core/checksum_collection.rb
129
+ - lib/nanoc/core/checksum_store.rb
127
130
  - lib/nanoc/core/checksummer.rb
128
131
  - lib/nanoc/core/code_snippet.rb
132
+ - lib/nanoc/core/compiled_content_cache.rb
133
+ - lib/nanoc/core/compiled_content_store.rb
129
134
  - lib/nanoc/core/configuration-schema.json
130
135
  - lib/nanoc/core/configuration.rb
131
136
  - lib/nanoc/core/content.rb
@@ -137,9 +142,12 @@ files:
137
142
  - lib/nanoc/core/data_source.rb
138
143
  - lib/nanoc/core/dependency.rb
139
144
  - lib/nanoc/core/dependency_props.rb
145
+ - lib/nanoc/core/dependency_store.rb
146
+ - lib/nanoc/core/dependency_tracker.rb
140
147
  - lib/nanoc/core/directed_graph.rb
141
148
  - lib/nanoc/core/document.rb
142
149
  - lib/nanoc/core/error.rb
150
+ - lib/nanoc/core/errors.rb
143
151
  - lib/nanoc/core/identifiable_collection.rb
144
152
  - lib/nanoc/core/identifier.rb
145
153
  - lib/nanoc/core/in_memory_data_source.rb
@@ -147,11 +155,17 @@ files:
147
155
  - lib/nanoc/core/item.rb
148
156
  - lib/nanoc/core/item_collection.rb
149
157
  - lib/nanoc/core/item_rep.rb
158
+ - lib/nanoc/core/item_rep_repo.rb
150
159
  - lib/nanoc/core/layout.rb
151
160
  - lib/nanoc/core/layout_collection.rb
152
161
  - lib/nanoc/core/lazy_value.rb
153
162
  - lib/nanoc/core/notification_center.rb
163
+ - lib/nanoc/core/outdatedness_reasons.rb
164
+ - lib/nanoc/core/outdatedness_rule.rb
165
+ - lib/nanoc/core/outdatedness_status.rb
166
+ - lib/nanoc/core/outdatedness_store.rb
154
167
  - lib/nanoc/core/pattern.rb
168
+ - lib/nanoc/core/prefixed_data_source.rb
155
169
  - lib/nanoc/core/processing_action.rb
156
170
  - lib/nanoc/core/processing_actions.rb
157
171
  - lib/nanoc/core/processing_actions/filter.rb
@@ -160,8 +174,10 @@ files:
160
174
  - lib/nanoc/core/regexp_pattern.rb
161
175
  - lib/nanoc/core/site.rb
162
176
  - lib/nanoc/core/snapshot_def.rb
177
+ - lib/nanoc/core/store.rb
163
178
  - lib/nanoc/core/string_pattern.rb
164
179
  - lib/nanoc/core/temp_filename_factory.rb
180
+ - lib/nanoc/core/textual_compiled_content_cache.rb
165
181
  - lib/nanoc/core/textual_content.rb
166
182
  - lib/nanoc/core/version.rb
167
183
  homepage: https://nanoc.ws/
@@ -183,7 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
199
  - !ruby/object:Gem::Version
184
200
  version: '0'
185
201
  requirements: []
186
- rubygems_version: 3.0.4
202
+ rubygems_version: 3.0.6
187
203
  signing_key:
188
204
  specification_version: 4
189
205
  summary: Core of Nanoc