nanoc 4.7.13 → 4.7.14
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/NEWS.md +6 -0
- data/bin/nanoc +7 -0
- data/lib/nanoc/base/entities/code_snippet.rb +1 -1
- data/lib/nanoc/base/entities/configuration.rb +1 -1
- data/lib/nanoc/base/entities/directed_graph.rb +18 -119
- data/lib/nanoc/base/entities/item.rb +1 -1
- data/lib/nanoc/base/entities/item_collection.rb +1 -1
- data/lib/nanoc/base/entities/item_rep.rb +1 -1
- data/lib/nanoc/base/entities/layout.rb +1 -1
- data/lib/nanoc/base/entities/layout_collection.rb +1 -1
- data/lib/nanoc/base/errors.rb +4 -3
- data/lib/nanoc/base/services/item_rep_selector.rb +40 -61
- data/lib/nanoc/data_sources/filesystem.rb +1 -1
- data/lib/nanoc/rule_dsl/rules_collection.rb +1 -1
- data/lib/nanoc/version.rb +1 -1
- data/spec/nanoc/base/directed_graph_spec.rb +123 -296
- data/spec/nanoc/base/entities/identifiable_collection_spec.rb +2 -2
- data/spec/nanoc/base/entities/item_spec.rb +1 -1
- data/spec/nanoc/base/entities/layout_spec.rb +1 -1
- data/spec/nanoc/base/errors/dependency_cycle_spec.rb +14 -13
- data/spec/nanoc/base/services/item_rep_selector_spec.rb +41 -0
- data/test/base/test_directed_graph.rb +0 -256
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95f87711482fb7881b63a2a4d0a7fca8fecede30
|
4
|
+
data.tar.gz: 6d5b0673fa14f07f4081cc473e24bdd0d558b481
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ea685c54608f0c56af24542324c2cc2f3a4c7f84718c22d3abfde40288695290b45c83106283570be844b5183b12ca82c9a9239fefe34c47b8e73d9414755ad
|
7
|
+
data.tar.gz: cd48b21ea8577192f94e990a462d5237a81ea8a54bf3e60012e8552c69344b43abedafe5d70824d7f3732e95b7963542d59b55a2c331cb1df3e137475d6f89a5
|
data/NEWS.md
CHANGED
data/bin/nanoc
CHANGED
@@ -7,27 +7,28 @@ module Nanoc::Int
|
|
7
7
|
# @example Creating and using a directed graph
|
8
8
|
#
|
9
9
|
# # Create a graph with three vertices
|
10
|
-
# graph = Nanoc::Int::DirectedGraph.new(%w( a b c d ))
|
10
|
+
# graph = Nanoc::Int::DirectedGraph.new(%w( a b c d e ))
|
11
11
|
#
|
12
12
|
# # Add edges
|
13
13
|
# graph.add_edge('a', 'b')
|
14
14
|
# graph.add_edge('b', 'c')
|
15
15
|
# graph.add_edge('c', 'd')
|
16
|
+
# graph.add_edge('b', 'e')
|
16
17
|
#
|
17
|
-
# # Get (direct)
|
18
|
-
# graph.
|
19
|
-
# # => %w(
|
20
|
-
# graph.
|
21
|
-
# # => %w(
|
18
|
+
# # Get (direct) successors
|
19
|
+
# graph.direct_successors_of('a').sort
|
20
|
+
# # => %w( b )
|
21
|
+
# graph.successors_of('a').sort
|
22
|
+
# # => %w( b c d e )
|
22
23
|
#
|
23
24
|
# # Modify edges
|
24
|
-
# graph.
|
25
|
+
# graph.delete_edges_to('c')
|
25
26
|
#
|
26
|
-
# # Get (direct)
|
27
|
-
# graph.
|
28
|
-
# # => %w(
|
29
|
-
# graph.
|
30
|
-
# # => %w( b
|
27
|
+
# # Get (direct) successors again
|
28
|
+
# graph.direct_successors_of('a').sort
|
29
|
+
# # => %w( b )
|
30
|
+
# graph.successors_of('a').sort
|
31
|
+
# # => %w( b e )
|
31
32
|
#
|
32
33
|
# @api private
|
33
34
|
class DirectedGraph
|
@@ -36,8 +37,9 @@ module Nanoc::Int
|
|
36
37
|
# Creates a new directed graph with the given vertices.
|
37
38
|
def initialize(vertices)
|
38
39
|
@vertices = {}
|
39
|
-
|
40
|
-
|
40
|
+
@next_vertex_idx = 0
|
41
|
+
vertices.each do |v|
|
42
|
+
@vertices[v] = @next_vertex_idx.tap { @next_vertex_idx += 1 }
|
41
43
|
end
|
42
44
|
|
43
45
|
@from_graph = {}
|
@@ -45,8 +47,6 @@ module Nanoc::Int
|
|
45
47
|
|
46
48
|
@edge_props = {}
|
47
49
|
|
48
|
-
@roots = Set.new(@vertices.keys)
|
49
|
-
|
50
50
|
invalidate_caches
|
51
51
|
end
|
52
52
|
|
@@ -85,30 +85,6 @@ module Nanoc::Int
|
|
85
85
|
@edge_props[[from, to]] = props
|
86
86
|
end
|
87
87
|
|
88
|
-
@roots.delete(to)
|
89
|
-
|
90
|
-
invalidate_caches
|
91
|
-
end
|
92
|
-
|
93
|
-
# Removes the edge from the first vertex to the second vertex. If the
|
94
|
-
# edge does not exist, nothing is done.
|
95
|
-
#
|
96
|
-
# @param from Start vertex of the edge
|
97
|
-
#
|
98
|
-
# @param to End vertex of the edge
|
99
|
-
#
|
100
|
-
# @return [void]
|
101
|
-
def delete_edge(from, to)
|
102
|
-
@from_graph[from] ||= Set.new
|
103
|
-
@from_graph[from].delete(to)
|
104
|
-
|
105
|
-
@to_graph[to] ||= Set.new
|
106
|
-
@to_graph[to].delete(from)
|
107
|
-
|
108
|
-
@edge_props.delete([from, to])
|
109
|
-
|
110
|
-
@roots.add(to) if @to_graph[to].empty?
|
111
|
-
|
112
88
|
invalidate_caches
|
113
89
|
end
|
114
90
|
|
@@ -120,25 +96,7 @@ module Nanoc::Int
|
|
120
96
|
def add_vertex(v)
|
121
97
|
return if @vertices.key?(v)
|
122
98
|
|
123
|
-
@vertices[v] = @
|
124
|
-
|
125
|
-
@roots << v
|
126
|
-
end
|
127
|
-
|
128
|
-
# Deletes all edges coming from the given vertex.
|
129
|
-
#
|
130
|
-
# @param from Vertex from which all edges should be removed
|
131
|
-
#
|
132
|
-
# @return [void]
|
133
|
-
def delete_edges_from(from)
|
134
|
-
return if @from_graph[from].nil?
|
135
|
-
|
136
|
-
@from_graph[from].each do |to|
|
137
|
-
@to_graph[to].delete(from)
|
138
|
-
@edge_props.delete([from, to])
|
139
|
-
@roots.add(to) if @to_graph[to].empty?
|
140
|
-
end
|
141
|
-
@from_graph.delete(from)
|
99
|
+
@vertices[v] = @next_vertex_idx.tap { @next_vertex_idx += 1 }
|
142
100
|
end
|
143
101
|
|
144
102
|
# Deletes all edges going to the given vertex.
|
@@ -154,64 +112,12 @@ module Nanoc::Int
|
|
154
112
|
@edge_props.delete([from, to])
|
155
113
|
end
|
156
114
|
@to_graph.delete(to)
|
157
|
-
@roots.add(to)
|
158
|
-
end
|
159
|
-
|
160
|
-
# Removes the given vertex from the graph.
|
161
|
-
#
|
162
|
-
# @param v Vertex to remove from the graph
|
163
|
-
#
|
164
|
-
# @return [void]
|
165
|
-
def delete_vertex(v)
|
166
|
-
delete_edges_to(v)
|
167
|
-
delete_edges_from(v)
|
168
115
|
|
169
|
-
|
170
|
-
@roots.delete(v)
|
116
|
+
invalidate_caches
|
171
117
|
end
|
172
118
|
|
173
119
|
# @group Querying the graph
|
174
120
|
|
175
|
-
# Returns a cycle if there is any.
|
176
|
-
def any_cycle
|
177
|
-
all_paths.lazy.map { |path| cycle_in_path(path) }.find(&:itself)
|
178
|
-
end
|
179
|
-
|
180
|
-
# Given a potentially closed path, returns a cycle if there is any.
|
181
|
-
def cycle_in_path(path)
|
182
|
-
vertex = path.last
|
183
|
-
index = path.index(vertex)
|
184
|
-
|
185
|
-
if index < path.size - 1
|
186
|
-
path[index..-2]
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
# Yields all paths (including potentially closed ones).
|
191
|
-
def all_paths
|
192
|
-
Enumerator.new do |y|
|
193
|
-
@vertices.keys.each do |vertex|
|
194
|
-
dfs_from(vertex) do |path|
|
195
|
-
y << path
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
# Yields all paths (including potentially closed ones) starting from the given vertex.
|
202
|
-
def dfs_from(vertex, path_so_far = [])
|
203
|
-
new_path = path_so_far + [vertex]
|
204
|
-
yield(new_path)
|
205
|
-
|
206
|
-
unless path_so_far.include?(vertex)
|
207
|
-
direct_successors_of(vertex).each do |next_vertex|
|
208
|
-
dfs_from(next_vertex, new_path) do |path|
|
209
|
-
yield(path)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
121
|
# Returns the direct predecessors of the given vertex, i.e. the vertices
|
216
122
|
# x where there is an edge from x to the given vertex y.
|
217
123
|
#
|
@@ -275,13 +181,6 @@ module Nanoc::Int
|
|
275
181
|
result
|
276
182
|
end
|
277
183
|
|
278
|
-
# Returns all root vertices, i.e. vertices where no edge points to.
|
279
|
-
#
|
280
|
-
# @return [Set] The set of all root vertices in this graph.
|
281
|
-
def roots
|
282
|
-
@roots
|
283
|
-
end
|
284
|
-
|
285
184
|
private
|
286
185
|
|
287
186
|
# Invalidates cached data. This method should be called when the internal
|
data/lib/nanoc/base/errors.rb
CHANGED
@@ -71,13 +71,14 @@ module Nanoc::Int
|
|
71
71
|
# Error that is raised during site compilation when an item (directly or
|
72
72
|
# indirectly) includes its own item content, leading to endless recursion.
|
73
73
|
class DependencyCycle < Generic
|
74
|
-
def initialize(
|
75
|
-
|
74
|
+
def initialize(stack)
|
75
|
+
start_idx = stack.index(stack.last)
|
76
|
+
cycle = stack[start_idx..-2]
|
76
77
|
|
77
78
|
msg_bits = []
|
78
79
|
msg_bits << 'The site cannot be compiled because there is a dependency cycle:'
|
79
80
|
msg_bits << ''
|
80
|
-
cycle.
|
81
|
+
cycle.each.with_index do |r, i|
|
81
82
|
msg_bits << " (#{i + 1}) item #{r.item.identifier}, rep #{r.name.inspect}, uses compiled content of"
|
82
83
|
end
|
83
84
|
msg_bits << msg_bits.pop + ' (1)'
|
@@ -9,79 +9,58 @@ module Nanoc::Int
|
|
9
9
|
@reps = reps
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
prio_dependent = Set.new
|
18
|
-
prio_in_progress = Set.new
|
19
|
-
loop do
|
20
|
-
rep = find(graph, prio_dependent, prio_in_progress)
|
21
|
-
break if NONE.equal?(rep)
|
22
|
-
|
23
|
-
begin
|
24
|
-
prio_in_progress << rep
|
25
|
-
yield(rep)
|
26
|
-
prio_in_progress.delete(rep)
|
27
|
-
graph.delete_vertex(rep)
|
28
|
-
rescue => e
|
29
|
-
handle_error(e, rep, graph, prio_dependent)
|
30
|
-
end
|
12
|
+
class MicroGraph
|
13
|
+
def initialize(reps)
|
14
|
+
@reps = Set.new(reps)
|
15
|
+
@stack = []
|
31
16
|
end
|
32
17
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
NONE
|
42
|
-
elsif prio_dependent.any?
|
43
|
-
find_prio(graph, prio_dependent, prio_dependent, prio_in_progress)
|
44
|
-
elsif prio_in_progress.any?
|
45
|
-
find_prio(graph, prio_in_progress, prio_dependent, prio_in_progress)
|
46
|
-
else
|
47
|
-
graph.roots.each { |e| break e }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def find_prio(graph, prio, prio_dependent, prio_in_progress)
|
52
|
-
until prio.empty?
|
53
|
-
rep = prio.each { |e| break e }
|
54
|
-
if graph.roots.include?(rep)
|
55
|
-
return rep
|
18
|
+
def next
|
19
|
+
if @stack.any?
|
20
|
+
@stack.last
|
21
|
+
elsif @reps.any?
|
22
|
+
@reps.each { |rep| break rep }.tap do |rep|
|
23
|
+
@reps.delete(rep)
|
24
|
+
@stack.push(rep)
|
25
|
+
end
|
56
26
|
else
|
57
|
-
|
27
|
+
nil
|
58
28
|
end
|
59
29
|
end
|
60
30
|
|
61
|
-
|
62
|
-
|
31
|
+
def mark_ok
|
32
|
+
@stack.pop
|
33
|
+
end
|
63
34
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
e.unwrap
|
68
|
-
else
|
69
|
-
e
|
35
|
+
def mark_failed(dep)
|
36
|
+
if @stack.include?(dep)
|
37
|
+
raise Nanoc::Int::Errors::DependencyCycle.new(@stack + [dep])
|
70
38
|
end
|
71
39
|
|
72
|
-
|
73
|
-
|
74
|
-
else
|
75
|
-
raise(e)
|
40
|
+
@reps.delete(dep)
|
41
|
+
@stack.push(dep)
|
76
42
|
end
|
77
43
|
end
|
78
44
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
45
|
+
def each
|
46
|
+
mg = MicroGraph.new(@reps)
|
47
|
+
|
48
|
+
loop do
|
49
|
+
rep = mg.next
|
50
|
+
break if rep.nil?
|
51
|
+
|
52
|
+
begin
|
53
|
+
yield(rep)
|
54
|
+
mg.mark_ok
|
55
|
+
rescue => e
|
56
|
+
actual_error = e.is_a?(Nanoc::Int::Errors::CompilationError) ? e.unwrap : e
|
57
|
+
|
58
|
+
if actual_error.is_a?(Nanoc::Int::Errors::UnmetDependency)
|
59
|
+
mg.mark_failed(actual_error.rep)
|
60
|
+
else
|
61
|
+
raise(e)
|
62
|
+
end
|
63
|
+
end
|
85
64
|
end
|
86
65
|
end
|
87
66
|
end
|