nanoc 4.0.2 → 4.1.0a1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +17 -0
  3. data/Gemfile +50 -46
  4. data/Gemfile.lock +365 -0
  5. data/Guardfile +3 -0
  6. data/NEWS.md +21 -0
  7. data/README.md +1 -1
  8. data/lib/nanoc/base.rb +3 -15
  9. data/lib/nanoc/base/checksummer.rb +3 -14
  10. data/lib/nanoc/base/compilation/compiler.rb +112 -283
  11. data/lib/nanoc/base/compilation/compiler_dsl.rb +29 -37
  12. data/lib/nanoc/base/compilation/dependency_tracker.rb +25 -170
  13. data/lib/nanoc/base/compilation/filter.rb +3 -4
  14. data/lib/nanoc/base/compilation/item_rep_repo.rb +33 -0
  15. data/lib/nanoc/base/compilation/outdatedness_checker.rb +39 -53
  16. data/lib/nanoc/base/compilation/rule.rb +13 -24
  17. data/lib/nanoc/base/compilation/rule_context.rb +29 -15
  18. data/lib/nanoc/base/entities.rb +10 -0
  19. data/lib/nanoc/base/{source_data → entities}/code_snippet.rb +1 -4
  20. data/lib/nanoc/base/{source_data → entities}/configuration.rb +1 -1
  21. data/lib/nanoc/base/entities/content.rb +8 -9
  22. data/lib/nanoc/base/{identifiable_collection.rb → entities/identifiable_collection.rb} +0 -0
  23. data/lib/nanoc/base/entities/identifier.rb +11 -2
  24. data/lib/nanoc/base/{source_data → entities}/item.rb +0 -18
  25. data/lib/nanoc/base/{result_data → entities}/item_rep.rb +15 -13
  26. data/lib/nanoc/base/entities/rule_memory.rb +54 -0
  27. data/lib/nanoc/base/entities/rule_memory_action.rb +19 -0
  28. data/lib/nanoc/base/entities/rule_memory_actions.rb +3 -0
  29. data/lib/nanoc/base/entities/rule_memory_actions/filter.rb +22 -0
  30. data/lib/nanoc/base/entities/rule_memory_actions/layout.rb +22 -0
  31. data/lib/nanoc/base/entities/rule_memory_actions/snapshot.rb +26 -0
  32. data/lib/nanoc/base/entities/rules_collection.rb +120 -0
  33. data/lib/nanoc/base/{source_data → entities}/site.rb +11 -10
  34. data/lib/nanoc/base/repos.rb +2 -0
  35. data/lib/nanoc/base/repos/checksum_store.rb +3 -9
  36. data/lib/nanoc/base/repos/compiled_content_cache.rb +0 -5
  37. data/lib/nanoc/base/{source_data → repos}/data_source.rb +3 -6
  38. data/lib/nanoc/base/repos/dependency_store.rb +118 -0
  39. data/lib/nanoc/base/repos/rule_memory_store.rb +1 -5
  40. data/lib/nanoc/base/repos/site_loader.rb +0 -28
  41. data/lib/nanoc/base/repos/store.rb +0 -12
  42. data/lib/nanoc/base/services.rb +8 -0
  43. data/lib/nanoc/base/services/compiler_loader.rb +49 -0
  44. data/lib/nanoc/base/services/executor.rb +4 -4
  45. data/lib/nanoc/base/services/item_rep_builder.rb +30 -0
  46. data/lib/nanoc/base/services/item_rep_router.rb +55 -0
  47. data/lib/nanoc/base/services/item_rep_selector.rb +39 -0
  48. data/lib/nanoc/base/services/item_rep_writer.rb +2 -0
  49. data/lib/nanoc/base/services/postprocessor.rb +26 -0
  50. data/lib/nanoc/base/services/preprocessor.rb +26 -0
  51. data/lib/nanoc/base/services/recording_executor.rb +36 -22
  52. data/lib/nanoc/base/services/rule_memory_calculator.rb +84 -0
  53. data/lib/nanoc/base/services/rules_loader.rb +29 -0
  54. data/lib/nanoc/base/views.rb +6 -0
  55. data/lib/nanoc/base/views/config_view.rb +8 -2
  56. data/lib/nanoc/base/views/identifiable_collection_view.rb +5 -4
  57. data/lib/nanoc/base/views/item_rep_collection_view.rb +7 -6
  58. data/lib/nanoc/base/views/item_rep_view.rb +13 -12
  59. data/lib/nanoc/base/views/item_view.rb +18 -12
  60. data/lib/nanoc/base/views/layout_view.rb +1 -1
  61. data/lib/nanoc/base/views/mixins/document_view_mixin.rb +2 -1
  62. data/lib/nanoc/base/views/mutable_identifiable_collection_view.rb +1 -1
  63. data/lib/nanoc/base/views/mutable_item_collection_view.rb +4 -7
  64. data/lib/nanoc/base/views/post_compile_item_collection_view.rb +8 -0
  65. data/lib/nanoc/base/views/post_compile_item_view.rb +7 -0
  66. data/lib/nanoc/base/views/site_view.rb +3 -2
  67. data/lib/nanoc/base/views/view.rb +12 -0
  68. data/lib/nanoc/base/views/view_context.rb +12 -0
  69. data/lib/nanoc/cli/commands/compile.rb +13 -15
  70. data/lib/nanoc/cli/commands/create-site.rb +15 -0
  71. data/lib/nanoc/cli/commands/prune.rb +1 -1
  72. data/lib/nanoc/cli/commands/shell.rb +3 -3
  73. data/lib/nanoc/cli/commands/show-data.rb +5 -5
  74. data/lib/nanoc/cli/commands/show-rules.rb +2 -1
  75. data/lib/nanoc/cli/error_handler.rb +28 -30
  76. data/lib/nanoc/cli/stream_cleaners/ansi_colors.rb +1 -1
  77. data/lib/nanoc/data_sources/filesystem.rb +1 -1
  78. data/lib/nanoc/extra/checking/check.rb +8 -7
  79. data/lib/nanoc/extra/checking/checks/external_links.rb +14 -1
  80. data/lib/nanoc/extra/checking/runner.rb +1 -1
  81. data/lib/nanoc/extra/deployer.rb +3 -3
  82. data/lib/nanoc/extra/piper.rb +5 -5
  83. data/lib/nanoc/extra/pruner.rb +8 -7
  84. data/lib/nanoc/filters/relativize_paths.rb +48 -32
  85. data/lib/nanoc/filters/sass/sass_filesystem_importer.rb +0 -1
  86. data/lib/nanoc/helpers/blogging.rb +15 -7
  87. data/lib/nanoc/helpers/capturing.rb +56 -13
  88. data/lib/nanoc/helpers/link_to.rb +2 -2
  89. data/lib/nanoc/helpers/tagging.rb +5 -10
  90. data/lib/nanoc/helpers/text.rb +9 -11
  91. data/lib/nanoc/version.rb +1 -1
  92. data/nanoc-4.0.2.gem +0 -0
  93. data/tags +1175 -0
  94. data/test/base/test_compiler.rb +48 -98
  95. data/test/base/test_compiler_dsl.rb +113 -39
  96. data/test/base/test_dependency_tracker.rb +80 -79
  97. data/test/base/test_outdatedness_checker.rb +39 -26
  98. data/test/base/test_site.rb +0 -97
  99. data/test/cli/commands/test_compile.rb +2 -3
  100. data/test/extra/checking/checks/test_external_links.rb +25 -0
  101. data/test/extra/deployers/test_fog.rb +12 -6
  102. data/test/filters/test_erb.rb +1 -1
  103. data/test/filters/test_erubis.rb +1 -1
  104. data/test/filters/test_haml.rb +1 -1
  105. data/test/filters/test_less.rb +4 -4
  106. data/test/filters/test_sass.rb +1 -0
  107. data/test/filters/test_xsl.rb +7 -8
  108. data/test/helper.rb +0 -2
  109. data/test/helpers/test_blogging.rb +26 -23
  110. data/test/helpers/test_capturing.rb +131 -12
  111. data/test/helpers/test_filtering.rb +6 -6
  112. data/test/helpers/test_link_to.rb +1 -1
  113. data/test/helpers/test_rendering.rb +16 -24
  114. data/test/helpers/test_tagging.rb +13 -10
  115. data/test/helpers/test_xml_sitemap.rb +25 -21
  116. metadata +36 -14
  117. data/lib/nanoc/base/compilation/rule_memory_calculator.rb +0 -35
  118. data/lib/nanoc/base/compilation/rules_collection.rb +0 -245
  119. data/test/base/test_rule_context.rb +0 -78
