class Nanoc::Int::Compiler
Responsible for compiling a site’s item representations.
The compilation process makes use of notifications (see {Nanoc::Int::NotificationCenter}) to track dependencies between items, layouts, etc. The following notifications are used:
-
`compilation_started` — indicates that the compiler has started compiling this item representation. Has one argument: the item representation itself. Only one item can be compiled at a given moment; therefore, it is not possible to get two consecutive `compilation_started` notifications without also getting a `compilation_ended` notification in between them.
-
`compilation_ended` — indicates that the compiler has finished compiling this item representation (either successfully or with failure). Has one argument: the item representation itself.
-
`visit_started` — indicates that the compiler requires content or attributes from the item representation that will be visited. Has one argument: the visited item identifier. This notification is used to track dependencies of items on other items; a `visit_started` event followed by another `visit_started` event indicates that the item corresponding to the former event will depend on the item from the latter event.
-
`visit_ended` — indicates that the compiler has finished visiting the item representation and that the requested attributes or content have been fetched (either successfully or with failure)
-
`processing_started` — indicates that the compiler has started processing the specified object, which can be an item representation (when it is compiled) or a layout (when it is used to lay out an item representation or when it is used as a partial)
-
`processing_ended` — indicates that the compiler has finished processing the specified object.
@api private
Attributes
@api private
@api private
@api private
@api private
@api private
@api private
@api private
@api private
The compilation stack. When the compiler begins compiling a rep or a layout, it will be placed on the stack; when it is done compiling the rep or layout, it will be removed from the stack.
@return [Array] The compilation stack
Public Class Methods
# File lib/nanoc/base/compilation/compiler.rb, line 72 def initialize(site, compiled_content_cache,, checksum_store,, rule_memory_store,, action_provider,, dependency_store,, outdatedness_checker,, reps)) @site = site @compiled_content_cache = compiled_content_cache @checksum_store = checksum_store @rule_memory_store = rule_memory_store @dependency_store = dependency_store @outdatedness_checker = outdatedness_checker @reps = reps @action_provider = action_provider @stack = [] end
Public Instance Methods
@param [Nanoc::Int::ItemRep] rep The item representation for which the
assigns should be fetched
@return [Hash] The assigns that should be used in the next filter/layout
operation
@api private
# File lib/nanoc/base/compilation/compiler.rb, line 150 def assigns_for(rep) content_or_filename_assigns = if rep.binary? { filename: rep.snapshot_contents[:last].filename } else { content: rep.snapshot_contents[:last].string } end view_context = create_view_context # TODO: Do not expose @site (necessary for captures store though…) content_or_filename_assigns.merge( item: Nanoc::ItemWithRepsView.new(rep.item, view_context), rep: Nanoc::ItemRepView.new(rep, view_context), item_rep: Nanoc::ItemRepView.new(rep, view_context), items: Nanoc::ItemCollectionWithRepsView.new(site.items, view_context), layouts: Nanoc::LayoutCollectionView.new(site.layouts, view_context), config: Nanoc::ConfigView.new(site.config, view_context), site: Nanoc::SiteView.new(site, view_context), ) end
# File lib/nanoc/base/compilation/compiler.rb, line 137 def build_reps builder = Nanoc::Int::ItemRepBuilder.new( site, action_provider, @reps) builder.run end
# File lib/nanoc/base/compilation/compiler.rb, line 172 def create_view_context Nanoc::ViewContext.new(reps: @reps, items: @site.items) end
@api private
# File lib/nanoc/base/compilation/compiler.rb, line 177 def filter_name_and_args_for_layout(layout) mem = action_provider.memory_for(layout) if mem.nil? || mem.size != 1 || !mem[0].is_a?(Nanoc::Int::RuleMemoryActions::Filter) # FIXME: Provide a nicer error message raise Nanoc::Int::Errors::Generic, "No rule memory found for #{layout.identifier}" end [mem[0].filter_name, mem[0].params] end
# File lib/nanoc/base/compilation/compiler.rb, line 113 def load_stores stores.each(&:load) end
# File lib/nanoc/base/compilation/compiler.rb, line 93 def run load_stores @site.freeze # Determine which reps need to be recompiled forget_dependencies_if_outdated @stack = [] dependency_tracker = Nanoc::Int::DependencyTracker.new(@dependency_store) dependency_tracker.run do compile_reps end store ensure Nanoc::Int::TempFilenameFactory.instance.cleanup( Nanoc::Filter::TMP_BINARY_ITEMS_DIR) Nanoc::Int::TempFilenameFactory.instance.cleanup( Nanoc::Int::ItemRepWriter::TMP_TEXT_ITEMS_DIR) end
# File lib/nanoc/base/compilation/compiler.rb, line 86 def run_all @action_provider.preprocess(@site) build_reps run @action_provider.postprocess(@site, @reps) end
Store the modified helper data used for compiling the site.
@return [void]
# File lib/nanoc/base/compilation/compiler.rb, line 120 def store # Calculate rule memory (@reps.to_a + @site.layouts.to_a).each do |obj| rule_memory_store[obj] = action_provider.memory_for(obj).serialize end # Calculate checksums objects_to_checksum = site.items.to_a + site.layouts.to_a + site.code_snippets + [site.config] objects_to_checksum.each do |obj| checksum_store[obj] = Nanoc::Int::Checksummer.calc(obj) end # Store stores.each(&:store) end
Private Instance Methods
@return [Boolean]
# File lib/nanoc/base/compilation/compiler.rb, line 244 def can_reuse_content_for_rep?(rep) !rep.item.forced_outdated? && !outdatedness_checker.outdated?(rep) && compiled_content_cache[rep] end
Compiles the given item representation.
This method should not be called directly; please use {Nanoc::Int::Compiler#run} instead, and pass this item representation's item as its first argument.
@param [Nanoc::Int::ItemRep] rep The rep that is to be compiled
@return [void]
# File lib/nanoc/base/compilation/compiler.rb, line 218 def compile_rep(rep) Nanoc::Int::NotificationCenter.post(:compilation_started, rep) Nanoc::Int::NotificationCenter.post(:processing_started, rep) Nanoc::Int::NotificationCenter.post(:visit_started, rep.item) if can_reuse_content_for_rep?(rep) Nanoc::Int::NotificationCenter.post(:cached_content_used, rep) rep.snapshot_contents = compiled_content_cache[rep] else recalculate_content_for_rep(rep) end rep.compiled = true compiled_content_cache[rep] = rep.snapshot_contents Nanoc::Int::NotificationCenter.post(:processing_ended, rep) Nanoc::Int::NotificationCenter.post(:compilation_ended, rep) rescue => e rep.forget_progress Nanoc::Int::NotificationCenter.post(:compilation_failed, rep, e) raise e ensure Nanoc::Int::NotificationCenter.post(:visit_ended, rep.item) end
# File lib/nanoc/base/compilation/compiler.rb, line 188 def compile_reps # Listen to processing start/stop Nanoc::Int::NotificationCenter.on(:processing_started, self) { |obj| @stack.push(obj) } Nanoc::Int::NotificationCenter.on(:processing_ended, self) { |_obj| @stack.pop } # Assign snapshots @reps.each do |rep| rep.snapshot_defs = action_provider.snapshots_defs_for(rep) end # Find item reps to compile and compile them selector = Nanoc::Int::ItemRepSelector.new(@reps) selector.each do |rep| @stack = [] compile_rep(rep) end ensure Nanoc::Int::NotificationCenter.remove(:processing_started, self) Nanoc::Int::NotificationCenter.remove(:processing_ended, self) end
Clears the list of dependencies for items that will be recompiled.
@return [void]
# File lib/nanoc/base/compilation/compiler.rb, line 269 def forget_dependencies_if_outdated @site.items.each do |i| if @reps[i].any? { |r| outdatedness_checker.outdated?(r) } @dependency_store.forget_dependencies_for(i) end end end
@return [void]
# File lib/nanoc/base/compilation/compiler.rb, line 249 def recalculate_content_for_rep(rep) executor = Nanoc::Int::Executor.new(self) action_provider.memory_for(rep).each do |action| case action when Nanoc::Int::RuleMemoryActions::Filter executor.filter(rep, action.filter_name, action.params) when Nanoc::Int::RuleMemoryActions::Layout executor.layout(rep, action.layout_identifier, action.params) when Nanoc::Int::RuleMemoryActions::Snapshot executor.snapshot(rep, action.snapshot_name, final: action.final?, path: action.path) else raise "Internal inconsistency: unknown action #{action.inspect}" end end end
Returns all stores that can load/store data that can be used for compilation.
# File lib/nanoc/base/compilation/compiler.rb, line 279 def stores [ checksum_store, compiled_content_cache, @dependency_store, rule_memory_store, ] end