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