nanoc3 3.2.0a3 → 3.2.0a4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/LICENSE +1 -1
- data/NEWS.md +23 -4
- data/README.md +7 -0
- data/lib/nanoc3/base/compilation/checksum_store.rb +17 -90
- data/lib/nanoc3/base/compilation/compiled_content_cache.rb +5 -0
- data/lib/nanoc3/base/compilation/compiler.rb +112 -175
- data/lib/nanoc3/base/compilation/compiler_dsl.rb +54 -11
- data/lib/nanoc3/base/compilation/dependency_tracker.rb +32 -65
- data/lib/nanoc3/base/compilation/filter.rb +4 -3
- data/lib/nanoc3/base/compilation/item_rep_proxy.rb +19 -4
- data/lib/nanoc3/base/compilation/item_rep_recorder_proxy.rb +90 -0
- data/lib/nanoc3/base/compilation/outdatedness_checker.rb +152 -15
- data/lib/nanoc3/base/compilation/outdatedness_reasons.rb +12 -9
- data/lib/nanoc3/base/compilation/rule.rb +3 -1
- data/lib/nanoc3/base/compilation/rule_memory_calculator.rb +42 -0
- data/lib/nanoc3/base/compilation/rule_memory_store.rb +53 -0
- data/lib/nanoc3/base/compilation/rules_collection.rb +205 -0
- data/lib/nanoc3/base/core_ext/array.rb +20 -0
- data/lib/nanoc3/base/core_ext/hash.rb +30 -0
- data/lib/nanoc3/base/core_ext/pathname.rb +26 -0
- data/lib/nanoc3/base/core_ext/string.rb +12 -0
- data/lib/nanoc3/base/core_ext.rb +1 -0
- data/lib/nanoc3/base/directed_graph.rb +11 -3
- data/lib/nanoc3/base/errors.rb +0 -4
- data/lib/nanoc3/base/memoization.rb +72 -0
- data/lib/nanoc3/base/result_data/item_rep.rb +64 -25
- data/lib/nanoc3/base/source_data/code_snippet.rb +9 -0
- data/lib/nanoc3/base/source_data/configuration.rb +20 -0
- data/lib/nanoc3/base/source_data/item.rb +29 -4
- data/lib/nanoc3/base/source_data/layout.rb +20 -1
- data/lib/nanoc3/base/source_data/site.rb +49 -26
- data/lib/nanoc3/base/store.rb +10 -1
- data/lib/nanoc3/base.rb +6 -1
- data/lib/nanoc3/cli/base.rb +20 -7
- data/lib/nanoc3/cli/commands/compile.rb +0 -2
- data/lib/nanoc3/cli/commands/create_site.rb +16 -7
- data/lib/nanoc3/cli/commands/debug.rb +3 -3
- data/lib/nanoc3/cli/commands/view.rb +1 -0
- data/lib/nanoc3/cli/commands/watch.rb +2 -1
- data/lib/nanoc3/data_sources/deprecated/delicious.rb +0 -2
- data/lib/nanoc3/data_sources/deprecated/last_fm.rb +0 -2
- data/lib/nanoc3/data_sources/deprecated/twitter.rb +0 -2
- data/lib/nanoc3/data_sources/filesystem.rb +17 -3
- data/lib/nanoc3/data_sources/filesystem_unified.rb +17 -17
- data/lib/nanoc3/extra/auto_compiler.rb +5 -1
- data/lib/nanoc3/extra/core_ext/time.rb +1 -1
- data/lib/nanoc3/extra/file_proxy.rb +11 -1
- data/lib/nanoc3/extra/validators/links.rb +1 -1
- data/lib/nanoc3/filters/asciidoc.rb +3 -3
- data/lib/nanoc3/filters/colorize_syntax.rb +106 -27
- data/lib/nanoc3/filters/erb.rb +16 -6
- data/lib/nanoc3/filters/erubis.rb +5 -1
- data/lib/nanoc3/filters/haml.rb +2 -1
- data/lib/nanoc3/filters/less.rb +3 -6
- data/lib/nanoc3/filters/mustache.rb +3 -0
- data/lib/nanoc3/filters/redcarpet.rb +27 -0
- data/lib/nanoc3/filters/sass.rb +1 -5
- data/lib/nanoc3/filters/slim.rb +25 -0
- data/lib/nanoc3/filters/typogruby.rb +23 -0
- data/lib/nanoc3/filters.rb +6 -0
- data/lib/nanoc3/helpers/blogging.rb +22 -26
- data/lib/nanoc3/helpers/rendering.rb +1 -1
- data/lib/nanoc3/helpers/xml_sitemap.rb +11 -2
- data/lib/nanoc3.rb +24 -3
- data/nanoc3.gemspec +4 -3
- data/tasks/clean.rake +11 -0
- data/tasks/doc.rake +14 -0
- data/tasks/test.rake +38 -0
- data/test/base/core_ext/array_spec.rb +55 -0
- data/test/base/core_ext/hash_spec.rb +82 -0
- data/test/base/core_ext/pathname_spec.rb +29 -0
- data/test/base/core_ext/string_spec.rb +39 -0
- data/test/base/test_checksum_store.rb +37 -0
- data/test/base/test_code_snippet.rb +33 -0
- data/test/base/test_compiler.rb +303 -0
- data/test/base/test_compiler_dsl.rb +156 -0
- data/test/base/test_context.rb +33 -0
- data/test/base/test_data_source.rb +48 -0
- data/test/base/test_dependency_tracker.rb +264 -0
- data/test/base/test_directed_graph.rb +285 -0
- data/test/base/test_filter.rb +85 -0
- data/test/base/test_item.rb +164 -0
- data/test/base/test_item_rep.rb +555 -0
- data/test/base/test_layout.rb +44 -0
- data/test/base/test_memoization.rb +53 -0
- data/test/base/test_notification_center.rb +36 -0
- data/test/base/test_outdatedness_checker.rb +365 -0
- data/test/base/test_plugin.rb +32 -0
- data/test/base/test_rule.rb +21 -0
- data/test/base/test_rule_context.rb +67 -0
- data/test/base/test_site.rb +144 -0
- data/test/cli/commands/test_compile.rb +12 -0
- data/test/cli/commands/test_create_item.rb +12 -0
- data/test/cli/commands/test_create_layout.rb +28 -0
- data/test/cli/commands/test_create_site.rb +24 -0
- data/test/cli/commands/test_help.rb +12 -0
- data/test/cli/commands/test_info.rb +12 -0
- data/test/cli/commands/test_update.rb +12 -0
- data/test/cli/test_logger.rb +12 -0
- data/test/data_sources/test_filesystem.rb +420 -0
- data/test/data_sources/test_filesystem_unified.rb +562 -0
- data/test/data_sources/test_filesystem_verbose.rb +359 -0
- data/test/extra/core_ext/test_enumerable.rb +32 -0
- data/test/extra/core_ext/test_time.rb +17 -0
- data/test/extra/deployers/test_rsync.rb +234 -0
- data/test/extra/test_auto_compiler.rb +417 -0
- data/test/extra/test_file_proxy.rb +21 -0
- data/test/extra/test_vcs.rb +24 -0
- data/test/extra/validators/test_links.rb +53 -0
- data/test/extra/validators/test_w3c.rb +49 -0
- data/test/filters/test_asciidoc.rb +22 -0
- data/test/filters/test_bluecloth.rb +20 -0
- data/test/filters/test_coderay.rb +46 -0
- data/test/filters/test_colorize_syntax.rb +149 -0
- data/test/filters/test_erb.rb +101 -0
- data/test/filters/test_erubis.rb +72 -0
- data/test/filters/test_haml.rb +98 -0
- data/test/filters/test_kramdown.rb +20 -0
- data/test/filters/test_less.rb +59 -0
- data/test/filters/test_markaby.rb +26 -0
- data/test/filters/test_maruku.rb +20 -0
- data/test/filters/test_mustache.rb +27 -0
- data/test/filters/test_rainpress.rb +31 -0
- data/test/filters/test_rdiscount.rb +33 -0
- data/test/filters/test_rdoc.rb +18 -0
- data/test/filters/test_redcarpet.rb +63 -0
- data/test/filters/test_redcloth.rb +35 -0
- data/test/filters/test_relativize_paths.rb +231 -0
- data/test/filters/test_rubypants.rb +20 -0
- data/test/filters/test_sass.rb +103 -0
- data/test/filters/test_slim.rb +37 -0
- data/test/filters/test_typogruby.rb +23 -0
- data/test/helper.rb +161 -0
- data/test/helpers/test_blogging.rb +756 -0
- data/test/helpers/test_breadcrumbs.rb +83 -0
- data/test/helpers/test_capturing.rb +43 -0
- data/test/helpers/test_filtering.rb +108 -0
- data/test/helpers/test_html_escape.rb +34 -0
- data/test/helpers/test_link_to.rb +251 -0
- data/test/helpers/test_rendering.rb +90 -0
- data/test/helpers/test_tagging.rb +89 -0
- data/test/helpers/test_text.rb +26 -0
- data/test/helpers/test_xml_sitemap.rb +105 -0
- data/test/tasks/test_clean.rb +69 -0
- metadata +96 -27
- data/lib/nanoc3/base/compilation/checksummer.rb +0 -68
@@ -16,6 +16,8 @@ module Nanoc3
|
|
16
16
|
|
17
17
|
# @return [Symbol] The name of the snapshot this rule will apply to.
|
18
18
|
# Ignored for compilation rules, but used for routing rules.
|
19
|
+
#
|
20
|
+
# @since 3.2.0
|
19
21
|
attr_reader :snapshot_name
|
20
22
|
|
21
23
|
# Creates a new item compilation rule with the given identifier regex,
|
@@ -62,7 +64,7 @@ module Nanoc3
|
|
62
64
|
# @return [void]
|
63
65
|
def apply_to(rep, params={})
|
64
66
|
compiler = params[:compiler] or raise ArgumentError, "Required :compiler option is missing"
|
65
|
-
rep = Nanoc3::ItemRepProxy.new(rep, compiler)
|
67
|
+
rep = Nanoc3::ItemRepProxy.new(rep, compiler) unless rep.is_proxy?
|
66
68
|
Nanoc3::RuleContext.new(:rep => rep, :compiler => compiler).instance_eval &@block
|
67
69
|
end
|
68
70
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3
|
4
|
+
|
5
|
+
# Calculates rule memories for objects that can be run through a rule (item
|
6
|
+
# representations and layouts).
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class RuleMemoryCalculator
|
10
|
+
|
11
|
+
extend Nanoc3::Memoization
|
12
|
+
|
13
|
+
# @option params [Nanoc3::RulesCollection] rules_collection The rules
|
14
|
+
# collection
|
15
|
+
def initialize(params={})
|
16
|
+
super('tmp/rule_memory', 1)
|
17
|
+
|
18
|
+
@rules_collection = params[:rules_collection] or
|
19
|
+
raise ArgumentError, "Required :rules_collection option is missing"
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [#reference] obj The object to calculate the rule memory for
|
23
|
+
#
|
24
|
+
# @return [Array] The caluclated rule memory for the given object
|
25
|
+
def [](obj)
|
26
|
+
result = case obj.type
|
27
|
+
when :item_rep
|
28
|
+
@rules_collection.new_rule_memory_for_rep(obj)
|
29
|
+
when :layout
|
30
|
+
@rules_collection.new_rule_memory_for_layout(obj)
|
31
|
+
else
|
32
|
+
raise RuntimeError,
|
33
|
+
"Do not know how to calculate the rule memory for #{obj.inspect}"
|
34
|
+
end
|
35
|
+
|
36
|
+
result
|
37
|
+
end
|
38
|
+
memoize :[]
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3
|
4
|
+
|
5
|
+
# Stores rule memories for objects that can be run through a rule (item
|
6
|
+
# representations and layouts).
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class RuleMemoryStore < ::Nanoc3::Store
|
10
|
+
|
11
|
+
# @option params [Nanoc3::Site] site The site where this rule memory store
|
12
|
+
# belongs to
|
13
|
+
def initialize(params={})
|
14
|
+
super('tmp/rule_memory', 1)
|
15
|
+
|
16
|
+
@site = params[:site] if params.has_key?(:site)
|
17
|
+
|
18
|
+
@rule_memories = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param [Nanoc3::ItemRep, Nanoc3::Layout] obj The item representation or
|
22
|
+
# the layout to get the rule memory for
|
23
|
+
#
|
24
|
+
# @return [Array] The rule memory for the given object
|
25
|
+
def [](obj)
|
26
|
+
@rule_memories[obj.reference]
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param [Nanoc3::ItemRep, Nanoc3::Layout] obj The item representation or
|
30
|
+
# the layout to set the rule memory for
|
31
|
+
#
|
32
|
+
# @param [Array] rule_memory The new rule memory to be stored
|
33
|
+
#
|
34
|
+
# @return [void]
|
35
|
+
def []=(obj, rule_memory)
|
36
|
+
@rule_memories[obj.reference] = rule_memory
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
# @see Nanoc3::Store#data
|
42
|
+
def data
|
43
|
+
@rule_memories
|
44
|
+
end
|
45
|
+
|
46
|
+
# @see Nanoc3::Store#data=
|
47
|
+
def data=(new_data)
|
48
|
+
@rule_memories = new_data
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
module Nanoc3
|
2
|
+
|
3
|
+
# Keeps track of the rules in a site.
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
class RulesCollection
|
7
|
+
|
8
|
+
extend Nanoc3::Memoization
|
9
|
+
|
10
|
+
# @return [Array<Nanoc3::Rule>] The list of item compilation rules that
|
11
|
+
# will be used to compile items.
|
12
|
+
attr_reader :item_compilation_rules
|
13
|
+
|
14
|
+
# @return [Array<Nanoc3::Rule>] The list of routing rules that will be
|
15
|
+
# used to give all items a path.
|
16
|
+
attr_reader :item_routing_rules
|
17
|
+
|
18
|
+
# The hash containing layout-to-filter mapping rules. This hash is
|
19
|
+
# ordered: iterating over the hash will happen in insertion order.
|
20
|
+
#
|
21
|
+
# @return [Hash] The layout-to-filter mapping rules
|
22
|
+
attr_reader :layout_filter_mapping
|
23
|
+
|
24
|
+
# @return [Proc] The code block that will be executed after all data is
|
25
|
+
# loaded but before the site is compiled
|
26
|
+
attr_accessor :preprocessor
|
27
|
+
|
28
|
+
# @param [Nanoc3::Compiler] compiler The site’s compiler
|
29
|
+
def initialize(compiler)
|
30
|
+
@compiler = compiler
|
31
|
+
|
32
|
+
@item_compilation_rules = []
|
33
|
+
@item_routing_rules = []
|
34
|
+
@layout_filter_mapping = OrderedHash.new
|
35
|
+
end
|
36
|
+
|
37
|
+
# TODO document
|
38
|
+
def add_item_compilation_rule(rule, position=:after)
|
39
|
+
case position
|
40
|
+
when :before
|
41
|
+
@item_compilation_rules.unshift(rule)
|
42
|
+
when :after
|
43
|
+
@item_compilation_rules << rule
|
44
|
+
else
|
45
|
+
raise "#add_item_routing_rule expected position to be :after or :before"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# TODO document
|
50
|
+
def add_item_routing_rule(rule, position=:after)
|
51
|
+
case position
|
52
|
+
when :before
|
53
|
+
@item_routing_rules.unshift(rule)
|
54
|
+
when :after
|
55
|
+
@item_routing_rules << rule
|
56
|
+
else
|
57
|
+
raise "#add_item_routing_rule expected position to be :after or :before"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# TODO document
|
62
|
+
def item_compilation_rules_for(item)
|
63
|
+
@item_compilation_rules.select { |r| r.applicable_to?(item) }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Loads this site’s rules.
|
67
|
+
def load
|
68
|
+
# Find rules file
|
69
|
+
rules_filenames = [ 'Rules', 'rules', 'Rules.rb', 'rules.rb' ]
|
70
|
+
rules_filename = rules_filenames.find { |f| File.file?(f) }
|
71
|
+
raise Nanoc3::Errors::NoRulesFileFound.new if rules_filename.nil?
|
72
|
+
|
73
|
+
# Get rule data
|
74
|
+
@data = File.read(rules_filename)
|
75
|
+
|
76
|
+
# Load DSL
|
77
|
+
dsl.instance_eval(@data, "./#{rules_filename}")
|
78
|
+
end
|
79
|
+
|
80
|
+
# Unloads this site’s rules.
|
81
|
+
def unload
|
82
|
+
@item_compilation_rules = []
|
83
|
+
@item_routing_rules = []
|
84
|
+
@layout_filter_mapping = OrderedHash.new
|
85
|
+
end
|
86
|
+
|
87
|
+
# Finds the first matching compilation rule for the given item
|
88
|
+
# representation.
|
89
|
+
#
|
90
|
+
# @param [Nanoc3::ItemRep] rep The item rep for which to fetch the rule
|
91
|
+
#
|
92
|
+
# @return [Nanoc3::Rule, nil] The compilation rule for the given item rep,
|
93
|
+
# or nil if no rules have been found
|
94
|
+
def compilation_rule_for(rep)
|
95
|
+
@item_compilation_rules.find do |rule|
|
96
|
+
rule.applicable_to?(rep.item) && rule.rep_name == rep.name
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Finds the first matching routing rule for the given item representation.
|
101
|
+
#
|
102
|
+
# @param [Nanoc3::ItemRep] rep The item rep for which to fetch the rule
|
103
|
+
#
|
104
|
+
# @return [Nanoc3::Rule, nil] The routing rule for the given item rep, or
|
105
|
+
# nil if no rules have been found
|
106
|
+
def routing_rule_for(rep)
|
107
|
+
@item_routing_rules.find do |rule|
|
108
|
+
rule.applicable_to?(rep.item) && rule.rep_name == rep.name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns the list of routing rules that can be applied to the given item
|
113
|
+
# representation. For each snapshot, the first matching rule will be
|
114
|
+
# returned. The result is a hash containing the corresponding rule for
|
115
|
+
# each snapshot.
|
116
|
+
#
|
117
|
+
# @return [Hash<Symbol, Nanoc3::Rule>] The routing rules for the given rep
|
118
|
+
def routing_rules_for(rep)
|
119
|
+
rules = {}
|
120
|
+
@item_routing_rules.each do |rule|
|
121
|
+
next if !rule.applicable_to?(rep.item)
|
122
|
+
next if rule.rep_name != rep.name
|
123
|
+
next if rules.has_key?(rule.snapshot_name)
|
124
|
+
|
125
|
+
rules[rule.snapshot_name] = rule
|
126
|
+
end
|
127
|
+
rules
|
128
|
+
end
|
129
|
+
|
130
|
+
# Finds the filter name and arguments to use for the given layout.
|
131
|
+
#
|
132
|
+
# @param [Nanoc3::Layout] layout The layout for which to fetch the filter.
|
133
|
+
#
|
134
|
+
# @return [Array, nil] A tuple containing the filter name and the filter
|
135
|
+
# arguments for the given layout.
|
136
|
+
def filter_for_layout(layout)
|
137
|
+
@layout_filter_mapping.each_pair do |layout_identifier, filter_name_and_args|
|
138
|
+
return filter_name_and_args if layout.identifier =~ layout_identifier
|
139
|
+
end
|
140
|
+
nil
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns the Nanoc3::CompilerDSL that should be used for this site.
|
144
|
+
def dsl
|
145
|
+
Nanoc3::CompilerDSL.new(self)
|
146
|
+
end
|
147
|
+
memoize :dsl
|
148
|
+
|
149
|
+
# TODO document
|
150
|
+
def reference
|
151
|
+
:rules
|
152
|
+
end
|
153
|
+
|
154
|
+
# TODO document
|
155
|
+
def data
|
156
|
+
@data
|
157
|
+
end
|
158
|
+
|
159
|
+
# TODO document
|
160
|
+
def checksum
|
161
|
+
@data.checksum
|
162
|
+
end
|
163
|
+
|
164
|
+
def inspect
|
165
|
+
"<#{self.class}:0x#{self.object_id.to_s(16)}>"
|
166
|
+
end
|
167
|
+
|
168
|
+
# @param [Nanoc3::ItemRep] rep The item representation to get the rule
|
169
|
+
# memory for
|
170
|
+
#
|
171
|
+
# @return [Array] The rule memory for the given item representation
|
172
|
+
def new_rule_memory_for_rep(rep)
|
173
|
+
recording_proxy = rep.to_recording_proxy
|
174
|
+
compilation_rule_for(rep).apply_to(recording_proxy, :compiler => @compiler)
|
175
|
+
recording_proxy.rule_memory
|
176
|
+
end
|
177
|
+
memoize :new_rule_memory_for_rep
|
178
|
+
|
179
|
+
# @param [Nanoc3::Layout] layout The layout to get the rule memory for
|
180
|
+
#
|
181
|
+
# @return [Array] The rule memory for the given layout
|
182
|
+
def new_rule_memory_for_layout(layout)
|
183
|
+
filter_for_layout(layout)
|
184
|
+
end
|
185
|
+
memoize :new_rule_memory_for_layout
|
186
|
+
|
187
|
+
# TODO document
|
188
|
+
def rule_memory_differs_for(obj)
|
189
|
+
!rule_memory_store[obj].eql?(rule_memory_calculator[obj])
|
190
|
+
end
|
191
|
+
memoize :rule_memory_differs_for
|
192
|
+
|
193
|
+
# TODO document
|
194
|
+
def rule_memory_store
|
195
|
+
@compiler.rule_memory_store
|
196
|
+
end
|
197
|
+
|
198
|
+
# TODO document
|
199
|
+
def rule_memory_calculator
|
200
|
+
@compiler.rule_memory_calculator
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
@@ -24,6 +24,26 @@ module Nanoc3::ArrayExtensions
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
# Freezes the contents of the array, as well as all array elements. The
|
28
|
+
# array elements will be frozen using {#freeze_recursively} if they respond
|
29
|
+
# to that message, or #freeze if they do not.
|
30
|
+
#
|
31
|
+
# @see Hash#freeze_recursively
|
32
|
+
#
|
33
|
+
# @return [void]
|
34
|
+
#
|
35
|
+
# @since 3.2.0
|
36
|
+
def freeze_recursively
|
37
|
+
freeze
|
38
|
+
each do |value|
|
39
|
+
if value.respond_to?(:freeze_recursively)
|
40
|
+
value.freeze_recursively
|
41
|
+
else
|
42
|
+
value.freeze
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
27
47
|
end
|
28
48
|
|
29
49
|
class Array
|
@@ -24,6 +24,36 @@ module Nanoc3::HashExtensions
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
# Freezes the contents of the hash, as well as all hash values. The hash
|
28
|
+
# values will be frozen using {#freeze_recursively} if they respond to
|
29
|
+
# that message, or #freeze if they do not.
|
30
|
+
#
|
31
|
+
# @see Array#freeze_recursively
|
32
|
+
#
|
33
|
+
# @return [void]
|
34
|
+
#
|
35
|
+
# @since 3.2.0
|
36
|
+
def freeze_recursively
|
37
|
+
freeze
|
38
|
+
each_pair do |key, value|
|
39
|
+
if value.respond_to?(:freeze_recursively)
|
40
|
+
value.freeze_recursively
|
41
|
+
else
|
42
|
+
value.freeze
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Calculates the checksum for this hash. Any change to this hash will result
|
48
|
+
# in a different checksum.
|
49
|
+
#
|
50
|
+
# @return [String] The checksum for this hash
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
def checksum
|
54
|
+
Marshal.dump(self).checksum
|
55
|
+
end
|
56
|
+
|
27
57
|
end
|
28
58
|
|
29
59
|
class Hash
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::PathnameExtensions
|
4
|
+
|
5
|
+
# Calculates the checksum for the file referenced to by this pathname. Any
|
6
|
+
# change to the file contents will result in a different checksum.
|
7
|
+
#
|
8
|
+
# @return [String] The checksum for this file
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
def checksum
|
12
|
+
digest = Digest::SHA1.new
|
13
|
+
File.open(self.to_s, 'r') do |io|
|
14
|
+
until io.eof
|
15
|
+
data = io.readpartial(2**10)
|
16
|
+
digest.update(data)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
digest.hexdigest
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class Pathname
|
25
|
+
include Nanoc3::PathnameExtensions
|
26
|
+
end
|
@@ -27,6 +27,18 @@ module Nanoc3::StringExtensions
|
|
27
27
|
self.gsub(/“|”/, '"').gsub(/‘|’/, '\'').gsub('…', '...')
|
28
28
|
end
|
29
29
|
|
30
|
+
# Calculates the checksum for this string. Any change to this string will
|
31
|
+
# result in a different checksum.
|
32
|
+
#
|
33
|
+
# @return [String] The checksum for this string
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
def checksum
|
37
|
+
digest = Digest::SHA1.new
|
38
|
+
digest.update(self)
|
39
|
+
digest.hexdigest
|
40
|
+
end
|
41
|
+
|
30
42
|
end
|
31
43
|
|
32
44
|
class String
|
data/lib/nanoc3/base/core_ext.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'set'
|
4
|
-
|
5
3
|
module Nanoc3
|
6
4
|
|
7
5
|
# Represents a directed graph. It is used by the dependency tracker for
|
@@ -89,6 +87,8 @@ module Nanoc3
|
|
89
87
|
# @param to End vertex of the edge
|
90
88
|
#
|
91
89
|
# @return [void]
|
90
|
+
#
|
91
|
+
# @since 3.2.0
|
92
92
|
def delete_edge(from, to)
|
93
93
|
@from_graph[from] ||= Set.new
|
94
94
|
@from_graph[from].delete(to)
|
@@ -103,9 +103,11 @@ module Nanoc3
|
|
103
103
|
|
104
104
|
# Adds the given vertex to the graph.
|
105
105
|
#
|
106
|
-
# @param
|
106
|
+
# @param v The vertex to add to the graph
|
107
107
|
#
|
108
108
|
# @return [void]
|
109
|
+
#
|
110
|
+
# @since 3.2.0
|
109
111
|
def add_vertex(v)
|
110
112
|
return if @vertices.include?(v)
|
111
113
|
|
@@ -120,6 +122,8 @@ module Nanoc3
|
|
120
122
|
# @param from Vertex from which all edges should be removed
|
121
123
|
#
|
122
124
|
# @return [void]
|
125
|
+
#
|
126
|
+
# @since 3.2.0
|
123
127
|
def delete_edges_from(from)
|
124
128
|
return if @from_graph[from].nil?
|
125
129
|
|
@@ -150,6 +154,8 @@ module Nanoc3
|
|
150
154
|
# @param v Vertex to remove from the graph
|
151
155
|
#
|
152
156
|
# @return [void]
|
157
|
+
#
|
158
|
+
# @since 3.2.0
|
153
159
|
def delete_vertex(v)
|
154
160
|
delete_edges_to(v)
|
155
161
|
delete_edges_from(v)
|
@@ -217,6 +223,8 @@ module Nanoc3
|
|
217
223
|
# Returns all root vertices, i.e. vertices where no edge points to.
|
218
224
|
#
|
219
225
|
# @return [Set] The set of all root vertices in this graph.
|
226
|
+
#
|
227
|
+
# @since 3.2.0
|
220
228
|
def roots
|
221
229
|
@roots
|
222
230
|
end
|
data/lib/nanoc3/base/errors.rb
CHANGED
@@ -160,10 +160,6 @@ module Nanoc3
|
|
160
160
|
|
161
161
|
end
|
162
162
|
|
163
|
-
# Error that is raised when an internal consistency error is detected.
|
164
|
-
class InternalConsistency < Generic
|
165
|
-
end
|
166
|
-
|
167
163
|
# @deprecated No longer necessary, but kept for backwards compatibility.
|
168
164
|
class DataNotYetAvailable < Generic
|
169
165
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3
|
4
|
+
|
5
|
+
# Adds support for memoizing functions.
|
6
|
+
#
|
7
|
+
# @since 3.2.0
|
8
|
+
module Memoization
|
9
|
+
|
10
|
+
CACHE = {}
|
11
|
+
|
12
|
+
# Memoizes the method with the given name. The modified method will cache
|
13
|
+
# the results of the original method, so that calling a method twice with
|
14
|
+
# the same arguments will short-circuit and return the cached results
|
15
|
+
# immediately.
|
16
|
+
#
|
17
|
+
# Memoization assumes that the current object as well as the function
|
18
|
+
# arguments are immutable. Mutating the object or the arguments will not
|
19
|
+
# cause memoized methods to recalculate their results. There is no way to
|
20
|
+
# un-memoize a result, and calculation results will remain in memory even
|
21
|
+
# if they are no longer needed.
|
22
|
+
#
|
23
|
+
# @example A fast fib function due to memoization
|
24
|
+
#
|
25
|
+
# class FibFast
|
26
|
+
#
|
27
|
+
# extend Nanoc3::Memoization
|
28
|
+
#
|
29
|
+
# def run(n)
|
30
|
+
# if n == 0
|
31
|
+
# 0
|
32
|
+
# elsif n == 1
|
33
|
+
# 1
|
34
|
+
# else
|
35
|
+
# run(n-1) + run(n-2)
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
# memoize :run
|
39
|
+
#
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# @param [Symbol, String] method_name The name of the method to memoize
|
43
|
+
#
|
44
|
+
# @return [void]
|
45
|
+
def memoize(method_name)
|
46
|
+
# Alias
|
47
|
+
original_method_name = '__nonmemoized_' + method_name.to_s
|
48
|
+
alias_method original_method_name, method_name
|
49
|
+
|
50
|
+
# Redefine
|
51
|
+
define_method(method_name) do |*args|
|
52
|
+
# Get method-specific cache
|
53
|
+
key = [ self, method_name ]
|
54
|
+
if !CACHE.has_key?(key)
|
55
|
+
CACHE[key] = {}
|
56
|
+
end
|
57
|
+
method_cache = CACHE[key]
|
58
|
+
|
59
|
+
# Recalculate if necessary
|
60
|
+
if !method_cache.has_key?(args)
|
61
|
+
result = send(original_method_name, *args)
|
62
|
+
method_cache[args] = result
|
63
|
+
end
|
64
|
+
|
65
|
+
# Done
|
66
|
+
method_cache[args]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|