@@ -50,8 +50,7 @@ module Nanoc::Int
50
50
  # @param [String] identifier A pattern matching identifiers of items that
51
51
  # should be compiled using this rule
52
52
  #
53
- # @option params [Symbol] :rep (:default) The name of the representation
54
- # that should be compiled using this rule
53
+ # @param [Symbol] rep The name of the representation
55
54
  #
56
55
  # @yield The block that will be executed when an item matching this
57
56
  # compilation rule needs to be compiled
@@ -69,15 +68,10 @@ module Nanoc::Int
69
68
  # compile '/bar/', :rep => :raw do
70
69
  # # do nothing
71
70
  # end
72
- def compile(identifier, params = {}, &block)
73
- # Require block
71
+ def compile(identifier, rep: :default, &block)
74
72
  raise ArgumentError.new('#compile requires a block') unless block_given?
75
73
 
76
- # Get rep name
77
- rep_name = params[:rep] || :default
78
-
79
- # Create rule
80
- rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep_name, block)
74
+ rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep, block)
81
75
  @rules_collection.add_item_compilation_rule(rule)
82
76
  end
83
77
 
@@ -94,8 +88,7 @@ module Nanoc::Int
94
88
  # @param [String] identifier A pattern matching identifiers of items that
95
89
  # should be routed using this rule
