nanoc3 3.0.9 → 3.1.0a1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/NEWS.md +360 -0
- data/README.md +85 -0
- data/Rakefile +2 -2
- data/bin/nanoc3 +0 -4
- data/lib/nanoc3/base/code_snippet.rb +14 -6
- data/lib/nanoc3/base/compiler.rb +68 -49
- data/lib/nanoc3/base/compiler_dsl.rb +70 -29
- data/lib/nanoc3/base/context.rb +47 -0
- data/lib/nanoc3/base/core_ext/array.rb +4 -0
- data/lib/nanoc3/base/core_ext/hash.rb +5 -1
- data/lib/nanoc3/base/core_ext/string.rb +2 -0
- data/lib/nanoc3/base/data_source.rb +132 -96
- data/lib/nanoc3/base/dependency_tracker.rb +160 -185
- data/lib/nanoc3/base/directed_graph.rb +252 -0
- data/lib/nanoc3/base/errors.rb +52 -4
- data/lib/nanoc3/base/filter.rb +43 -28
- data/lib/nanoc3/base/item.rb +93 -25
- data/lib/nanoc3/base/item_rep.rb +166 -55
- data/lib/nanoc3/base/layout.rb +16 -13
- data/lib/nanoc3/base/notification_center.rb +28 -12
- data/lib/nanoc3/base/plugin_registry.rb +158 -0
- data/lib/nanoc3/base/rule.rb +27 -8
- data/lib/nanoc3/base/rule_context.rb +59 -46
- data/lib/nanoc3/base/site.rb +124 -77
- data/lib/nanoc3/base.rb +7 -2
- data/lib/nanoc3/cli/base.rb +4 -1
- data/lib/nanoc3/cli/commands/autocompile.rb +5 -4
- data/lib/nanoc3/cli/commands/compile.rb +28 -7
- data/lib/nanoc3/cli/commands/create_item.rb +1 -1
- data/lib/nanoc3/cli/commands/create_layout.rb +1 -1
- data/lib/nanoc3/cli/commands/create_site.rb +46 -22
- data/lib/nanoc3/cli/commands/debug.rb +100 -0
- data/lib/nanoc3/cli/commands/help.rb +1 -1
- data/lib/nanoc3/cli/commands/info.rb +1 -1
- data/lib/nanoc3/cli/commands/view.rb +85 -0
- data/lib/nanoc3/cli/commands.rb +2 -0
- data/lib/nanoc3/cli/logger.rb +7 -0
- data/lib/nanoc3/cli.rb +0 -3
- data/lib/nanoc3/data_sources/{delicious.rb → deprecated/delicious.rb} +1 -24
- data/lib/nanoc3/data_sources/{last_fm.rb → deprecated/last_fm.rb} +1 -27
- data/lib/nanoc3/data_sources/{twitter.rb → deprecated/twitter.rb} +1 -14
- data/lib/nanoc3/data_sources/filesystem.rb +188 -176
- data/lib/nanoc3/data_sources/filesystem_unified.rb +107 -0
- data/lib/nanoc3/data_sources/filesystem_verbose.rb +80 -0
- data/lib/nanoc3/data_sources.rb +18 -9
- data/lib/nanoc3/extra/core_ext/enumerable.rb +39 -0
- data/lib/nanoc3/extra/core_ext/time.rb +2 -2
- data/lib/nanoc3/extra/core_ext.rb +1 -0
- data/lib/nanoc3/extra/deployers/rsync.rb +49 -3
- data/lib/nanoc3/extra/file_proxy.rb +7 -0
- data/lib/nanoc3/extra/vcs.rb +25 -24
- data/lib/nanoc3/extra/vcses/bazaar.rb +4 -0
- data/lib/nanoc3/extra/vcses/dummy.rb +4 -0
- data/lib/nanoc3/extra/vcses/git.rb +4 -0
- data/lib/nanoc3/extra/vcses/mercurial.rb +4 -0
- data/lib/nanoc3/extra/vcses/subversion.rb +4 -0
- data/lib/nanoc3/extra.rb +4 -1
- data/lib/nanoc3/filters/erb.rb +1 -1
- data/lib/nanoc3/filters/erubis.rb +1 -1
- data/lib/nanoc3/filters/haml.rb +1 -1
- data/lib/nanoc3/filters/kramdown.rb +14 -0
- data/lib/nanoc3/filters/maruku.rb +1 -1
- data/lib/nanoc3/filters/rainpress.rb +1 -1
- data/lib/nanoc3/filters/rdiscount.rb +3 -1
- data/lib/nanoc3/filters.rb +2 -0
- data/lib/nanoc3/helpers/blogging.rb +91 -75
- data/lib/nanoc3/helpers/breadcrumbs.rb +18 -10
- data/lib/nanoc3/helpers/capturing.rb +24 -29
- data/lib/nanoc3/helpers/filtering.rb +20 -17
- data/lib/nanoc3/helpers/html_escape.rb +7 -4
- data/lib/nanoc3/helpers/link_to.rb +51 -41
- data/lib/nanoc3/helpers/rendering.rb +15 -8
- data/lib/nanoc3/helpers/tagging.rb +27 -21
- data/lib/nanoc3/helpers/text.rb +12 -8
- data/lib/nanoc3/helpers/xml_sitemap.rb +13 -15
- data/lib/nanoc3/tasks/deploy/rsync.rake +4 -1
- data/lib/nanoc3/tasks.rb +2 -1
- data/lib/nanoc3.rb +24 -1
- metadata +43 -87
- data/NEWS.rdoc +0 -328
- data/README.rdoc +0 -83
- data/lib/nanoc3/base/plugin.rb +0 -88
- data/lib/nanoc3/base/preprocessor_context.rb +0 -37
- data/lib/nanoc3/data_sources/filesystem_combined.rb +0 -214
- data/lib/nanoc3/data_sources/filesystem_common.rb +0 -22
- data/lib/nanoc3/data_sources/filesystem_compact.rb +0 -256
- data/lib/nanoc3/extra/context.rb +0 -24
- data/lib/nanoc3/package.rb +0 -107
- data/vendor/cri/ChangeLog +0 -0
- data/vendor/cri/LICENSE +0 -19
- data/vendor/cri/NEWS +0 -0
- data/vendor/cri/README +0 -4
- data/vendor/cri/Rakefile +0 -25
- data/vendor/cri/lib/cri/base.rb +0 -153
- data/vendor/cri/lib/cri/command.rb +0 -105
- data/vendor/cri/lib/cri/core_ext/string.rb +0 -41
- data/vendor/cri/lib/cri/core_ext.rb +0 -8
- data/vendor/cri/lib/cri/option_parser.rb +0 -186
- data/vendor/cri/lib/cri.rb +0 -12
- data/vendor/cri/test/test_base.rb +0 -6
- data/vendor/cri/test/test_command.rb +0 -6
- data/vendor/cri/test/test_core_ext.rb +0 -21
- data/vendor/cri/test/test_option_parser.rb +0 -279
@@ -0,0 +1,252 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3
|
4
|
+
|
5
|
+
# Nanoc3::DirectedGraph represents a directed graph. It is used by the
|
6
|
+
# dependency tracker for storing and querying dependencies between items.
|
7
|
+
# Internally, the graph will be stored as an adjacency matrix. For this,
|
8
|
+
# the {Nanoc3::DirectedGraph::SquareBooleanMatrix} class is used.
|
9
|
+
#
|
10
|
+
# @example Creating and using a directed graph
|
11
|
+
#
|
12
|
+
# # Create a graph with three vertices
|
13
|
+
# graph = DirectedGraph.new(%w( a b c d ))
|
14
|
+
#
|
15
|
+
# # Add edges
|
16
|
+
# graph.add_edge('a', 'b')
|
17
|
+
# graph.add_edge('b', 'c')
|
18
|
+
# graph.add_edge('c', 'd')
|
19
|
+
#
|
20
|
+
# # Get (direct) predecessors
|
21
|
+
# graph.direct_predecessors_of('d').sort
|
22
|
+
# # => %w( c )
|
23
|
+
# graph.predecessors_of('d').sort
|
24
|
+
# # => %w( a b c )
|
25
|
+
#
|
26
|
+
# # Modify edges
|
27
|
+
# graph.remove_edge('a', 'b')
|
28
|
+
#
|
29
|
+
# # Get (direct) predecessors again
|
30
|
+
# graph.direct_predecessors_of('d').sort
|
31
|
+
# # => %w( c )
|
32
|
+
# graph.predecessors_of('d').sort
|
33
|
+
# # => %w( b c )
|
34
|
+
class DirectedGraph
|
35
|
+
|
36
|
+
# Nanoc3::DirectedGraph::SquareBooleanMatrix is, as the name says, a
|
37
|
+
# square matrix that contains boolean values. It is used as an adjacency
|
38
|
+
# matrix by the {Nanoc3::DirectedGraph} class.
|
39
|
+
class SquareBooleanMatrix
|
40
|
+
|
41
|
+
# Creates a new matrix with the given number of rows/columns.
|
42
|
+
#
|
43
|
+
# @param [Number] size The number of elements along both sides of the
|
44
|
+
# matrix (in other words, the square root of the number of elements)
|
45
|
+
def initialize(size)
|
46
|
+
@size = size
|
47
|
+
end
|
48
|
+
|
49
|
+
# Gets the value at the given x/y coordinates.
|
50
|
+
#
|
51
|
+
# @param [Number] x The X coordinate
|
52
|
+
# @param [Number] y The Y coordinate
|
53
|
+
#
|
54
|
+
# @return The value at the given coordinates
|
55
|
+
def [](x, y)
|
56
|
+
@data ||= {}
|
57
|
+
@data[x] ||= {}
|
58
|
+
@data[x].has_key?(y) ? @data[x][y] : false
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sets the value at the given x/y coordinates.
|
62
|
+
#
|
63
|
+
# @param [Number] x The X coordinate
|
64
|
+
# @param [Number] y The Y coordinate
|
65
|
+
# @param value The value to set at the given coordinates
|
66
|
+
#
|
67
|
+
# @return [void]
|
68
|
+
def []=(x, y, value)
|
69
|
+
@data ||= {}
|
70
|
+
@data[x] ||= {}
|
71
|
+
@data[x][y] = value
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns a string representing this matrix in ASCII art.
|
75
|
+
#
|
76
|
+
# @return [String] The string representation of this matrix
|
77
|
+
def to_s
|
78
|
+
s = ''
|
79
|
+
|
80
|
+
# Calculate column width
|
81
|
+
width = (@size-1).to_s.size
|
82
|
+
|
83
|
+
# Add header
|
84
|
+
s << ' ' + ' '*width + ' '
|
85
|
+
@size.times { |i| s << '| ' + format("%#{width}i", i) + ' ' }
|
86
|
+
s << "\n"
|
87
|
+
|
88
|
+
# Add rows
|
89
|
+
@size.times do |x|
|
90
|
+
# Add line
|
91
|
+
s << '-' + '-'*width + '-'
|
92
|
+
@size.times { |i| s << '+-' + '-'*width + '-' }
|
93
|
+
s << "\n"
|
94
|
+
|
95
|
+
# Add actual row
|
96
|
+
s << ' ' + format("%#{width}i", x)+ ' '
|
97
|
+
@size.times do |y|
|
98
|
+
s << '| ' + format("%#{width}s", self[x, y] ? '*' : ' ') + ' '
|
99
|
+
end
|
100
|
+
s << "\n"
|
101
|
+
end
|
102
|
+
|
103
|
+
# Done
|
104
|
+
s
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
# The list of vertices in this graph.
|
110
|
+
#
|
111
|
+
# @return [Array]
|
112
|
+
attr_reader :vertices
|
113
|
+
|
114
|
+
# Creates a new directed graph with the given vertices.
|
115
|
+
def initialize(vertices)
|
116
|
+
@vertices = vertices
|
117
|
+
|
118
|
+
@matrix = SquareBooleanMatrix.new(@vertices.size)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Adds an edge from the first vertex to the second vertex.
|
122
|
+
#
|
123
|
+
# @param from Vertex where the edge should start
|
124
|
+
# @param to Vertex where the edge should end
|
125
|
+
#
|
126
|
+
# @return [void]
|
127
|
+
def add_edge(from, to)
|
128
|
+
from_index, to_index = indices_of(from, to)
|
129
|
+
@matrix[from_index, to_index] = true
|
130
|
+
end
|
131
|
+
|
132
|
+
# Removes the edge from the first vertex to the second vertex. If the
|
133
|
+
# edge does not exist, nothing is done.
|
134
|
+
#
|
135
|
+
# @param from Start vertex of the edge
|
136
|
+
# @param to End vertex of the edge
|
137
|
+
#
|
138
|
+
# @return [void]
|
139
|
+
def remove_edge(from, to)
|
140
|
+
from_index, to_index = indices_of(from, to)
|
141
|
+
@matrix[from_index, to_index] = false
|
142
|
+
end
|
143
|
+
|
144
|
+
# Returns the direct predecessors of the given vertex, i.e. the vertices
|
145
|
+
# x where there is an edge from x to the given vertex y.
|
146
|
+
#
|
147
|
+
# @param to The vertex of which the predecessors should be calculated
|
148
|
+
#
|
149
|
+
# @return [Array] Direct predecessors of the given vertex
|
150
|
+
def direct_predecessors_of(to)
|
151
|
+
@vertices.select do |from|
|
152
|
+
from_index, to_index = indices_of(from, to)
|
153
|
+
@matrix[from_index, to_index] == true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns the direct successors of the given vertex, i.e. the vertices y
|
158
|
+
# where there is an edge from the given vertex x to y.
|
159
|
+
#
|
160
|
+
# @param from The vertex of which the successors should be calculated
|
161
|
+
#
|
162
|
+
# @return [Array] Direct successors of the given vertex
|
163
|
+
def direct_successors_of(from)
|
164
|
+
@vertices.select do |to|
|
165
|
+
from_index, to_index = indices_of(from, to)
|
166
|
+
@matrix[from_index, to_index] == true
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns the predecessors of the given vertex, i.e. the vertices x for
|
171
|
+
# which there is a path from x to the given vertex y.
|
172
|
+
#
|
173
|
+
# @param to The vertex of which the predecessors should be calculated
|
174
|
+
#
|
175
|
+
# @return [Array] Predecessors of the given vertex
|
176
|
+
def predecessors_of(to)
|
177
|
+
recursively_find_vertices(to, :direct_predecessors_of)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Returns the successors of the given vertex, i.e. the vertices y for
|
181
|
+
# which there is a path from the given vertex x to y.
|
182
|
+
#
|
183
|
+
# @param from The vertex of which the successors should be calculated
|
184
|
+
#
|
185
|
+
# @return [Array] Successors of the given vertex
|
186
|
+
def successors_of(from)
|
187
|
+
recursively_find_vertices(from, :direct_successors_of)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Returns an array of tuples representing the edges. The result of this
|
191
|
+
# method may take a while to compute and should be cached if possible.
|
192
|
+
#
|
193
|
+
# @return [Array] The list of all edges in this graph.
|
194
|
+
def edges
|
195
|
+
result = []
|
196
|
+
|
197
|
+
@vertices.each do |from|
|
198
|
+
@vertices.each do |to|
|
199
|
+
from_index, to_index = indices_of(from, to)
|
200
|
+
next if @matrix[from_index, to_index] == false
|
201
|
+
|
202
|
+
result << [ from_index, to_index ]
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
result
|
207
|
+
end
|
208
|
+
|
209
|
+
# Returns a string representing this graph in ASCII art (or, to be more
|
210
|
+
# precise, the string representation of the matrix backing this graph).
|
211
|
+
#
|
212
|
+
# @return [String] The string representation of this graph
|
213
|
+
def to_s
|
214
|
+
@matrix.to_s
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
# Returns an array of indices for the given vertices. Raises an error if
|
220
|
+
# one or more given objects are not vertices.
|
221
|
+
def indices_of(*vertices)
|
222
|
+
vertices.map { |v| @vertices.index(v) or raise RuntimeError, "#{v.inspect} not a vertex" }
|
223
|
+
end
|
224
|
+
|
225
|
+
# Recursively finds vertices, starting at the vertex start, using the
|
226
|
+
# given method, which should be a symbol to a method that takes a vertex
|
227
|
+
# and returns related vertices (e.g. predecessors, successors).
|
228
|
+
def recursively_find_vertices(start, method)
|
229
|
+
all_vertices = []
|
230
|
+
|
231
|
+
processed_vertices = []
|
232
|
+
unprocessed_vertices = [ start ]
|
233
|
+
|
234
|
+
until unprocessed_vertices.empty?
|
235
|
+
# Get next unprocessed vertex
|
236
|
+
vertex = unprocessed_vertices.pop
|
237
|
+
next if processed_vertices.include?(vertex)
|
238
|
+
processed_vertices << vertex
|
239
|
+
|
240
|
+
# Add predecessors of this vertex
|
241
|
+
send(method, vertex).each do |v|
|
242
|
+
all_vertices << v unless all_vertices.include?(v)
|
243
|
+
unprocessed_vertices << v
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
all_vertices
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
data/lib/nanoc3/base/errors.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module Nanoc3
|
4
4
|
|
5
|
+
# Module that contains all nanoc-specific errors.
|
5
6
|
module Errors
|
6
7
|
|
7
8
|
# Generic error. Superclass for all nanoc-specific errors.
|
@@ -11,83 +12,130 @@ module Nanoc3
|
|
11
12
|
# Error that is raised when a site is loaded that uses a data source with
|
12
13
|
# an unknown identifier.
|
13
14
|
class UnknownDataSource < Generic
|
15
|
+
|
16
|
+
# @param [String] data_source_name The data source name for which no
|
17
|
+
# data source could be found
|
14
18
|
def initialize(data_source_name)
|
15
19
|
super("The data source specified in the site's configuration file, #{data_source_name}, does not exist.")
|
16
20
|
end
|
21
|
+
|
17
22
|
end
|
18
23
|
|
19
24
|
# Error that is raised during site compilation when an item uses a layout
|
20
25
|
# that is not present in the site.
|
21
26
|
class UnknownLayout < Generic
|
27
|
+
|
28
|
+
# @param [String] layout_identifier The layout identifier for which no
|
29
|
+
# layout could be found
|
22
30
|
def initialize(layout_identifier)
|
23
31
|
super("The site does not have a layout with identifier '#{layout_identifier}'.")
|
24
32
|
end
|
33
|
+
|
25
34
|
end
|
26
35
|
|
27
36
|
# Error that is raised during site compilation when an item uses a filter
|
28
37
|
# that is not known.
|
29
38
|
class UnknownFilter < Generic
|
39
|
+
|
40
|
+
# @param [Symbol] filter_name The filter name for which no filter could
|
41
|
+
# be found
|
30
42
|
def initialize(filter_name)
|
31
43
|
super("The requested filter, #{filter_name}, does not exist.")
|
32
44
|
end
|
45
|
+
|
33
46
|
end
|
34
47
|
|
35
48
|
# Error that is raised during site compilation when a layout is compiled
|
36
49
|
# for which the filter cannot be determined. This is similar to the
|
37
|
-
#
|
50
|
+
# {UnknownFilter} error, but specific for filters for layouts.
|
38
51
|
class CannotDetermineFilter < Generic
|
52
|
+
|
53
|
+
# @param [String] layout_identifier The identifier of the layout for
|
54
|
+
# which the filter could not be determined
|
39
55
|
def initialize(layout_identifier)
|
40
56
|
super("The filter to be used for the '#{layout_identifier}' could not be determined. Make sure the layout does have a filter.")
|
41
57
|
end
|
58
|
+
|
42
59
|
end
|
43
60
|
|
44
61
|
# Error that is raised when data is requested when the data is not yet
|
45
|
-
# available (possibly due to a missing
|
62
|
+
# available (possibly due to a missing {Nanoc3::Site#load_data}).
|
46
63
|
class DataNotYetAvailable < Generic
|
64
|
+
|
65
|
+
# @param [String] type The name of the data type that is not yet
|
66
|
+
# available. For example: `"site"`, `"items"`.
|
67
|
+
#
|
68
|
+
# @param [Boolean] plural True if the given type is plural, false
|
69
|
+
# otherwise. This only has an effect on the exception message. For
|
70
|
+
# example, if the given type is `"site"`, plural would be `false`; if
|
71
|
+
# the given type is `"items"`, plural would be `true`.
|
47
72
|
def initialize(type, plural)
|
48
|
-
super("#{type} #{plural ? 'are' : 'is'} not available yet. You may be missing a
|
73
|
+
super("#{type} #{plural ? 'are' : 'is'} not available yet. You may be missing a Nanoc3::Site#load_data call.")
|
49
74
|
end
|
75
|
+
|
50
76
|
end
|
51
77
|
|
52
78
|
# Error that is raised during site compilation when an item (directly or
|
53
79
|
# indirectly) includes its own item content, leading to endless recursion.
|
54
80
|
class RecursiveCompilation < Generic
|
81
|
+
|
82
|
+
# @param [Array<Nanoc3::ItemRep>] reps A list of item representations
|
83
|
+
# that mutually depend on each other
|
55
84
|
def initialize(reps)
|
56
85
|
super("The site cannot be compiled because the following items mutually depend on each other: #{reps.inspect}.")
|
57
86
|
end
|
87
|
+
|
58
88
|
end
|
59
89
|
|
60
90
|
# Error that is raised when no rules file can be found in the current
|
61
91
|
# working directory.
|
62
92
|
class NoRulesFileFound < Generic
|
93
|
+
|
63
94
|
def initialize
|
64
95
|
super("This site does not have a rules file, which is required for nanoc sites.")
|
65
96
|
end
|
97
|
+
|
66
98
|
end
|
67
99
|
|
68
100
|
# Error that is raised when no compilation rule that can be applied to the
|
69
101
|
# current item can be found.
|
70
102
|
class NoMatchingCompilationRuleFound < Generic
|
103
|
+
|
104
|
+
# @param [Nanoc3::Item] item The item for which no compilation rule
|
105
|
+
# could be found
|
71
106
|
def initialize(item)
|
72
107
|
super("No compilation rules were found for the '#{item.identifier}' item.")
|
73
108
|
end
|
109
|
+
|
74
110
|
end
|
75
111
|
|
76
112
|
# Error that is raised when no routing rule that can be applied to the
|
77
113
|
# current item can be found.
|
78
114
|
class NoMatchingRoutingRuleFound < Generic
|
115
|
+
|
116
|
+
# @param [Nanoc3::Item] item The item for which no routing rule could be
|
117
|
+
# found
|
79
118
|
def initialize(rep)
|
80
119
|
super("No routing rules were found for the '#{rep.item.identifier}' item (rep '#{rep.name}').")
|
81
120
|
end
|
121
|
+
|
82
122
|
end
|
83
123
|
|
84
|
-
# Error that is raised when an rep cannot be compiled because it depends
|
124
|
+
# Error that is raised when an rep cannot be compiled because it depends
|
125
|
+
# on other representations.
|
85
126
|
class UnmetDependency < Generic
|
127
|
+
|
128
|
+
# @return [Nanoc3::ItemRep] The item representation that cannot yet be
|
129
|
+
# compiled
|
86
130
|
attr_reader :rep
|
131
|
+
|
132
|
+
# @param [Nanoc3::ItemRep] The item representation that cannot yet be
|
133
|
+
# compiled
|
87
134
|
def initialize(rep)
|
88
135
|
@rep = rep
|
89
136
|
super("The '#{rep.item.identifier}' item (rep '#{rep.name}') cannot currently be compiled yet due to an unmet dependency.")
|
90
137
|
end
|
138
|
+
|
91
139
|
end
|
92
140
|
|
93
141
|
end
|
data/lib/nanoc3/base/filter.rb
CHANGED
@@ -2,49 +2,64 @@
|
|
2
2
|
|
3
3
|
module Nanoc3
|
4
4
|
|
5
|
-
# Nanoc3::Filter is responsible for filtering items. It is
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
5
|
+
# Nanoc3::Filter is responsible for filtering items. It is the superclass
|
6
|
+
# for all textual filters.
|
7
|
+
#
|
8
|
+
# When creating a filter with a hash containing assigned variables, those
|
9
|
+
# variables will be made available in the `@assigns` instance variable and
|
10
|
+
# the {#assigns} method. The assigns itself will also be available as
|
11
|
+
# instance variables and instance methods.
|
12
|
+
#
|
13
|
+
# @example Accessing assigns in different ways
|
14
|
+
#
|
15
|
+
# filter = SomeFilter.new({ :foo => 'bar' })
|
16
|
+
# filter.instance_eval { @assigns[:foo] }
|
17
|
+
# # => 'bar'
|
18
|
+
# filter.instance_eval { assigns[:foo] }
|
19
|
+
# # => 'bar'
|
20
|
+
# filter.instance_eval { @foo }
|
21
|
+
# # => 'bar'
|
22
|
+
# filter.instance_eval { foo }
|
23
|
+
# # => 'bar'
|
24
|
+
#
|
25
|
+
# @abstract Subclass and override {#run} to implement a custom filter.
|
26
|
+
class Filter < Context
|
9
27
|
|
10
28
|
# A hash containing variables that will be made available during
|
11
29
|
# filtering.
|
12
|
-
attr_reader :assigns
|
13
|
-
|
14
|
-
# Creates a new filter with the given assigns.
|
15
30
|
#
|
16
|
-
#
|
17
|
-
|
18
|
-
def initialize(a_assigns={})
|
19
|
-
@assigns = a_assigns
|
20
|
-
end
|
31
|
+
# @return [Hash]
|
32
|
+
attr_reader :assigns
|
21
33
|
|
22
|
-
|
23
|
-
def self.identifiers(*identifiers)
|
24
|
-
Nanoc3::Filter.register(self, *identifiers)
|
25
|
-
end
|
34
|
+
extend Nanoc3::PluginRegistry::PluginMethods
|
26
35
|
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
Nanoc3::Plugin.register(Nanoc3::Filter, class_or_name, *identifiers)
|
36
|
+
# Creates a new filter that has access to the given assigns.
|
37
|
+
#
|
38
|
+
# @param [Hash] a_assigns A hash containing variables that should be made
|
39
|
+
# available during filtering.
|
40
|
+
def initialize(hash={})
|
41
|
+
@assigns = hash
|
42
|
+
super
|
35
43
|
end
|
36
44
|
|
37
|
-
# Runs the filter
|
45
|
+
# Runs the filter on the given content.
|
46
|
+
#
|
47
|
+
# @abstract
|
38
48
|
#
|
39
|
-
#
|
49
|
+
# @param [String] content The unprocessed content that should be filtered.
|
40
50
|
#
|
41
|
-
#
|
51
|
+
# @param [Hash] params A hash containing parameters. Filter subclasses can
|
52
|
+
# use these parameters to allow modifying the filter's behaviour.
|
53
|
+
#
|
54
|
+
# @return [String] The filtered content
|
42
55
|
def run(content, params={})
|
43
56
|
raise NotImplementedError.new("Nanoc3::Filter subclasses must implement #run")
|
44
57
|
end
|
45
58
|
|
46
59
|
# Returns the filename associated with the item that is being filtered.
|
47
|
-
#
|
60
|
+
# It is in the format `item <identifier> (rep <name>)`.
|
61
|
+
#
|
62
|
+
# @return [String] The filename
|
48
63
|
def filename
|
49
64
|
if assigns[:layout]
|
50
65
|
"layout #{assigns[:layout].identifier}"
|
data/lib/nanoc3/base/item.rb
CHANGED
@@ -2,47 +2,48 @@
|
|
2
2
|
|
3
3
|
module Nanoc3
|
4
4
|
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# time to speed up compilation.
|
5
|
+
# Represents a compileable item in a site. It has content and attributes, as
|
6
|
+
# well as an identifier (which starts and ends with a slash). It can also
|
7
|
+
# store the modification time to speed up compilation.
|
8
8
|
class Item
|
9
9
|
|
10
|
-
#
|
10
|
+
# @return [Nanoc3::Site] The site this item belongs to
|
11
11
|
attr_accessor :site
|
12
12
|
|
13
|
-
#
|
13
|
+
# @return [Hash] This item's attributes
|
14
14
|
attr_accessor :attributes
|
15
15
|
|
16
|
-
# This item's identifier
|
16
|
+
# @return [String] This item's identifier
|
17
17
|
attr_accessor :identifier
|
18
18
|
|
19
|
-
# The time when this item was last modified
|
19
|
+
# @return [Time] The time when this item was last modified
|
20
20
|
attr_reader :mtime
|
21
21
|
|
22
|
-
# This item
|
22
|
+
# @return [Array<Nanoc3::ItemRep>] This item’s list of item reps
|
23
23
|
attr_reader :reps
|
24
24
|
|
25
|
-
# This item's raw, uncompiled content
|
25
|
+
# @return [String] This item's raw, uncompiled content
|
26
26
|
attr_reader :raw_content
|
27
27
|
|
28
|
-
# The parent item of this item. This can be
|
28
|
+
# @return [Nanoc3::Item, nil] The parent item of this item. This can be
|
29
|
+
# nil even for non-root items.
|
29
30
|
attr_accessor :parent
|
30
31
|
|
31
|
-
# The child items of this item
|
32
|
+
# @return [Array<Nanoc3::Item>] The child items of this item
|
32
33
|
attr_accessor :children
|
33
34
|
|
34
|
-
#
|
35
|
-
|
35
|
+
# @return [Boolean] Whether or not this item is outdated because of its
|
36
|
+
# dependencies are outdated
|
37
|
+
attr_accessor :outdated_due_to_dependencies
|
38
|
+
alias_method :outdated_due_to_dependencies?, :outdated_due_to_dependencies
|
36
39
|
|
37
|
-
#
|
40
|
+
# @param [String] raw_content The uncompiled item content.
|
38
41
|
#
|
39
|
-
#
|
42
|
+
# @param [Hash] attributes A hash containing this item's attributes.
|
40
43
|
#
|
41
|
-
#
|
44
|
+
# @param [String] identifier This item's identifier.
|
42
45
|
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# +mtime+:: The time when this item was last modified.
|
46
|
+
# @param [String, nil] mtime The time when this item was last modified.
|
46
47
|
def initialize(raw_content, attributes, identifier, mtime=nil)
|
47
48
|
@raw_content = raw_content
|
48
49
|
@attributes = attributes.symbolize_keys
|
@@ -55,7 +56,72 @@ module Nanoc3
|
|
55
56
|
@reps = []
|
56
57
|
end
|
57
58
|
|
59
|
+
# Returns the rep with the given name.
|
60
|
+
#
|
61
|
+
# @param [Symbol] rep_name The name of the representation to return
|
62
|
+
#
|
63
|
+
# @return [Nanoc3::ItemRep] The representation with the given name
|
64
|
+
def rep(rep_name)
|
65
|
+
@reps.find { |r| r.name == rep_name }
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns the compiled content from a given representation and a given
|
69
|
+
# snapshot. This is a convenience method that makes fetching compiled
|
70
|
+
# content easier.
|
71
|
+
#
|
72
|
+
# @option params [String] :rep (:default) The name of the representation
|
73
|
+
# from which the compiled content should be fetched. By default, the
|
74
|
+
# compiled content will be fetched from the default representation.
|
75
|
+
#
|
76
|
+
# @option params [String] :snapshot (:last) The name of the snapshot from
|
77
|
+
# which to fetch the compiled content. By default, the fully compiled
|
78
|
+
# content will be fetched, with all filters and layouts applied--not the
|
79
|
+
# pre-layout content.
|
80
|
+
#
|
81
|
+
# @return [String] The compiled content of the given rep (or the default
|
82
|
+
# rep if no rep is specified) at the given snapshot (or the default
|
83
|
+
# snapshot if no snapshot is specified)
|
84
|
+
def compiled_content(params={})
|
85
|
+
# Get rep
|
86
|
+
rep_name = params[:rep] || :default
|
87
|
+
rep = reps.find { |r| r.name == rep_name }
|
88
|
+
if rep.nil?
|
89
|
+
raise Nanoc3::Errors::Generic,
|
90
|
+
"No rep named #{rep_name.inspect} was found."
|
91
|
+
end
|
92
|
+
|
93
|
+
# Get rep's content
|
94
|
+
rep.compiled_content(params)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns the path from a given representation. This is a convenience
|
98
|
+
# method that makes fetching the path of a rep easier.
|
99
|
+
#
|
100
|
+
# @option params [String] :rep (:default) The name of the representation
|
101
|
+
# from which the path should be fetched. By default, the path will be
|
102
|
+
# fetched from the default representation.
|
103
|
+
#
|
104
|
+
# @return [String] The path of the given rep ( or the default rep if no
|
105
|
+
# rep is specified)
|
106
|
+
def path(params={})
|
107
|
+
rep_name = params[:rep] || :default
|
108
|
+
|
109
|
+
# Get rep
|
110
|
+
rep = reps.find { |r| r.name == rep_name }
|
111
|
+
if rep.nil?
|
112
|
+
raise Nanoc3::Errors::Generic,
|
113
|
+
"No rep named #{rep_name.inspect} was found."
|
114
|
+
end
|
115
|
+
|
116
|
+
# Get rep's path
|
117
|
+
rep.path
|
118
|
+
end
|
119
|
+
|
58
120
|
# Requests the attribute with the given key.
|
121
|
+
#
|
122
|
+
# @param [Symbol] key The name of the attribute to fetch
|
123
|
+
#
|
124
|
+
# @return [Object] The value of the requested attribute
|
59
125
|
def [](key)
|
60
126
|
Nanoc3::NotificationCenter.post(:visit_started, self)
|
61
127
|
Nanoc3::NotificationCenter.post(:visit_ended, self)
|
@@ -64,20 +130,22 @@ module Nanoc3
|
|
64
130
|
end
|
65
131
|
|
66
132
|
# Sets the attribute with the given key to the given value.
|
133
|
+
#
|
134
|
+
# @param [Symbol] key The name of the attribute to set
|
135
|
+
#
|
136
|
+
# @param [Object] value The value of the attribute to set
|
67
137
|
def []=(key, value)
|
68
138
|
@attributes[key] = value
|
69
139
|
end
|
70
140
|
|
71
|
-
#
|
141
|
+
# Determines whether this item (or rather, its reps) is outdated and
|
142
|
+
# should be recompiled (or rather, its reps should be recompiled).
|
143
|
+
#
|
144
|
+
# @return [Boolean] true if any reps are outdated; false otherwise.
|
72
145
|
def outdated?
|
73
146
|
@reps.any? { |r| r.outdated? }
|
74
147
|
end
|
75
148
|
|
76
|
-
# Alias for #dependencies_outdated.
|
77
|
-
def dependencies_outdated?
|
78
|
-
self.dependencies_outdated
|
79
|
-
end
|
80
|
-
|
81
149
|
def inspect
|
82
150
|
"<#{self.class}:0x#{self.object_id.to_s(16)} identifier=#{self.identifier}>"
|
83
151
|
end
|