when a template is modified, all pages inheriting from it are updated too (functional tests are coming)

This commit is contained in:
dinedine 2010-08-23 01:48:11 +02:00
parent 4805d8813e
commit 75783ec881
3 changed files with 72 additions and 15 deletions

View File

@ -7,10 +7,14 @@ module Models
included do included do
field :serialized_template, :type => Binary field :serialized_template, :type => Binary
field :template_dependencies, :type => Array, :default => []
before_validation :serialize_template before_validation :serialize_template
after_save :update_template_descendants
validate :template_must_be_valid validate :template_must_be_valid
scope :pages, lambda { |domain| { :any_in => { :domains => [*domain] } } }
end end
module InstanceMethods module InstanceMethods
@ -21,26 +25,22 @@ module Models
protected protected
def parse def parse(context = {})
@template = ::Liquid::Template.parse(self.raw_template, { :site => self.site, :page => self }) @template = ::Liquid::Template.parse(self.raw_template, { :site => self.site, :page => self }.merge(context))
@template.root.context.clear @template.root.context.clear
# TODO: walk thru the document tree to get parents as well as used snippets self.template_dependencies = parent_templates(@template.root)
# TODO: snippets dependencies
end end
def serialize_template def serialize_template
if self.new_record? || self.raw_template_changed? if self.new_record? || self.raw_template_changed?
@template_changed = true
@parsing_errors = [] @parsing_errors = []
begin begin
self.parse self._serialize_template
self.serialized_template = BSON::Binary.new(Marshal.dump(@template))
# TODO: let other pages inheriting from that one and modify them in consequences
# TODO: build array of parent pages
rescue ::Liquid::SyntaxError => error rescue ::Liquid::SyntaxError => error
@parsing_errors << :liquid_syntax @parsing_errors << :liquid_syntax
rescue ::Locomotive::Liquid::PageNotFound => error rescue ::Locomotive::Liquid::PageNotFound => error
@ -49,10 +49,56 @@ module Models
end end
end end
def _serialize_template(context = {})
self.parse(context)
self.serialized_template = BSON::Binary.new(Marshal.dump(@template))
end
def template_must_be_valid def template_must_be_valid
@parsing_errors.try(:each) { |msg| self.errors.add :template, msg } @parsing_errors.try(:each) { |msg| self.errors.add :template, msg }
end end
def parent_templates(node, templates = [])
templates << node.page_id if node.is_a?(Locomotive::Liquid::Tags::Extends)
if node.respond_to?(:nodelist)
node.nodelist.each do |child|
self.parent_templates(child, templates)
end
end
templates
end
def update_template_descendants
return unless @template_changed == true
# we admit at this point that the current template is up-to-date
descendants = self.site.pages.any_in(:template_dependencies => [self.id]).to_a
# group them by fullpath for better performance
cached = descendants.inject({}) { |memo, page| memo[page.fullpath] = page; memo }
self._update_direct_template_descendants(descendants, cached)
# finally save them all
descendants.map(&:save)
# puts "** first descendant = #{descendants.first.object_id} / #{descendants.first.template.inspect}"
end
def _update_direct_template_descendants(descendants, cached)
direct_descendants = descendants.select do |page|
(page.template_dependencies - self.template_dependencies).size == 1
end
direct_descendants.each do |page|
page.send(:_serialize_template, { :cached_parent => self, :cached_pages => cached })
page.send(:_update_direct_template_descendants, descendants, cached)
end
end
end end
end end

View File

@ -3,17 +3,27 @@ module Locomotive
module Tags module Tags
class Extends < ::Liquid::Extends class Extends < ::Liquid::Extends
attr_accessor :page_id
def parse_parent_template(context) def parse_parent_template(context)
page = nil page = nil
if @template_name == 'parent' if @template_name == 'parent'
page = context[:page].parent if context[:cached_parent]
page = context[:cached_parent]
context[:cached_parent] = nil
else else
page = context[:site].pages.where(:fullpath => @template_name.gsub("'", '')).first page = context[:page].parent
end
else
path = @template_name.gsub("'", '')
page = context[:cached_pages].try(:[], path) || context[:site].pages.where(:fullpath => path).first
end end
raise PageNotFound.new("Page with fullpath '#{@template_name}' was not found") if page.nil? raise PageNotFound.new("Page with fullpath '#{@template_name}' was not found") if page.nil?
@page_id = page.id
template = page.template template = page.template
# merge blocks ? # merge blocks ?

View File

@ -1,7 +1,8 @@
# require "rubygems" # require "rubygems"
# require "ruby-prof" # require "ruby-prof"
ENV["RAILS_ENV"] ||= 'test' ENV["RAILS_ENV"] ||= 'test'
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
require "./" + File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
%w{sites pages layouts}.each do |collection| %w{sites pages layouts}.each do |collection|
Mongoid.master.collection(collection).drop Mongoid.master.collection(collection).drop