96
90
  #
97
- # @option params [Symbol] :rep (:default) The name of the representation
98
- # that should be routed using this rule
91
+ # @param [Symbol] :rep The name of the representation
99
92
  #
100
93
  # @yield The block that will be executed when an item matching this
101
94
  # compilation rule needs to be routed
@@ -113,16 +106,10 @@ module Nanoc::Int
113
106
  # route '/bar/', :rep => :raw do
114
107
  # '/raw' + item.identifier + 'index.txt'
115
108
  # end
116
- def route(identifier, params = {}, &block)
117
- # Require block
109
+ def route(identifier, rep: :default, snapshot: :last, &block)
118
110
  raise ArgumentError.new('#route requires a block') unless block_given?
119
111
 
120
- # Get rep name
121
- rep_name = params[:rep] || :default
122
- snapshot_name = params[:snapshot] || :last
123
-
124
- # Create rule
125
- rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep_name, block, snapshot_name: snapshot_name)
112
+ rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep, block, snapshot_name: snapshot)
126
113
  @rules_collection.add_item_routing_rule(rule)
127
114
  end
128
115
 
@@ -166,8 +153,7 @@ module Nanoc::Int
166
153
  # @param [String] identifier A pattern matching identifiers of items that
167
154
  # should be processed using this meta-rule
168
155
  #
169
- # @option params [Symbol] :rep (:default) The name of the representation
170
- # that should be routed using this rule
156
+ # @param [Symbol] rep The name of the representation
171
157
  #
172
158
  # @return [void]
173
159
  #
@@ -180,16 +166,11 @@ module Nanoc::Int
180
166
  # @example Copying the `:raw` rep of the `/bar/` item as-is
181
167
  #
182
168
  # passthrough '/bar/', :rep => :raw
183
- def passthrough(identifier, params = {})
184
- # Require no block
169
+ def passthrough(identifier, rep: :default)
185
170
  raise ArgumentError.new('#passthrough does not require a block') if block_given?
186
171
 
187
- # Get rep name
188
- rep_name = params[:rep] || :default
189
-
190
- # Create compilation rule
191
172
  compilation_block = proc {}
192
- compilation_rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep_name, compilation_block)
173
+ compilation_rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep, compilation_block)
193
174
  @rules_collection.add_item_compilation_rule(compilation_rule)
194
175
 
195
176
  # Create routing rule
@@ -204,7 +185,7 @@ module Nanoc::Int
204
185
  item[:extension].nil? || (item[:content_filename].nil? && item.identifier =~ %r{#{item[:extension]}/$}) ? item.identifier.chop : item.identifier.chop + '.' + item[:extension]
205
186
  end
206
187
  end
207
- routing_rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep_name, routing_block, snapshot_name: :last)
188
+ routing_rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep, routing_block, snapshot_name: :last)
208
189
  @rules_collection.add_item_routing_rule(routing_rule)
