forked from nanoc/nanoc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rules_collection.rb
229 lines (198 loc) · 7.17 KB
/
rules_collection.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
module Nanoc3
# Keeps track of the rules in a site.
#
# @api private
class RulesCollection
extend Nanoc3::Memoization
# @return [Array<Nanoc3::Rule>] The list of item compilation rules that
# will be used to compile items.
attr_reader :item_compilation_rules
# @return [Array<Nanoc3::Rule>] The list of routing rules that will be
# used to give all items a path.
attr_reader :item_routing_rules
# The hash containing layout-to-filter mapping rules. This hash is
# ordered: iterating over the hash will happen in insertion order.
#
# @return [Hash] The layout-to-filter mapping rules
attr_reader :layout_filter_mapping
# @return [Proc] The code block that will be executed after all data is
# loaded but before the site is compiled
attr_accessor :preprocessor
# @param [Nanoc3::Compiler] compiler The site’s compiler
def initialize(compiler)
@compiler = compiler
@item_compilation_rules = []
@item_routing_rules = []
@layout_filter_mapping = OrderedHash.new
end
# Add the given rule to the list of item compilation rules.
#
# @param [Nanoc3::Rule] rule The item compilation rule to add
#
# @param [:before, :after] position The place where the rule should be
# added (either at the beginning or the end of the list of rules)
#
# @return [void]
def add_item_compilation_rule(rule, position=:after)
case position
when :before
@item_compilation_rules.unshift(rule)
when :after
@item_compilation_rules << rule
else
raise "#add_item_routing_rule expected position to be :after or :before"
end
end
# Add the given rule to the list of item routing rules.
#
# @param [Nanoc3::Rule] rule The item routing rule to add
#
# @param [:before, :after] position The place where the rule should be
# added (either at the beginning or the end of the list of rules)
#
# @return [void]
def add_item_routing_rule(rule, position=:after)
case position
when :before
@item_routing_rules.unshift(rule)
when :after
@item_routing_rules << rule
else
raise "#add_item_routing_rule expected position to be :after or :before"
end
end
# @param [Nanoc3::Item] item The item for which the compilation rules
# should be retrieved
#
# @return [Array] The list of item compilation rules for the given item
def item_compilation_rules_for(item)
@item_compilation_rules.select { |r| r.applicable_to?(item) }
end
# Loads this site’s rules.
#
# @return [void]
def load
# Find rules file
rules_filenames = [ 'Rules', 'rules', 'Rules.rb', 'rules.rb' ]
rules_filename = rules_filenames.find { |f| File.file?(f) }
raise Nanoc3::Errors::NoRulesFileFound.new if rules_filename.nil?
# Get rule data
@data = File.read(rules_filename)
# Load DSL
dsl.instance_eval(@data, "./#{rules_filename}")
end
# Unloads this site’s rules.
#
# @return [void]
def unload
@item_compilation_rules = []
@item_routing_rules = []
@layout_filter_mapping = OrderedHash.new
end
# Finds the first matching compilation rule for the given item
# representation.
#
# @param [Nanoc3::ItemRep] rep The item rep for which to fetch the rule
#
# @return [Nanoc3::Rule, nil] The compilation rule for the given item rep,
# or nil if no rules have been found
def compilation_rule_for(rep)
@item_compilation_rules.find do |rule|
rule.applicable_to?(rep.item) && rule.rep_name == rep.name
end
end
# Finds the first matching routing rule for the given item representation.
#
# @param [Nanoc3::ItemRep] rep The item rep for which to fetch the rule
#
# @return [Nanoc3::Rule, nil] The routing rule for the given item rep, or
# nil if no rules have been found
def routing_rule_for(rep)
@item_routing_rules.find do |rule|
rule.applicable_to?(rep.item) && rule.rep_name == rep.name
end
end
# Returns the list of routing rules that can be applied to the given item
# representation. For each snapshot, the first matching rule will be
# returned. The result is a hash containing the corresponding rule for
# each snapshot.
#
# @param [Nanoc3::ItemRep] rep The item rep for which to fetch the rules
#
# @return [Hash<Symbol, Nanoc3::Rule>] The routing rules for the given rep
def routing_rules_for(rep)
rules = {}
@item_routing_rules.each do |rule|
next if !rule.applicable_to?(rep.item)
next if rule.rep_name != rep.name
next if rules.has_key?(rule.snapshot_name)
rules[rule.snapshot_name] = rule
end
rules
end
# Finds the filter name and arguments to use for the given layout.
#
# @param [Nanoc3::Layout] layout The layout for which to fetch the filter.
#
# @return [Array, nil] A tuple containing the filter name and the filter
# arguments for the given layout.
def filter_for_layout(layout)
@layout_filter_mapping.each_pair do |layout_identifier, filter_name_and_args|
return filter_name_and_args if layout.identifier =~ layout_identifier
end
nil
end
# Returns the Nanoc3::CompilerDSL that should be used for this site.
def dsl
Nanoc3::CompilerDSL.new(self, @compiler.site.config)
end
memoize :dsl
# Returns an object that can be used for uniquely identifying objects.
#
# @return [Object] An unique reference to this object
def reference
:rules
end
# @return [String] The checksum for this object. If its contents change,
# the checksum will change as well.
def checksum
@data.checksum
end
def inspect
"<#{self.class}:0x#{self.object_id.to_s(16)}>"
end
# @param [Nanoc3::ItemRep] rep The item representation to get the rule
# memory for
#
# @return [Array] The rule memory for the given item representation
def new_rule_memory_for_rep(rep)
recording_proxy = rep.to_recording_proxy
compilation_rule_for(rep).apply_to(recording_proxy, :compiler => @compiler)
recording_proxy.rule_memory
end
memoize :new_rule_memory_for_rep
# @param [Nanoc3::Layout] layout The layout to get the rule memory for
#
# @return [Array] The rule memory for the given layout
def new_rule_memory_for_layout(layout)
filter_for_layout(layout)
end
memoize :new_rule_memory_for_layout
# @param [Nanoc3::Item] obj The object for which to check the rule memory
#
# @return [Boolean] true if the rule memory for the given object has
# changed since the last compilation, false otherwise
def rule_memory_differs_for(obj)
!rule_memory_store[obj].eql?(rule_memory_calculator[obj])
end
memoize :rule_memory_differs_for
# @return [Nanoc3::RuleMemoryStore] The rule memory store
def rule_memory_store
@compiler.rule_memory_store
end
# @return [Nanoc3::RuleMemoryCalculator] The rule memory calculator
def rule_memory_calculator
@compiler.rule_memory_calculator
end
end
end