nanoc3 3.1.9 → 3.2.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 +0 -50
- data/README.md +3 -15
- data/bin/nanoc3 +2 -0
- data/lib/nanoc3/base/checksummer.rb +40 -0
- data/lib/nanoc3/base/code_snippet.rb +30 -12
- data/lib/nanoc3/base/compiled_content_cache.rb +86 -0
- data/lib/nanoc3/base/compiler.rb +134 -95
- data/lib/nanoc3/base/compiler_dsl.rb +12 -11
- data/lib/nanoc3/base/core_ext/string.rb +2 -2
- data/lib/nanoc3/base/data_source.rb +17 -16
- data/lib/nanoc3/base/dependency_tracker.rb +102 -121
- data/lib/nanoc3/base/directed_graph.rb +65 -3
- data/lib/nanoc3/base/errors.rb +20 -16
- data/lib/nanoc3/base/item.rb +58 -50
- data/lib/nanoc3/base/item_rep.rb +177 -150
- data/lib/nanoc3/base/layout.rb +51 -18
- data/lib/nanoc3/base/notification_center.rb +8 -8
- data/lib/nanoc3/base/plugin_registry.rb +9 -9
- data/lib/nanoc3/base/rule.rb +18 -9
- data/lib/nanoc3/base/rule_context.rb +5 -5
- data/lib/nanoc3/base/site.rb +135 -47
- data/lib/nanoc3/base.rb +21 -19
- data/lib/nanoc3/cli/base.rb +51 -74
- data/lib/nanoc3/cli/commands/autocompile.rb +3 -0
- data/lib/nanoc3/cli/commands/compile.rb +35 -74
- data/lib/nanoc3/cli/commands/create_site.rb +17 -5
- data/lib/nanoc3/cli/commands/debug.rb +11 -4
- data/lib/nanoc3/cli/commands/view.rb +0 -1
- data/lib/nanoc3/cli/commands/watch.rb +148 -0
- data/lib/nanoc3/cli/commands.rb +1 -0
- data/lib/nanoc3/cli/logger.rb +15 -21
- data/lib/nanoc3/data_sources/deprecated/twitter.rb +0 -1
- data/lib/nanoc3/data_sources/filesystem.rb +11 -40
- data/lib/nanoc3/data_sources/filesystem_unified.rb +22 -22
- data/lib/nanoc3/extra/auto_compiler.rb +1 -1
- data/lib/nanoc3/extra/chick.rb +8 -8
- data/lib/nanoc3/extra/deployers/rsync.rb +2 -3
- data/lib/nanoc3/extra/validators/links.rb +32 -51
- data/lib/nanoc3/extra/validators/w3c.rb +2 -2
- data/lib/nanoc3/extra/vcs.rb +1 -1
- data/lib/nanoc3/filters/colorize_syntax.rb +15 -19
- data/lib/nanoc3/filters/erb.rb +1 -5
- data/lib/nanoc3/filters/erubis.rb +1 -5
- data/lib/nanoc3/filters/haml.rb +1 -2
- data/lib/nanoc3/filters/less.rb +2 -51
- data/lib/nanoc3/filters/mustache.rb +21 -0
- data/lib/nanoc3/filters/rdiscount.rb +1 -2
- data/lib/nanoc3/filters/relativize_paths.rb +3 -2
- data/lib/nanoc3/filters/sass.rb +50 -56
- data/lib/nanoc3/filters.rb +2 -0
- data/lib/nanoc3/helpers/blogging.rb +22 -29
- data/lib/nanoc3/helpers/breadcrumbs.rb +1 -1
- data/lib/nanoc3/helpers/capturing.rb +1 -1
- data/lib/nanoc3/helpers/filtering.rb +1 -1
- data/lib/nanoc3/helpers/link_to.rb +10 -21
- data/lib/nanoc3/helpers/rendering.rb +5 -24
- data/lib/nanoc3/helpers/tagging.rb +6 -6
- data/lib/nanoc3/helpers/text.rb +2 -2
- data/lib/nanoc3.rb +1 -1
- metadata +35 -93
- data/.gemtest +0 -0
- data/doc/yardoc_templates/default/layout/html/footer.erb +0 -10
- data/nanoc3.gemspec +0 -41
- data/tasks/clean.rake +0 -11
- data/tasks/doc.rake +0 -14
- data/tasks/gem.rake +0 -13
- data/tasks/test.rake +0 -38
- data/test/base/core_ext/array_spec.rb +0 -23
- data/test/base/core_ext/hash_spec.rb +0 -41
- data/test/base/core_ext/string_spec.rb +0 -27
- data/test/base/test_code_snippet.rb +0 -33
- data/test/base/test_compiler.rb +0 -410
- data/test/base/test_compiler_dsl.rb +0 -121
- data/test/base/test_context.rb +0 -33
- data/test/base/test_data_source.rb +0 -48
- data/test/base/test_dependency_tracker.rb +0 -510
- data/test/base/test_directed_graph.rb +0 -91
- data/test/base/test_filter.rb +0 -85
- data/test/base/test_item.rb +0 -141
- data/test/base/test_item_rep.rb +0 -953
- data/test/base/test_layout.rb +0 -44
- data/test/base/test_notification_center.rb +0 -36
- data/test/base/test_plugin.rb +0 -32
- data/test/base/test_rule.rb +0 -21
- data/test/base/test_rule_context.rb +0 -63
- data/test/base/test_site.rb +0 -366
- data/test/cli/commands/test_compile.rb +0 -12
- data/test/cli/commands/test_create_item.rb +0 -12
- data/test/cli/commands/test_create_layout.rb +0 -28
- data/test/cli/commands/test_create_site.rb +0 -24
- data/test/cli/commands/test_help.rb +0 -12
- data/test/cli/commands/test_info.rb +0 -12
- data/test/cli/commands/test_update.rb +0 -12
- data/test/cli/test_logger.rb +0 -12
- data/test/data_sources/test_filesystem.rb +0 -420
- data/test/data_sources/test_filesystem_unified.rb +0 -538
- data/test/data_sources/test_filesystem_verbose.rb +0 -359
- data/test/extra/core_ext/test_enumerable.rb +0 -32
- data/test/extra/core_ext/test_time.rb +0 -17
- data/test/extra/deployers/test_rsync.rb +0 -234
- data/test/extra/test_auto_compiler.rb +0 -482
- data/test/extra/test_file_proxy.rb +0 -21
- data/test/extra/test_vcs.rb +0 -24
- data/test/extra/validators/test_links.rb +0 -53
- data/test/extra/validators/test_w3c.rb +0 -49
- data/test/filters/test_bluecloth.rb +0 -20
- data/test/filters/test_coderay.rb +0 -46
- data/test/filters/test_colorize_syntax.rb +0 -84
- data/test/filters/test_erb.rb +0 -72
- data/test/filters/test_erubis.rb +0 -72
- data/test/filters/test_haml.rb +0 -98
- data/test/filters/test_kramdown.rb +0 -20
- data/test/filters/test_less.rb +0 -118
- data/test/filters/test_markaby.rb +0 -26
- data/test/filters/test_maruku.rb +0 -20
- data/test/filters/test_rainpress.rb +0 -31
- data/test/filters/test_rdiscount.rb +0 -33
- data/test/filters/test_rdoc.rb +0 -18
- data/test/filters/test_redcloth.rb +0 -20
- data/test/filters/test_relativize_paths.rb +0 -231
- data/test/filters/test_rubypants.rb +0 -20
- data/test/filters/test_sass.rb +0 -235
- data/test/gem_loader.rb +0 -11
- data/test/helper.rb +0 -99
- data/test/helpers/test_blogging.rb +0 -808
- data/test/helpers/test_breadcrumbs.rb +0 -83
- data/test/helpers/test_capturing.rb +0 -42
- data/test/helpers/test_filtering.rb +0 -108
- data/test/helpers/test_html_escape.rb +0 -18
- data/test/helpers/test_link_to.rb +0 -251
- data/test/helpers/test_rendering.rb +0 -109
- data/test/helpers/test_tagging.rb +0 -89
- data/test/helpers/test_text.rb +0 -26
- data/test/helpers/test_xml_sitemap.rb +0 -69
- data/test/tasks/test_clean.rb +0 -71
@@ -33,13 +33,13 @@ module Nanoc3
|
|
33
33
|
# rep as a block argument.
|
34
34
|
#
|
35
35
|
# @param [String] identifier A pattern matching identifiers of items that
|
36
|
-
#
|
36
|
+
# should be compiled using this rule
|
37
37
|
#
|
38
38
|
# @option params [Symbol] :rep (:default) The name of the representation
|
39
|
-
#
|
39
|
+
# that should be compiled using this rule
|
40
40
|
#
|
41
41
|
# @yield The block that will be executed when an item matching this
|
42
|
-
#
|
42
|
+
# compilation rule needs to be compiled
|
43
43
|
#
|
44
44
|
# @return [void]
|
45
45
|
#
|
@@ -77,13 +77,13 @@ module Nanoc3
|
|
77
77
|
# and passing the rep as a block argument.
|
78
78
|
#
|
79
79
|
# @param [String] identifier A pattern matching identifiers of items that
|
80
|
-
#
|
80
|
+
# should be routed using this rule
|
81
81
|
#
|
82
82
|
# @option params [Symbol] :rep (:default) The name of the representation
|
83
|
-
#
|
83
|
+
# that should be routed using this rule
|
84
84
|
#
|
85
85
|
# @yield The block that will be executed when an item matching this
|
86
|
-
#
|
86
|
+
# compilation rule needs to be routed
|
87
87
|
#
|
88
88
|
# @return [void]
|
89
89
|
#
|
@@ -103,10 +103,11 @@ module Nanoc3
|
|
103
103
|
raise ArgumentError.new("#route requires a block") unless block_given?
|
104
104
|
|
105
105
|
# Get rep name
|
106
|
-
rep_name
|
106
|
+
rep_name = params[:rep] || :default
|
107
|
+
snapshot_name = params[:snapshot] || :last
|
107
108
|
|
108
109
|
# Create rule
|
109
|
-
rule = Rule.new(identifier_to_regex(identifier), rep_name, block)
|
110
|
+
rule = Rule.new(identifier_to_regex(identifier), rep_name, block, :snapshot_name => snapshot_name)
|
110
111
|
@site.compiler.item_routing_rules << rule
|
111
112
|
end
|
112
113
|
|
@@ -117,13 +118,13 @@ module Nanoc3
|
|
117
118
|
# contains filter arguments that will be passed to the filter.
|
118
119
|
#
|
119
120
|
# @param [String] identifier A pattern matching identifiers of layouts
|
120
|
-
#
|
121
|
+
# that should be filtered using this rule
|
121
122
|
#
|
122
123
|
# @param [Symbol] filter_name The name of the filter that should be run
|
123
|
-
#
|
124
|
+
# when processing the layout
|
124
125
|
#
|
125
126
|
# @param [Hash] params Extra filter arguments that should be passed to the
|
126
|
-
#
|
127
|
+
# filter when processing the layout (see {Nanoc3::Filter#run})
|
127
128
|
#
|
128
129
|
# @return [void]
|
129
130
|
#
|
@@ -18,12 +18,12 @@ module Nanoc3::StringExtensions
|
|
18
18
|
# @return [String] The decomposed string
|
19
19
|
def make_compatible_with_env
|
20
20
|
# Check whether environment supports Unicode
|
21
|
-
#
|
21
|
+
# FIXME this is ugly, and there most likely are better ways to do this
|
22
22
|
is_unicode_supported = %w( LC_ALL LC_CTYPE LANG ).any? { |e| ENV[e] =~ /UTF/ }
|
23
23
|
return self if is_unicode_supported
|
24
24
|
|
25
25
|
# Decompose if necessary
|
26
|
-
#
|
26
|
+
# FIXME this decomposition is not generally usable
|
27
27
|
self.gsub(/“|”/, '"').gsub(/‘|’/, '\'').gsub('…', '...')
|
28
28
|
end
|
29
29
|
|
@@ -21,21 +21,22 @@ module Nanoc3
|
|
21
21
|
# first time.
|
22
22
|
#
|
23
23
|
# @abstract Subclasses should at least implement {#items} and {#layouts}. If
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
24
|
+
# the data source should support creating items and layouts using the
|
25
|
+
# `create_item` and `create_layout` CLI commands, the {#setup},
|
26
|
+
# {#create_item} and {#create_layout} methods should be implemented as
|
27
|
+
# well.
|
27
28
|
class DataSource
|
28
29
|
|
29
30
|
# @return [String] The root path where items returned by this data source
|
30
|
-
#
|
31
|
+
# should be mounted.
|
31
32
|
attr_reader :items_root
|
32
33
|
|
33
34
|
# @return [String] The root path where layouts returned by this data
|
34
|
-
#
|
35
|
+
# source should be mounted.
|
35
36
|
attr_reader :layouts_root
|
36
37
|
|
37
38
|
# @return [Hash] The configuration for this data source. For example,
|
38
|
-
#
|
39
|
+
# online data sources could contain authentication details.
|
39
40
|
attr_reader :config
|
40
41
|
|
41
42
|
extend Nanoc3::PluginRegistry::PluginMethods
|
@@ -45,12 +46,12 @@ module Nanoc3
|
|
45
46
|
# @param [Nanoc3::Site] site The site this data source belongs to.
|
46
47
|
#
|
47
48
|
# @param [String] items_root The prefix that should be given to all items
|
48
|
-
#
|
49
|
-
#
|
49
|
+
# returned by the #items method (comparable to mount points for
|
50
|
+
# filesystems in Unix-ish OSes).
|
50
51
|
#
|
51
52
|
# @param [String] layouts_root The prefix that should be given to all
|
52
|
-
#
|
53
|
-
#
|
53
|
+
# layouts returned by the #layouts method (comparable to mount points
|
54
|
+
# for filesystems in Unix-ish OSes).
|
54
55
|
#
|
55
56
|
# @param [Hash] config The configuration for this data source.
|
56
57
|
def initialize(site, items_root, layouts_root, config)
|
@@ -189,9 +190,9 @@ module Nanoc3
|
|
189
190
|
# @param [String] identifier
|
190
191
|
#
|
191
192
|
# @param [Hash] params Extra parameters to give to the data source. This
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
193
|
+
# can be used to influence the way items are stored. For example,
|
194
|
+
# filesystem data sources could use this to pass the extension of the
|
195
|
+
# files that should be generated.
|
195
196
|
#
|
196
197
|
# @return [void]
|
197
198
|
def create_item(content, attributes, identifier, params={})
|
@@ -212,9 +213,9 @@ module Nanoc3
|
|
212
213
|
# @param [String] identifier
|
213
214
|
#
|
214
215
|
# @param [Hash] params Extra parameters to give to the data source. This
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
216
|
+
# can be used to influence the way items are stored. For example,
|
217
|
+
# filesystem data sources could use this to pass the extension of the
|
218
|
+
# files that should be generated.
|
218
219
|
#
|
219
220
|
# @return [void]
|
220
221
|
def create_layout(content, attributes, identifier, params={})
|
@@ -4,18 +4,18 @@ require 'pstore'
|
|
4
4
|
|
5
5
|
module Nanoc3
|
6
6
|
|
7
|
-
# Responsible for remembering dependencies between items. It is
|
8
|
-
# speed up compilation by only letting an item be recompiled when it
|
9
|
-
# outdated or any of its dependencies (or dependencies’ dependencies,
|
10
|
-
# is outdated.
|
7
|
+
# Responsible for remembering dependencies between items and layouts. It is
|
8
|
+
# used to speed up compilation by only letting an item be recompiled when it
|
9
|
+
# is outdated or any of its dependencies (or dependencies’ dependencies,
|
10
|
+
# etc) is outdated.
|
11
11
|
#
|
12
12
|
# The dependencies tracked by the dependency tracker are not dependencies
|
13
|
-
# based on an item’s content. When one
|
14
|
-
#
|
15
|
-
# on an item’s content (handled in
|
16
|
-
# recursive, the more general
|
17
|
-
# (e.g. item A can use an
|
18
|
-
# problems).
|
13
|
+
# based on an item’s or a layout’s content. When one object uses an
|
14
|
+
# attribute of another object, then this is also treated as a dependency.
|
15
|
+
# While dependencies based on an item’s or layout’s content (handled in
|
16
|
+
# {Nanoc3::Compiler}) cannot be mutually recursive, the more general
|
17
|
+
# dependencies in Nanoc3::DependencyTracker can (e.g. item A can use an
|
18
|
+
# attribute of item B and vice versa without problems).
|
19
19
|
#
|
20
20
|
# The dependency tracker remembers the dependency information between runs.
|
21
21
|
# Dependency information is stored in the `tmp/dependencies` file. This file
|
@@ -24,25 +24,26 @@ module Nanoc3
|
|
24
24
|
class DependencyTracker
|
25
25
|
|
26
26
|
# @return [String] The name of the file in which dependency information is
|
27
|
-
#
|
27
|
+
# stored
|
28
28
|
attr_accessor :filename
|
29
29
|
|
30
|
-
# @return [Array<Nanoc3::Item>] The list of items
|
31
|
-
# by the dependency tracker
|
32
|
-
attr_reader :
|
30
|
+
# @return [Array<Nanoc3::Item, Nanoc3::Layout>] The list of items and
|
31
|
+
# layouts that are being tracked by the dependency tracker
|
32
|
+
attr_reader :objects
|
33
33
|
|
34
34
|
# The version of the file format used to store dependencies.
|
35
|
-
STORE_VERSION =
|
35
|
+
STORE_VERSION = 3
|
36
36
|
|
37
|
-
# Creates a new dependency tracker for the given items.
|
37
|
+
# Creates a new dependency tracker for the given items and layouts.
|
38
38
|
#
|
39
|
-
# @param [Array<Nanoc3::Item>]
|
40
|
-
# should be managed
|
41
|
-
def initialize(
|
42
|
-
@
|
43
|
-
|
44
|
-
@
|
45
|
-
@
|
39
|
+
# @param [Array<Nanoc3::Item, Nanoc3::Layout>] objects The list of items
|
40
|
+
# and layouts whose dependencies should be managed
|
41
|
+
def initialize(objects)
|
42
|
+
@objects = objects
|
43
|
+
|
44
|
+
@filename = 'tmp/dependencies'
|
45
|
+
@graph = Nanoc3::DirectedGraph.new([ nil ] + @objects)
|
46
|
+
@previous_objects = []
|
46
47
|
end
|
47
48
|
|
48
49
|
# Starts listening for dependency messages (`:visit_started` and
|
@@ -50,24 +51,19 @@ module Nanoc3
|
|
50
51
|
#
|
51
52
|
# @return [void]
|
52
53
|
def start
|
53
|
-
# Initialize dependency stack. An
|
54
|
-
# when it is visited. Therefore, an
|
55
|
-
# all
|
54
|
+
# Initialize dependency stack. An object will be pushed onto this stack
|
55
|
+
# when it is visited. Therefore, an object on the stack always depends
|
56
|
+
# on all objects pushed above it.
|
56
57
|
@stack = []
|
57
58
|
|
58
59
|
# Register start of visits
|
59
|
-
Nanoc3::NotificationCenter.on(:visit_started, self) do |
|
60
|
-
|
61
|
-
|
62
|
-
$stderr.puts "*** Recording dependency on #{item.inspect}" if $DEBUG
|
63
|
-
self.record_dependency(@stack[-1], item)
|
64
|
-
end
|
65
|
-
|
66
|
-
@stack.push(item)
|
60
|
+
Nanoc3::NotificationCenter.on(:visit_started, self) do |obj|
|
61
|
+
self.record_dependency(@stack[-1], obj) unless @stack.empty?
|
62
|
+
@stack.push(obj)
|
67
63
|
end
|
68
64
|
|
69
65
|
# Register end of visits
|
70
|
-
Nanoc3::NotificationCenter.on(:visit_ended, self) do |
|
66
|
+
Nanoc3::NotificationCenter.on(:visit_ended, self) do |obj|
|
71
67
|
@stack.pop
|
72
68
|
end
|
73
69
|
end
|
@@ -81,71 +77,78 @@ module Nanoc3
|
|
81
77
|
Nanoc3::NotificationCenter.remove(:visit_ended, self)
|
82
78
|
end
|
83
79
|
|
84
|
-
# Returns the direct dependencies for
|
80
|
+
# Returns the direct dependencies for the given object.
|
85
81
|
#
|
86
|
-
# The direct dependencies of
|
87
|
-
# will cause
|
88
|
-
# not be returned (e.g. if A
|
89
|
-
# direct dependencies of A do
|
82
|
+
# The direct dependencies of the given object include the items
|
83
|
+
# and layouts that, when outdated will cause the given object to be marked
|
84
|
+
# as outdated. Indirect dependencies will not be returned (e.g. if A
|
85
|
+
# depends on B which depends on C, then the direct dependencies of A do
|
86
|
+
# not include C).
|
90
87
|
#
|
91
|
-
# @param [Nanoc3::Item]
|
92
|
-
# predecessors
|
88
|
+
# @param [Nanoc3::Item, Nanoc3::Layout] object The object for
|
89
|
+
# which to fetch the direct predecessors
|
93
90
|
#
|
94
|
-
# @return [Array<Nanoc3::Item>] The direct predecessors of
|
95
|
-
|
96
|
-
|
91
|
+
# @return [Array<Nanoc3::Item, Nanoc3::Layout>] The direct predecessors of
|
92
|
+
# the given object
|
93
|
+
def direct_predecessors_of(object)
|
94
|
+
@graph.direct_predecessors_of(object).compact
|
97
95
|
end
|
98
96
|
|
99
|
-
# Returns all dependencies (direct and indirect) for
|
97
|
+
# Returns all dependencies (direct and indirect) for the given object.
|
100
98
|
#
|
101
|
-
# The dependencies of
|
102
|
-
# cause
|
99
|
+
# The dependencies of given object include the objects that, when
|
100
|
+
# outdated, will cause the given object to be marked as outdated.
|
103
101
|
#
|
104
|
-
# @param [Nanoc3::Item]
|
105
|
-
# indirect predecessors
|
102
|
+
# @param [Nanoc3::Item, Nanoc3::Layout] object The object for which to
|
103
|
+
# fetch all direct and indirect predecessors
|
106
104
|
#
|
107
|
-
# @return [Array<Nanoc3::Item>] The predecessors of the
|
108
|
-
|
109
|
-
|
105
|
+
# @return [Array<Nanoc3::Item, Nanoc3::Layout>] The predecessors of the
|
106
|
+
# given object
|
107
|
+
def predecessors_of(object)
|
108
|
+
@graph.predecessors_of(object).compact
|
110
109
|
end
|
111
110
|
|
112
|
-
# Returns the direct inverse dependencies for
|
111
|
+
# Returns the direct inverse dependencies for the given object.
|
113
112
|
#
|
114
|
-
# The direct inverse dependencies of
|
115
|
-
# marked as outdated when
|
116
|
-
# not be returned (e.g. if A depends on B which
|
117
|
-
# direct inverse dependencies of C do not include
|
113
|
+
# The direct inverse dependencies of the given object include the objects
|
114
|
+
# that will be marked as outdated when the given object is outdated.
|
115
|
+
# Indirect dependencies will not be returned (e.g. if A depends on B which
|
116
|
+
# depends on C, then the direct inverse dependencies of C do not include
|
117
|
+
# A).
|
118
118
|
#
|
119
|
-
# @param [Nanoc3::Item]
|
120
|
-
# successors
|
119
|
+
# @param [Nanoc3::Item, Nanoc3::Layout] object The object for which to
|
120
|
+
# fetch the direct successors
|
121
121
|
#
|
122
|
-
# @return [Array<Nanoc3::Item>] The direct successors of
|
123
|
-
|
124
|
-
|
122
|
+
# @return [Array<Nanoc3::Item, Nanoc3::Layout>] The direct successors of
|
123
|
+
# the given object
|
124
|
+
def direct_successors_of(object)
|
125
|
+
@graph.direct_successors_of(object).compact
|
125
126
|
end
|
126
127
|
|
127
|
-
# Returns all inverse dependencies (direct and indirect) for
|
128
|
+
# Returns all inverse dependencies (direct and indirect) for the given
|
129
|
+
# object.
|
128
130
|
#
|
129
|
-
# The inverse dependencies of
|
130
|
-
# as outdated when
|
131
|
+
# The inverse dependencies of the given object include the objects that
|
132
|
+
# will be marked as outdated when the given object is outdated.
|
131
133
|
#
|
132
|
-
# @param [Nanoc3::Item]
|
133
|
-
# indirect successors
|
134
|
+
# @param [Nanoc3::Item, Nanoc3::Layout] object The object for which to
|
135
|
+
# fetch all direct and indirect successors
|
134
136
|
#
|
135
|
-
# @return [Array<Nanoc3::Item>] The successors of the
|
136
|
-
|
137
|
-
|
137
|
+
# @return [Array<Nanoc3::Item, Nanoc3::Layout>] The successors of the
|
138
|
+
# given object
|
139
|
+
def successors_of(object)
|
140
|
+
@graph.successors_of(object).compact
|
138
141
|
end
|
139
142
|
|
140
143
|
# Records a dependency from `src` to `dst` in the dependency graph. When
|
141
144
|
# `dst` is oudated, `src` will also become outdated.
|
142
145
|
#
|
143
|
-
# @param [Nanoc3::Item] src The source of the dependency,
|
144
|
-
# that will become outdated if dst is outdated
|
146
|
+
# @param [Nanoc3::Item, Nanoc3::Layout] src The source of the dependency,
|
147
|
+
# i.e. the object that will become outdated if dst is outdated
|
145
148
|
#
|
146
|
-
# @param [Nanoc3::Item] dst The destination of the
|
147
|
-
#
|
148
|
-
# is outdated
|
149
|
+
# @param [Nanoc3::Item, Nanoc3::Layout] dst The destination of the
|
150
|
+
# dependency, i.e. the object that will cause the source to become
|
151
|
+
# outdated if the destination is outdated
|
149
152
|
#
|
150
153
|
# @return [void]
|
151
154
|
def record_dependency(src, dst)
|
@@ -162,7 +165,7 @@ module Nanoc3
|
|
162
165
|
store = PStore.new(self.filename)
|
163
166
|
store.transaction do
|
164
167
|
store[:version] = STORE_VERSION
|
165
|
-
store[:vertices] = @graph.vertices.map { |
|
168
|
+
store[:vertices] = @graph.vertices.map { |obj| obj && obj.reference }
|
166
169
|
store[:edges] = @graph.edges
|
167
170
|
end
|
168
171
|
end
|
@@ -173,7 +176,7 @@ module Nanoc3
|
|
173
176
|
# @return [void]
|
174
177
|
def load_graph
|
175
178
|
# Create new graph
|
176
|
-
@graph = Nanoc3::DirectedGraph.new([ nil ] + @
|
179
|
+
@graph = Nanoc3::DirectedGraph.new([ nil ] + @objects)
|
177
180
|
|
178
181
|
# Get store
|
179
182
|
return if !File.file?(self.filename)
|
@@ -185,44 +188,44 @@ module Nanoc3
|
|
185
188
|
return if store[:version] != STORE_VERSION
|
186
189
|
|
187
190
|
# Load vertices
|
188
|
-
@
|
189
|
-
@
|
191
|
+
@previous_objects = store[:vertices].map do |reference|
|
192
|
+
@objects.find { |obj| reference == obj.reference }
|
190
193
|
end
|
191
194
|
|
192
195
|
# Load edges
|
193
196
|
store[:edges].each do |edge|
|
194
197
|
from_index, to_index = *edge
|
195
|
-
from, to = @
|
198
|
+
from, to = @previous_objects[from_index], @previous_objects[to_index]
|
196
199
|
@graph.add_edge(from, to)
|
197
200
|
end
|
198
201
|
end
|
199
202
|
end
|
200
203
|
|
201
|
-
# Traverses the dependency graph and marks all
|
202
|
-
# indirectly) depend on an outdated
|
204
|
+
# Traverses the dependency graph and marks all objects that (directly or
|
205
|
+
# indirectly) depend on an outdated object as outdated.
|
203
206
|
#
|
204
207
|
# @return [void]
|
205
208
|
def propagate_outdatedness
|
206
209
|
# Unmark everything
|
207
|
-
@
|
210
|
+
@objects.each { |o| o.outdated_due_to_dependencies = false }
|
208
211
|
|
209
|
-
# Mark new
|
210
|
-
|
211
|
-
|
212
|
+
# Mark new objects as outdated
|
213
|
+
added_objects = @objects - @previous_objects
|
214
|
+
added_objects.each { |o| o.outdated_due_to_dependencies = true }
|
212
215
|
|
213
216
|
# Mark successors of nil as outdated
|
214
|
-
self.successors_of(nil).each do |
|
215
|
-
|
217
|
+
self.successors_of(nil).each do |o|
|
218
|
+
o.outdated_due_to_dependencies = true
|
216
219
|
end
|
217
220
|
|
218
|
-
# Mark successors of outdated
|
221
|
+
# Mark successors of outdated objects as outdated
|
219
222
|
require 'set'
|
220
|
-
unprocessed = @
|
223
|
+
unprocessed = @objects.select { |o| o.outdated? }
|
221
224
|
seen = Set.new(unprocessed)
|
222
225
|
until unprocessed.empty?
|
223
|
-
|
226
|
+
obj = unprocessed.shift
|
224
227
|
|
225
|
-
self.direct_successors_of(
|
228
|
+
self.direct_successors_of(obj).each do |successor|
|
226
229
|
next if seen.include?(successor)
|
227
230
|
seen << successor
|
228
231
|
|
@@ -232,32 +235,17 @@ module Nanoc3
|
|
232
235
|
end
|
233
236
|
end
|
234
237
|
|
235
|
-
# Empties the list of dependencies for the given
|
236
|
-
# before recompiling the given
|
238
|
+
# Empties the list of dependencies for the given object. This is necessary
|
239
|
+
# before recompiling the given object, because otherwise old dependencies
|
237
240
|
# will stick around and new dependencies will appear twice. This function
|
238
241
|
# removes all incoming edges for the given vertex.
|
239
242
|
#
|
240
|
-
# @param [Nanoc3::Item]
|
241
|
-
#
|
242
|
-
# @return [void]
|
243
|
-
def forget_dependencies_for(item)
|
244
|
-
@graph.delete_edges_to(item)
|
245
|
-
end
|
246
|
-
|
247
|
-
# Prints the dependency graph in human-readable form.
|
243
|
+
# @param [Nanoc3::Item, Nanoc3::Layout] object The object for which to
|
244
|
+
# forget all dependencies
|
248
245
|
#
|
249
246
|
# @return [void]
|
250
|
-
def
|
251
|
-
@
|
252
|
-
puts "#{item.inspect} depends on:"
|
253
|
-
|
254
|
-
predecessors = direct_predecessors_of(item)
|
255
|
-
predecessors.each do |pred|
|
256
|
-
puts " #{pred.inspect}"
|
257
|
-
end
|
258
|
-
puts " (nothing!)" if predecessors.empty?
|
259
|
-
puts
|
260
|
-
end
|
247
|
+
def forget_dependencies_for(object)
|
248
|
+
@graph.delete_edges_to(object)
|
261
249
|
end
|
262
250
|
|
263
251
|
# @deprecated Use {#propagate_outdatedness} instead.
|
@@ -265,13 +253,6 @@ module Nanoc3
|
|
265
253
|
propagate_outdatedness
|
266
254
|
end
|
267
255
|
|
268
|
-
private
|
269
|
-
|
270
|
-
# Returns the item with the given identifier, or nil if no item is found.
|
271
|
-
def item_with_identifier(identifier)
|
272
|
-
@items.find { |i| i.identifier == identifier }
|
273
|
-
end
|
274
|
-
|
275
256
|
end
|
276
257
|
|
277
258
|
end
|
@@ -46,16 +46,19 @@ module Nanoc3
|
|
46
46
|
@to_graph = {}
|
47
47
|
|
48
48
|
@vertice_indexes = {}
|
49
|
-
vertices.each_with_index do |v, i|
|
49
|
+
@vertices.each_with_index do |v, i|
|
50
50
|
@vertice_indexes[v] = i
|
51
51
|
end
|
52
52
|
|
53
|
+
@roots = Set.new(@vertices)
|
54
|
+
|
53
55
|
invalidate_caches
|
54
56
|
end
|
55
57
|
|
56
58
|
# Adds an edge from the first vertex to the second vertex.
|
57
59
|
#
|
58
60
|
# @param from Vertex where the edge should start
|
61
|
+
#
|
59
62
|
# @param to Vertex where the edge should end
|
60
63
|
#
|
61
64
|
# @return [void]
|
@@ -66,6 +69,8 @@ module Nanoc3
|
|
66
69
|
@to_graph[to] ||= Set.new
|
67
70
|
@to_graph[to] << from
|
68
71
|
|
72
|
+
@roots.delete(to)
|
73
|
+
|
69
74
|
invalidate_caches
|
70
75
|
end
|
71
76
|
|
@@ -73,30 +78,75 @@ module Nanoc3
|
|
73
78
|
# edge does not exist, nothing is done.
|
74
79
|
#
|
75
80
|
# @param from Start vertex of the edge
|
81
|
+
#
|
76
82
|
# @param to End vertex of the edge
|
77
83
|
#
|
78
84
|
# @return [void]
|
79
|
-
def
|
85
|
+
def delete_edge(from, to)
|
80
86
|
@from_graph[from] ||= Set.new
|
81
87
|
@from_graph[from].delete(to)
|
82
88
|
|
83
89
|
@to_graph[to] ||= Set.new
|
84
90
|
@to_graph[to].delete(from)
|
85
91
|
|
92
|
+
@roots.add(to) if @to_graph[to].empty?
|
93
|
+
|
86
94
|
invalidate_caches
|
87
95
|
end
|
88
96
|
|
97
|
+
# Adds the given vertex to the graph.
|
98
|
+
#
|
99
|
+
# @param [Vertex] v The vertex to add to the graph
|
100
|
+
#
|
101
|
+
# @return [void]
|
102
|
+
def add_vertex(v)
|
103
|
+
return if @vertices.include?(v)
|
104
|
+
|
105
|
+
@vertices << v
|
106
|
+
@roots << v
|
107
|
+
end
|
108
|
+
|
109
|
+
# Deletes all edges coming from the given vertex.
|
110
|
+
#
|
111
|
+
# @param from Vertex from which all edges should be removed
|
112
|
+
#
|
113
|
+
# @return [void]
|
114
|
+
def delete_edges_from(from)
|
115
|
+
return if @from_graph[from].nil?
|
116
|
+
|
117
|
+
@from_graph[from].each do |to|
|
118
|
+
@to_graph[to].delete(from)
|
119
|
+
@roots.add(to) if @to_graph[to].empty?
|
120
|
+
end
|
121
|
+
@from_graph.delete(from)
|
122
|
+
end
|
123
|
+
|
89
124
|
# Deletes all edges going to the given vertex.
|
90
125
|
#
|
91
126
|
# @param to Vertex to which all edges should be removed
|
92
127
|
#
|
93
128
|
# @return [void]
|
94
129
|
def delete_edges_to(to)
|
95
|
-
@to_graph[to]
|
130
|
+
return if @to_graph[to].nil?
|
131
|
+
|
96
132
|
@to_graph[to].each do |from|
|
97
133
|
@from_graph[from].delete(to)
|
98
134
|
end
|
99
135
|
@to_graph.delete(to)
|
136
|
+
@roots.add(to)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Removes the given vertex from the graph.
|
140
|
+
#
|
141
|
+
# @param v Vertex to remove from the graph
|
142
|
+
#
|
143
|
+
# @return [void]
|
144
|
+
def delete_vertex(v)
|
145
|
+
delete_edges_to(v)
|
146
|
+
delete_edges_from(v)
|
147
|
+
|
148
|
+
@vertices.delete(v)
|
149
|
+
@roots.delete(v)
|
100
150
|
end
|
101
151
|
|
102
152
|
# Returns the direct predecessors of the given vertex, i.e. the vertices
|
@@ -153,6 +203,18 @@ module Nanoc3
|
|
153
203
|
result
|
154
204
|
end
|
155
205
|
|
206
|
+
# Returns all root vertices, i.e. vertices where no edge points to.
|
207
|
+
#
|
208
|
+
# @return [Set] The set of all root vertices in this graph.
|
209
|
+
def roots
|
210
|
+
@roots
|
211
|
+
end
|
212
|
+
|
213
|
+
# @deprecated Use {#delete_edge} instead
|
214
|
+
def remove_edge(from, to)
|
215
|
+
delete_edge(from, to)
|
216
|
+
end
|
217
|
+
|
156
218
|
private
|
157
219
|
|
158
220
|
# Invalidates cached data. This method should be called when the internal
|