209
190
  end
210
191
 
@@ -219,23 +200,20 @@ module Nanoc::Int
219
200
  # @param [String] identifier A pattern matching identifiers of items that
220
201
  # should be processed using this meta-rule
221
202
  #
222
- # @option params [Symbol] :rep (:default) The name of the representation
223
- # that should be routed using this rule
203
+ # @param [Symbol] rep The name of the representation
224
204
  #
225
205
  # @return [void]
226
206
  #
227
207
  # @example Suppressing compilation and output for all all `/foo/*` items.
228
208
  #
229
209
  # ignore '/foo/*'
230
- def ignore(identifier, params = {})
210
+ def ignore(identifier, rep: :default)
231
211
  raise ArgumentError.new('#ignore does not require a block') if block_given?
232
212
 
233
- rep_name = params[:rep] || :default
234
-
235
- compilation_rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep_name, proc {})
213
+ compilation_rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep, proc {})
236
214
  @rules_collection.add_item_compilation_rule(compilation_rule)
237
215
 
238
- routing_rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep_name, proc {}, snapshot_name: :last)
216
+ routing_rule = Nanoc::Int::Rule.new(create_pattern(identifier), rep, proc {}, snapshot_name: :last)
239
217
  @rules_collection.add_item_routing_rule(routing_rule)
240
218
  end
241
219
 
@@ -255,7 +233,21 @@ module Nanoc::Int
255
233
  filename = ["#{name}", "#{name}.rb", "./#{name}", "./#{name}.rb"].find { |f| File.file?(f) }
256
234
  raise Nanoc::Int::Errors::NoRulesFileFound.new if filename.nil?
257
235
 
258
- @rules_collection.parse(filename)
236
+ Nanoc::Int::RulesLoader.new(@config, @rules_collection).parse(filename)
237
+ end
238
+
239
+ # Creates a postprocessor block that will be executed after all data is
240
+ # loaded and the site is compiled.
241
+ #
242
+ # @yield The block that will be executed after site compilation completes
243
+ #
244
+ # @return [void]
245
+ def postprocess(&block)
246
+ if @rules_collection.postprocessors[rules_filename]
247
+ warn 'WARNING: A postprocess block is already defined. Defining ' \
248
+ 'another postprocess block overrides the previously one.'
249
+ end
250
+ @rules_collection.postprocessors[rules_filename] = block
259
251
  end
260
252
 
261
253
  # @api private
@@ -1,193 +1,48 @@
1
1
  module Nanoc::Int
2
- # Responsible for remembering dependencies between items and layouts. It is
3
- # used to speed up compilation by only letting an item be recompiled when it
4
- # is outdated or any of its dependencies (or dependencies’ dependencies,
5
- # etc) is outdated.
6
- #
7
- # The dependencies tracked by the dependency tracker are not dependencies
8
- # based on an item’s or a layout’s content. When one object uses an
9
- # attribute of another object, then this is also treated as a dependency.
10
- # While dependencies based on an item’s or layout’s content (handled in
11
- # {Nanoc::Int::Compiler}) cannot be mutually recursive, the more general
12
- # dependencies in Nanoc::Int::DependencyTracker can (e.g. item A can use an
13
- # attribute of item B and vice versa without problems).
14
- #
15
- # The dependency tracker remembers the dependency information between runs.
16
- # Dependency information is stored in the `tmp/dependencies` file.
17
- #
18
2
  # @api private
19
- class DependencyTracker < ::Nanoc::Int::Store
20
- # @return [Array<Nanoc::Int::Item, Nanoc::Int::Layout>] The list of items and
21
- # layouts that are being tracked by the dependency tracker
22
- attr_reader :objects
23
-
24
- # @return [Nanoc::Int::Compiler] The compiler that corresponds to this
25
- # dependency tracker
26
- attr_accessor :compiler
27
-
28
- # Creates a new dependency tracker for the given items and layouts.
29
- #
30
- # @param [Array<Nanoc::Int::Item, Nanoc::Int::Layout>] objects The list of items
31
- # and layouts whose dependencies should be managed
32
- def initialize(objects)
33
- super('tmp/dependencies', 4)
34
-
35
- @objects = objects
36
- @graph = Nanoc::Int::DirectedGraph.new([nil] + @objects)
37
- @stack = []
3
+ class DependencyTracker
4
+ def initialize(dependency_store)
5
+ @dependency_store = dependency_store
38
6
  end
