lib/nanoc/base/page.rb in nanoc-2.0.4 vs lib/nanoc/base/page.rb in nanoc-2.1
- old
+ new
@@ -1,160 +1,128 @@
module Nanoc
+
+ # A Nanoc::Page represents a page in a nanoc site. It has content and
+ # attributes, as well as a path. It can also store the modification time to
+ # speed up compilation.
+ #
+ # Each page has a list of page representations or reps (Nanoc::PageRep);
+ # compiling a page actually compiles all of its representations.
class Page
- PAGE_DEFAULTS = {
+ # Default values for pages.
+ DEFAULTS = {
:custom_path => nil,
:extension => 'html',
:filename => 'index',
:filters_pre => [],
:filters_post => [],
- :haml_options => {},
- :is_draft => false,
:layout => 'default',
- :path => nil,
:skip_output => false
}
- attr_reader :attributes
- attr_accessor :parent, :children
+ # The Nanoc::Site this page belongs to.
+ attr_accessor :site
- def initialize(hash, site)
- @site = site
- @compiler = site.compiler
+ # The parent page of this page. This can be nil even for non-root pages.
+ attr_accessor :parent
- @attributes = hash
- @content = { :pre => attribute_named(:uncompiled_content), :post => nil }
+ # The child pages of this page.
+ attr_accessor :children
- @parent = nil
- @children = []
+ # This page's raw, uncompiled content.
+ attr_reader :content
- @filtered_pre = false
- @layouted = false
- @filtered_post = false
- @written = false
- end
+ # A hash containing this page's attributes.
+ attr_accessor :attributes
- # Proxy support
+ # This page's path.
+ attr_reader :path
- def to_proxy
- @proxy ||= PageProxy.new(self)
- end
+ # The time when this page was last modified.
+ attr_reader :mtime
- # Accessors, kind of
+ # This page's list of page representations.
+ attr_reader :reps
- def modified? ; @modified ; end
+ # Creates a new page.
+ #
+ # +content+:: This page's unprocessed content.
+ #
+ # +attributes+:: A hash containing this page's attributes.
+ #
+ # +path+:: This page's path.
+ #
+ # +mtime+:: The time when this page was last modified.
+ def initialize(content, attributes, path, mtime=nil)
+ # Set primary attributes
+ @attributes = attributes.clean
+ @content = content
+ @path = path.cleaned_path
+ @mtime = mtime
- def attribute_named(name)
- return @attributes[name] if @attributes.has_key?(name)
- return @site.page_defaults[name] if @site.page_defaults.has_key?(name)
- return PAGE_DEFAULTS[name]
+ # Start disconnected
+ @parent = nil
+ @children = []
+ @reps = []
end
- def content
- compile(false) unless @filtered_pre
- @content[:pre]
- end
+ # Builds the individual page representations (Nanoc::PageRep) for this
+ # page.
+ def build_reps
+ # Get list of rep names
+ rep_names_default = (@site.page_defaults.attributes[:reps] || {}).keys
+ rep_names_this = (@attributes[:reps] || {}).keys + [ :default ]
+ rep_names = rep_names_default | rep_names_this
- def layouted_content
- compile(true)
- @content[:post]
- end
+ # Get list of reps
+ reps = rep_names.inject({}) do |memo, rep_name|
+ rep = (@attributes[:reps] || {})[rep_name]
+ is_bad = (@attributes[:reps] || {}).has_key?(rep_name) && rep.nil?
+ is_bad ? memo : memo.merge(rep_name => rep || {})
+ end
- def skip_output?
- attribute_named(:skip_output)
+ # Build reps
+ @reps = []
+ reps.each_pair do |name, attrs|
+ @reps << PageRep.new(self, attrs, name)
+ end
end
- def path
- attribute_named(:custom_path) || attribute_named(:path)
+ # Returns a proxy (Nanoc::PageProxy) for this page.
+ def to_proxy
+ @proxy ||= PageProxy.new(self)
end
- def path_on_filesystem
- if attribute_named(:custom_path).nil?
- @site.config[:output_dir] + attribute_named(:path) +
- attribute_named(:filename) + '.' + attribute_named(:extension)
- else
- @site.config[:output_dir] + attribute_named(:custom_path)
- end
+ # Returns the attribute with the given name.
+ def attribute_named(name)
+ return @attributes[name] if @attributes.has_key?(name)
+ return @site.page_defaults.attributes[name] if @site.page_defaults.attributes.has_key?(name)
+ return DEFAULTS[name]
end
- # Compiling
-
- def compile(full=true)
- @modified = false
-
- # Check for recursive call
- if @compiler.stack.include?(self)
- log(:high, "\n" + 'ERROR: Recursive call to page content. Page filter stack:', $stderr)
- log(:high, " - #{self.attribute_named(:path)}", $stderr)
- @compiler.stack.each_with_index do |page, i|
- log(:high, " - #{page.attribute_named(:path)}", $stderr)
- end
- exit(1)
+ # Saves the page in the database, creating it if it doesn't exist yet or
+ # updating it if it already exists. Tells the site's data source to save
+ # the page.
+ def save
+ @site.data_source.loading do
+ @site.data_source.save_page(self)
end
-
- @compiler.stack.push(self)
-
- # Filter pre
- unless @filtered_pre
- filter(:pre)
- @filtered_pre = true
- end
-
- # Layout
- if !@layouted and full
- layout
- @layouted = true
- end
-
- # Filter post
- if !@filtered_post and full
- filter(:post)
- @filtered_post = true
- end
-
- # Write
- if !@written and full
- @modified = FileManager.create_file(self.path_on_filesystem) { @content[:post] } unless skip_output?
- @written = true
- end
-
- @compiler.stack.pop
end
- def filter(stage)
- # Get filters
- error 'The `filters` property is no longer supported; please use `filters_pre` instead.' unless attribute_named(:filters).nil?
- filters = attribute_named(stage == :pre ? :filters_pre : :filters_post)
-
- filters.each do |filter_name|
- # Create filter
- filter_class = PluginManager.filter_named(filter_name)
- error "Unknown filter: '#{filter_name}'" if filter_class.nil?
- filter = filter_class.new(self.to_proxy, @site.pages.map { |p| p.to_proxy }, @site.config, @site)
-
- # Run filter
- @content[stage] = filter.run(@content[stage])
+ # Moves the page to a new path. Tells the site's data source to move the
+ # page.
+ def move_to(new_path)
+ @site.data_source.loading do
+ @site.data_source.move_page(self, new_path)
end
end
- def layout
- # Don't layout if not necessary
- if attribute_named(:layout).nil?
- @content[:post] = @content[:pre]
- return
+ # Deletes the page. Tells the site's data source to delete the page.
+ def delete
+ @site.data_source.loading do
+ @site.data_source.delete_page(self)
end
-
- # Find layout
- layout = @site.layouts.find { |l| l[:name] == attribute_named(:layout) }
- error 'Unknown layout: ' + attribute_named(:layout) if layout.nil?
-
- # Find layout processor
- layout_processor_class = PluginManager.layout_processor_for_extension(layout[:extension])
- error "Unknown layout processor: '#{layout[:extension]}'" if layout_processor_class.nil?
- layout_processor = layout_processor_class.new(self.to_proxy, @site.pages.map { |p| p.to_proxy }, @site.config, @site)
-
- # Layout
- @content[:post] = layout_processor.run(layout[:content])
end
end
+
end