nanoc-core 4.11.8 → 4.11.9

Sign up to get free protection for your applications and to get access to all the features.
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