39
7
 
40
- # Starts listening for dependency messages (`:visit_started` and
41
- # `:visit_ended`) and start recording dependencies.
8
+ # Record dependencies for the duration of the block.
42
9
  #
43
10
  # @return [void]
44
- def start
45
- # Initialize dependency stack. An object will be pushed onto this stack
46
- # when it is visited. Therefore, an object on the stack always depends
47
- # on all objects pushed above it.
48
- @stack = []
11
+ def run
12
+ unless block_given?
13
+ raise ArgumentError, 'No block given'
14
+ end
15
+
16
+ stack = []
17
+ start_tracking(stack)
18
+ yield
19
+ ensure
20
+ stop_tracking(stack)
21
+ end
49
22
 
50
- # Register start of visits
23
+ # @api private
24
+ def start_tracking(stack)
51
25
  Nanoc::Int::NotificationCenter.on(:visit_started, self) do |obj|
52
- unless @stack.empty?
53
- Nanoc::Int::NotificationCenter.post(:dependency_created, @stack.last, obj)
54
- record_dependency(@stack.last, obj)
26
+ unless stack.empty?
27
+ Nanoc::Int::NotificationCenter.post(:dependency_created, stack.last, obj)
28
+ @dependency_store.record_dependency(stack.last, obj)
55
29
  end
56
- @stack.push(obj)
30
+ stack.push(obj)
57
31
  end
58
32
 
59
- # Register end of visits
60
33
  Nanoc::Int::NotificationCenter.on(:visit_ended, self) do |_obj|
61
- @stack.pop
34
+ stack.pop
62
35
  end
63
36
  end
64
37
 
65
- # Stop listening for dependency messages and stop recording dependencies.
66
- #
67
- # @return [void]
68
- def stop
69
- # Sanity check
70
- unless @stack.empty?
38
+ # @api private
39
+ def stop_tracking(stack)
40
+ unless stack.empty?
71
41
  raise 'Internal inconsistency: dependency tracker stack not empty at end of compilation'
72
42
  end
73
43
 
74
- # Unregister
75
44
  Nanoc::Int::NotificationCenter.remove(:visit_started, self)
76
45
  Nanoc::Int::NotificationCenter.remove(:visit_ended, self)
77
46
  end
78
-
79
- # @return The topmost item on the stack, i.e. the one currently being
80
- # compiled
81
- def top
82
- @stack.last
83
- end
84
-
85
- # Returns the direct dependencies for the given object.
86
- #
87
- # The direct dependencies of the given object include the items and
88
- # layouts that, when outdated will cause the given object to be marked as
89
- # outdated. Indirect dependencies will not be returned (e.g. if A depends
90
- # on B which depends on C, then the direct dependencies of A do not
91
- # include C).
92
- #
93
- # The direct predecessors can include nil, which indicates an item that is
94
- # no longer present in the site.
95
- #
96
- # @param [Nanoc::Int::Item, Nanoc::Int::Layout] object The object for
97
- # which to fetch the direct predecessors
98
- #
99
- # @return [Array<Nanoc::Int::Item, Nanoc::Int::Layout, nil>] The direct
100
- # predecessors of
101
- # the given object
102
- def objects_causing_outdatedness_of(object)
103
- @graph.direct_predecessors_of(object)
104
- end
105
-
106
- # Returns the direct inverse dependencies for the given object.
107
- #
108
- # The direct inverse dependencies of the given object include the objects
109
- # that will be marked as outdated when the given object is outdated.
110
- # Indirect dependencies will not be returned (e.g. if A depends on B which
111
- # depends on C, then the direct inverse dependencies of C do not include
112
- # A).
113
- #
114
- # @param [Nanoc::Int::Item, Nanoc::Int::Layout] object The object for which to
115
- # fetch the direct successors
116
- #
117
- # @return [Array<Nanoc::Int::Item, Nanoc::Int::Layout>] The direct successors of
118
- # the given object
119
- def objects_outdated_due_to(object)
120
- @graph.direct_successors_of(object).compact
121
- end
122
-
123
- # Records a dependency from `src` to `dst` in the dependency graph. When
124
- # `dst` is oudated, `src` will also become outdated.
125
- #
126
- # @param [Nanoc::Int::Item, Nanoc::Int::Layout] src The source of the dependency,
127
- # i.e. the object that will become outdated if dst is outdated
128
- #
129
- # @param [Nanoc::Int::Item, Nanoc::Int::Layout] dst The destination of the
130
- # dependency, i.e. the object that will cause the source to become
131
- # outdated if the destination is outdated
132
- #
133
- # @return [void]
134
- def record_dependency(src, dst)
135
- # Warning! dst and src are *reversed* here!
136
- @graph.add_edge(dst, src) unless src == dst
137
- end
138
-
139
- # Empties the list of dependencies for the given object. This is necessary
140
- # before recompiling the given object, because otherwise old dependencies
141
- # will stick around and new dependencies will appear twice. This function
142
- # removes all incoming edges for the given vertex.
143
- #
144
- # @param [Nanoc::Int::Item, Nanoc::Int::Layout] object The object for which to
145
- # forget all dependencies
146
- #
147
- # @return [void]
148
- def forget_dependencies_for(object)
149
- @graph.delete_edges_to(object)
150
- end
151
-
152
- # @see Nanoc::Int::Store#unload
153
- def unload
154
- @graph = Nanoc::Int::DirectedGraph.new([nil] + @objects)
155
- end
156
-
157
- protected
158
-
159
- def data
160
- {
161
- edges: @graph.edges,
162
- vertices: @graph.vertices.map { |obj| obj && obj.reference },
163
- }
164
- end
165
-
166
- def data=(new_data)
167
- # Create new graph
168
- @graph = Nanoc::Int::DirectedGraph.new([nil] + @objects)
169
-
170
- # Load vertices
171
- previous_objects = new_data[:vertices].map do |reference|
172
- @objects.find { |obj| reference == obj.reference }
173
- end
174
-
175
- # Load edges
176
- new_data[:edges].each do |edge|
177
- from_index, to_index = *edge
178
- from = from_index && previous_objects[from_index]
179
- to = to_index && previous_objects[to_index]
180
- @graph.add_edge(from, to)
181
- end
182
-
183
- # Record dependency from all items on new items
184
- new_objects = (@objects - previous_objects)
185
- new_objects.each do |new_obj|
186
- @objects.each do |obj|
187
- next unless obj.is_a?(Nanoc::Int::Item)
188
- @graph.add_edge(new_obj, obj)
189
- end
190
- end
191
- end
192
47
  end
193
48
  end
@@ -181,11 +181,10 @@ module Nanoc
181
181
  # the given collection of items. In other words, require the given items
182
182
  # to be compiled first before this items is processed.
183
183
  #
184
- # @param [Array<Nanoc::Int::Item>] items The items that are depended on.
185
- #
186
184
  # @return [void]
187
185
  def depend_on(items)
188
- items = items.map { |i| i.unwrap rescue i }
186
+ orig_items = items
187
+ items = items.map { |i| i.is_a?(Nanoc::ItemView) ? i.unwrap : i }
189
188
 
190
189
  # Notify
191
190
  items.each do |item|
@@ -195,7 +194,7 @@ module Nanoc
195
194
 
196
195
  # Raise unmet dependency error if necessary
197
196
  items.each do |item|
198
- rep = item.reps.find { |r| !r.compiled? }
197
+ rep = orig_items.sample._context.reps[item].find { |r| !r.compiled? }
199
198
  raise Nanoc::Int::Errors::UnmetDependency.new(rep) if rep
200
199
  end
201
200
  end
@@ -0,0 +1,33 @@
1
+ module Nanoc::Int
2
+ # Stores item reps (in memory).
3
+ #
4
+ # @api private
5
+ class ItemRepRepo
6
+ include Enumerable
7
+
8
+ def initialize
9
+ @reps = []
10
+ @reps_by_item = {}
11
+ end
12
+
13
+ def <<(rep)
14
+ @reps << rep
15
+
16
+ @reps_by_item[rep.item] ||= []
17
+ @reps_by_item[rep.item] << rep
18
+ end
19
+
20
+ def to_a
21
+ @reps
22
+ end
23
+
24
+ def each(&block)
25
+ @reps.each(&block)
26
+ self
27
+ end
28
+
29
+ def [](item)
30
+ @reps_by_item.fetch(item, [])
31
+ end
32
+ end
33
+ end
@@ -5,24 +5,30 @@ module Nanoc::Int
5
5
  class OutdatednessChecker
6
6
  extend Nanoc::Int::Memoization
7
7
 
8
- # @option params [Nanoc::Int::Site] :site (nil) The site this outdatedness
9
- # checker belongs to.
10
- #
11
- # @option params [Nanoc::Int::ChecksumStore] :checksum_store (nil) The
12
- # checksum store where checksums of items, layouts, … are stored.
13
- #
14
- # @option params [Nanoc::Int::DependencyTracker] :dependency_tracker (nil) The
15
- # dependency tracker for the given site.
16
- def initialize(params = {})
17
- @site = params.fetch(:site) do
18
- raise ArgumentError, 'Nanoc::Int::OutdatednessChecker#initialize needs a :site parameter'
19
- end
20
- @checksum_store = params.fetch(:checksum_store) do
21
- raise ArgumentError, 'Nanoc::Int::OutdatednessChecker#initialize needs a :checksum_store parameter'
22
- end
23
- @dependency_tracker = params.fetch(:dependency_tracker) do
24
- raise ArgumentError, 'Nanoc::Int::OutdatednessChecker#initialize needs a :dependency_tracker parameter'
25
- end
8
+ attr_reader :checksum_store
9
+ attr_reader :dependency_store
10
+ attr_reader :rule_memory_calculator
11
+ attr_reader :rule_memory_store
12
+ attr_reader :rules_collection
13
+ attr_reader :site
14
+
15
+ Reasons = Nanoc::Int::OutdatednessReasons
16
+
17
+ # @param [Nanoc::Int::Site] site
18
+ # @param [Nanoc::Int::ChecksumStore] checksum_store
19
+ # @param [Nanoc::Int::DependencyStore] dependency_store
20
+ # @param [Nanoc::Int::RulesCollection] rules_collection
21
+ # @param [Nanoc::Int::RuleMemoryStore] rule_memory_store
22
+ # @param [Nanoc::Int::RuleMemoryCalculator] rule_memory_calculator
23
+ # @param [Nanoc::Int::ItemRepRepo] reps
24
+ def initialize(site:, checksum_store:, dependency_store:, rules_collection:, rule_memory_store:, rule_memory_calculator:, reps:)
25
+ @site = site
26
+ @checksum_store = checksum_store
27
+ @dependency_store = dependency_store
28
+ @rules_collection = rules_collection
29
+ @rule_memory_store = rule_memory_store
30
+ @rule_memory_calculator = rule_memory_calculator
31
+ @reps = reps
26
32
 
27
33
  @basic_outdatedness_reasons = {}
28
34
  @outdatedness_reasons = {}
@@ -45,12 +51,12 @@ module Nanoc::Int
45
51
  # @param [Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] obj The object
46
52
  # whose outdatedness reason should be calculated.
47
53
  #
48
- # @return [Nanoc::Int::OutdatednessReasons::Generic, nil] The reason why the
54
+ # @return [Reasons::Generic, nil] The reason why the
49
55
  # given object is outdated, or nil if the object is not outdated.
50
56
  def outdatedness_reason_for(obj)
51
57
  reason = basic_outdatedness_reason_for(obj)
52
58
  if reason.nil? && outdated_due_to_dependencies?(obj)
53
- reason = Nanoc::Int::OutdatednessReasons::DependenciesOutdated
59
+ reason = Reasons::DependenciesOutdated
54
60
  end
55
61
  reason
56
62
  end
@@ -78,42 +84,42 @@ module Nanoc::Int
78
84
  # @param [Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] obj The object
79
85
  # whose outdatedness reason should be calculated.
80
86
  #
81
- # @return [Nanoc::Int::OutdatednessReasons::Generic, nil] The reason why the
87
+ # @return [Reasons::Generic, nil] The reason why the
82
88
  # given object is outdated, or nil if the object is not outdated.
83
89
  def basic_outdatedness_reason_for(obj)
84
90
  case obj
85
91
  when Nanoc::Int::ItemRep
86
92
  # Outdated if rules outdated
87
- return Nanoc::Int::OutdatednessReasons::RulesModified if
93
+ return Reasons::RulesModified if
88
94
  rule_memory_differs_for(obj)
89
95
 
90
96
  # Outdated if checksums are missing or different
91
- return Nanoc::Int::OutdatednessReasons::NotEnoughData unless checksums_available?(obj.item)
92
- return Nanoc::Int::OutdatednessReasons::SourceModified unless checksums_identical?(obj.item)
97
+ return Reasons::NotEnoughData unless checksums_available?(obj.item)
98
+ return Reasons::SourceModified unless checksums_identical?(obj.item)
93
99
 
94
100
  # Outdated if compiled file doesn't exist (yet)
95
- return Nanoc::Int::OutdatednessReasons::NotWritten if obj.raw_path && !File.file?(obj.raw_path)
101
+ return Reasons::NotWritten if obj.raw_path && !File.file?(obj.raw_path)
96
102
 
97
103
  # Outdated if code snippets outdated
98
- return Nanoc::Int::OutdatednessReasons::CodeSnippetsModified if site.code_snippets.any? do |cs|
104
+ return Reasons::CodeSnippetsModified if site.code_snippets.any? do |cs|
99
105
  object_modified?(cs)
100
106
  end
101
107
 
102
108
  # Outdated if configuration outdated
103
- return Nanoc::Int::OutdatednessReasons::ConfigurationModified if object_modified?(site.config)
109
+ return Reasons::ConfigurationModified if object_modified?(site.config)
104
110
 
105
111
  # Not outdated
106
112
  return nil
107
113
  when Nanoc::Int::Item
108
- obj.reps.find { |rep| basic_outdatedness_reason_for(rep) }
114
+ @reps[obj].find { |rep| basic_outdatedness_reason_for(rep) }
109
115
  when Nanoc::Int::Layout
110
116
  # Outdated if rules outdated
111
- return Nanoc::Int::OutdatednessReasons::RulesModified if
117
+ return Reasons::RulesModified if
112
118
  rule_memory_differs_for(obj)
113
119
 
114
120
  # Outdated if checksums are missing or different
115
- return Nanoc::Int::OutdatednessReasons::NotEnoughData unless checksums_available?(obj)
116
- return Nanoc::Int::OutdatednessReasons::SourceModified unless checksums_identical?(obj)
121
+ return Reasons::NotEnoughData unless checksums_available?(obj)
122
+ return Reasons::SourceModified unless checksums_identical?(obj)
117
123
 
118
124
  # Not outdated
119
125
  return nil
@@ -149,7 +155,7 @@ module Nanoc::Int
149
155
  return false if processed.include?(obj)
150
156
 
151
157
  # Calculate
152
- is_outdated = dependency_tracker.objects_causing_outdatedness_of(obj).any? do |other|
158
+ is_outdated = dependency_store.objects_causing_outdatedness_of(obj).any? do |other|
153
159
  other.nil? || basic_outdated?(other) || outdated_due_to_dependencies?(other, processed.merge([obj]))
154
160
  end
155
161
 
@@ -166,7 +172,7 @@ module Nanoc::Int
166
172
  # @return [Boolean] true if the rule memory for the given item
167
173
  # represenation has changed, false otherwise
168
174
  def rule_memory_differs_for(obj)
169
- rules_collection.rule_memory_differs_for(obj)
175
+ !rule_memory_store[obj].eql?(rule_memory_calculator[obj].serialize)
170
176
  end
171
177
  memoize :rule_memory_differs_for
172
178
 
@@ -196,25 +202,5 @@ module Nanoc::Int
196
202
  !checksums_available?(obj) || !checksums_identical?(obj)
197
203
  end
198
204
  memoize :object_modified?
199
-
200
- # @return [Nanoc::Int::ChecksumStore] The checksum store
201
- def checksum_store
202
- @checksum_store
203
- end
204
-
205
- # @return [Nanoc::Int::RulesCollection] The rules collection
206
- def rules_collection
207
- site.compiler.rules_collection
208
- end
209
-
210
- # @return [Nanoc::Int::DependencyTracker] The dependency tracker
211
- def dependency_tracker
212
- @dependency_tracker
213
- end
214
-
215
- # @return [Nanoc::Int::Site] The site
216
- def site
217
- @site
218
- end
219
205
  end
220
206
  end