first draft of the new template inheritance mechanism based on our fork of Liquid

This commit is contained in:
dinedine 2010-08-20 02:31:01 +02:00
parent eaf03be8d5
commit 53500bda9e
15 changed files with 109 additions and 196 deletions

19
Gemfile
View File

@ -3,17 +3,14 @@ source 'http://rubygems.org'
gem 'rails', '3.0.0.rc'
# gem 'liquid', '2.0.0'
gem 'liquid', '2.1.2'
# i think we'll need to fork our templating language
# gem 'locomotive-liquid'
gem 'liquid', :git => 'git://github.com/locomotivecms/liquid.git', :ref => 'a41213c77cbc81dab87d'
gem 'bson_ext', '>= 1.0.1'
gem 'mongoid', :git => "git://github.com/durran/mongoid.git", :ref => "e387a0d1dc74da057472"
gem 'mongoid', :git => 'git://github.com/durran/mongoid.git', :ref => 'e387a0d1dc74da057472'
gem 'mongoid_acts_as_tree', '0.1.5'
gem 'mongo_session_store', '2.0.0.pre'
gem 'warden'
gem 'devise', :git => "git://github.com/plataformatec/devise.git"
gem 'devise', :git => 'git://github.com/plataformatec/devise.git'
gem 'haml', '3.0.15'
gem 'rmagick', '2.12.2'
gem 'aws'
@ -40,16 +37,16 @@ group :test, :development do
end
group :test do
gem "autotest"
gem "growl-glue"
gem 'autotest'
gem 'growl-glue'
gem 'rspec-rails', '2.0.0.beta.19'
gem 'factory_girl_rails'
gem "pickle", :git => "http://github.com/codegram/pickle.git"
gem "pickle-mongoid"
gem 'pickle', :git => 'http://github.com/codegram/pickle.git'
gem 'pickle-mongoid'
gem 'capybara'
# would be nice..
# gem "capybara-envjs"
# gem 'capybara-envjs'
gem 'database_cleaner'
gem 'cucumber'

View File

@ -3,6 +3,12 @@ GIT
revision: e387a0d
ref: e387a0d1dc74da057472
specs:
mongoid (2.0.0.beta.15)
activemodel (= 3.0.0.rc)
bson (= 1.0.4)
mongo (= 1.0.6)
tzinfo (= 0.3.22)
will_paginate (~> 3.0.pre)
GIT
remote: git://github.com/floehopper/mocha.git
@ -11,6 +17,13 @@ GIT
mocha (0.9.8.20090918115329)
rake
GIT
remote: git://github.com/locomotivecms/liquid.git
revision: a41213c
ref: a41213c77cbc81dab87d
specs:
liquid (2.1.3)
GIT
remote: git://github.com/plataformatec/devise.git
revision: 01c272c
@ -133,7 +146,6 @@ GEM
configuration (>= 0.0.5)
rake (>= 0.8.1)
linecache (0.43)
liquid (2.1.2)
mail (2.2.5)
activesupport (>= 2.3.6)
mime-types
@ -144,12 +156,6 @@ GEM
bson (>= 1.0.4)
mongo_session_store (2.0.0.pre)
actionpack (~> 3.0)
mongoid (2.0.0.beta.15)
activemodel (= 3.0.0.rc)
bson (= 1.0.4)
mongo (= 1.0.6)
tzinfo (= 0.3.22)
will_paginate (~> 3.0.pre)
mongoid_acts_as_tree (0.1.5)
bson (>= 0.20.1)
mongoid (<= 2.0.0)
@ -252,7 +258,7 @@ DEPENDENCIES
inherited_resources (= 1.1.2)
jeweler
launchy
liquid (= 2.1.2)
liquid!
mimetype-fu
mocha!
mongo_session_store (= 2.0.0.pre)

View File

@ -1,5 +1,8 @@
# @deprecated
class Layout < LiquidTemplate
# acts_as_tree
protected
# TODO: move that in the liquify_template module

View File

@ -67,7 +67,7 @@ class Page
self.slug
else
slugs = self.self_and_ancestors.map(&:slug)
slugs.shift
slugs.shift unless slugs.size == 1
File.join slugs
end
end

View File

@ -1,6 +1,6 @@
%ul
= admin_submenu_item 'site', edit_admin_current_site_url
= admin_submenu_item 'layouts', admin_layouts_url
/ = admin_submenu_item 'layouts', admin_layouts_url
= admin_submenu_item 'snippets', admin_snippets_url
= admin_submenu_item 'theme_assets', admin_theme_assets_url
= admin_submenu_item 'account', edit_admin_my_account_url

View File

@ -8,7 +8,7 @@ Background:
Given I have the site: "test site" set up
Scenario: Liquid Inheritance with a single block
Given a layout named "above_and_below" with the source:
Given a page named "above-and-below" with the template:
"""
<div class="header"></div>
<div class="body">
@ -19,7 +19,7 @@ Scenario: Liquid Inheritance with a single block
And a page named "hello-world-with-layout" with the template:
"""
{% extends 'above_and_below' %}
{% extends 'above-and-below' %}
{% block body %}Hello World{% endblock %}
"""
@ -34,7 +34,7 @@ Scenario: Liquid Inheritance with a single block
"""
Scenario: Liquid Inheritance with multiple blocks
Given a layout named "layout_with_sidebar" with the source:
Given a page named "layout-with-sidebar" with the template:
"""
<div class="header"></div>
<div class="content">
@ -49,7 +49,7 @@ Scenario: Liquid Inheritance with multiple blocks
"""
And a page named "hello-world-multiblocks" with the template:
"""
{% extends 'layout_with_sidebar' %}
{% extends 'layout-with-sidebar' %}
{% block body %}Hello world{% endblock %}
"""
When I view the rendered page at "/hello-world-multiblocks"
@ -68,7 +68,7 @@ Scenario: Liquid Inheritance with multiple blocks
"""
Scenario: Multiple inheritance (layout extending another layout)
Given a layout named "layout_with_sidebar" with the source:
Given a page named "layout-with-sidebar" with the template:
"""
<div class="header"></div>
<div class="content">
@ -79,15 +79,15 @@ Scenario: Multiple inheritance (layout extending another layout)
</div>
<div class="footer"></div>
"""
And a layout named "custom_layout_with_sidebar" with the source:
And a page named "custom-layout-with-sidebar" with the template:
"""
{% extends 'layout_with_sidebar' %}
{% extends 'layout-with-sidebar' %}
{% block sidebar %}Custom sidebar{% endblock %}
{% block body %}Hello{% endblock %}
"""
And a page named "hello-world-multiblocks" with the template:
"""
{% extends 'custom_layout_with_sidebar' %}
{% extends 'custom-layout-with-sidebar' %}
{% block body %}{{ block.super }} world{% endblock %}
"""
When I view the rendered page at "/hello-world-multiblocks"
@ -103,9 +103,8 @@ Scenario: Multiple inheritance (layout extending another layout)
<div class="footer"></div>
"""
Scenario: Page extending a layout with multiple embedded blocks which extends another template
Given a layout named "layout_with_sidebar" with the source:
Given a page named "layout-with-sidebar" with the template:
"""
<div class="header"></div>
<div class="content">
@ -116,14 +115,14 @@ Scenario: Page extending a layout with multiple embedded blocks which extends an
</div>
<div class="footer"></div>
"""
And a layout named "custom_layout_with_sidebar" with the source:
And a page named "custom-layout-with-sidebar" with the template:
"""
{% extends 'layout_with_sidebar' %}
{% extends 'layout-with-sidebar' %}
{% block body %}{{ block.super }} {% block main %}mister{% endblock %}{% endblock %}
"""
And a page named "hello-world-multiblocks" with the template:
"""
{% extends 'custom_layout_with_sidebar' %}
{% extends 'custom-layout-with-sidebar' %}
{% block main %}{{ block.super }} Jacques{% endblock %}
"""
When I view the rendered page at "/hello-world-multiblocks"

View File

@ -1,16 +0,0 @@
module Locomotive
module Liquid
module Drops
class Block < ::Liquid::Drop
def initialize(block)
@block = block
end
def super
@block.call_super(@context)
end
end
end
end
end

View File

@ -44,7 +44,11 @@ module Locomotive
def store_template
begin
@template = ::Liquid::Template.parse(self.liquify_template_source)
# puts "self.liquify_template_source = #{self.liquify_template_source.inspect}"
@template = ::Liquid::Template.parse(self.liquify_template_source, { :site => self.site })
@template.root.context.clear
# puts "@template = #{@template.inspect}"
# @template = Locomotive::Liquid::Template.parse(self)
if self.respond_to?(:after_parse_template) # kind of callback
self.send(:after_parse_template)

View File

@ -1,50 +0,0 @@
module Locomotive
module Liquid
module Tags
class Block < ::Liquid::Block
Syntax = /(\w+)/
attr_accessor :parent
attr_reader :name
def initialize(tag_name, markup, tokens)
if markup =~ Syntax
@name = $1
else
raise ::Liquid::SyntaxError.new("Syntax Error in 'block' - Valid syntax: block [name]")
end
super if tokens
end
def render(context)
context.stack do
context['block'] = Locomotive::Liquid::Drops::Block.new(self)
render_all(@nodelist, context)
end
end
def add_parent(nodelist)
if parent
parent.add_parent(nodelist)
else
self.parent = self.class.new(@tag_name, @name, nil)
parent.nodelist = nodelist
end
end
def call_super(context)
if parent
parent.render(context)
else
''
end
end
end
::Liquid::Template.register_tag('block', Block)
end
end
end

View File

@ -15,7 +15,7 @@ module Locomotive
Syntax = /(#{::Liquid::VariableSignature}+)\s*from\s*(#{::Liquid::QuotedString}+)/
def initialize(tag_name, markup, tokens)
def initialize(tag_name, markup, tokens, context)
if markup =~ Syntax
@target = $1
@url = $2.gsub(/['"]/, '')

View File

@ -1,83 +1,26 @@
module Locomotive
module Liquid
module Tags
class Extends < ::Liquid::Block
Syntax = /(#{::Liquid::QuotedFragment})/
class Extends < ::Liquid::Extends
def initialize(tag_name, markup, tokens)
if markup =~ Syntax
@template_name = $1
else
raise ::Liquid::SyntaxError.new("Syntax Error in 'extends' - Valid syntax: extends [template]")
class PageNotFound < ::Liquid::Error; end
def parse_parent_template(context)
page = context[:site].pages.where(:fullpath => @template_name.gsub("'", '')).first
raise PageNotFound.new("Page with fullpath '#{@template_name}' was not found") if page.nil?
template = page.template
# merge blocks ?
blocks = find_blocks(template.root.nodelist)
blocks.each_value do |block|
block.send(:instance_variable_set, :"@context", context)
block.end_tag
end
super
@blocks = @nodelist.inject({}) do |m, node|
m[node.name] = node if node.is_a?(Locomotive::Liquid::Tags::Block); m
end
end
def parse(tokens)
parse_all(tokens)
end
def render(context)
template, parent_blocks = load_template(context)
@blocks.each do |name, block|
if pb = parent_blocks[name]
pb.parent = block.parent
pb.add_parent(pb.nodelist)
pb.nodelist = block.nodelist
else
if is_extending?(template)
template.root.nodelist << block
end
end
end
template.render(context)
end
private
def parse_all(tokens)
@nodelist ||= []
@nodelist.clear
while token = tokens.shift
case token
when /^#{::Liquid::TagStart}/
if token =~ /^#{::Liquid::TagStart}\s*(\w+)\s*(.*)?#{::Liquid::TagEnd}$/
# fetch the tag from registered blocks
if tag = ::Liquid::Template.tags[$1]
@nodelist << tag.new($1, $2, tokens)
else
# this tag is not registered with the system
# pass it to the current block for special handling or error reporting
unknown_tag($1, $2, tokens)
end
else
raise ::Liquid::SyntaxError, "Tag '#{token}' was not properly terminated with regexp: #{TagEnd.inspect} "
end
when /^#{::Liquid::VariableStart}/
@nodelist << create_variable(token)
when ''
# pass
else
@nodelist << token
end
end
end
def load_template(context)
layout = context.registers[:site].layouts.where(:slug => context[@template_name]).first
[layout.template, layout.template.send(:instance_variable_get, :"@parent_blocks")]
end
def is_extending?(template)
template.root.nodelist.any? { |node| node.is_a?(Extends) }
template
end
end

View File

@ -12,7 +12,7 @@ module Locomotive
Syntax = /(#{::Liquid::Expression}+)?/
def initialize(tag_name, markup, tokens)
def initialize(tag_name, markup, tokens, context)
if markup =~ Syntax
@site_or_page = $1 || 'page'
@options = {}

View File

@ -19,7 +19,7 @@ module Locomotive
Syntax = /(#{::Liquid::Expression}+)\s+by\s+([0-9]+)/
def initialize(tag_name, markup, tokens)
def initialize(tag_name, markup, tokens, context)
if markup =~ Syntax
@collection_name = $1
@per_page = $2.to_i

View File

@ -3,7 +3,7 @@ module Locomotive
module Tags
class WithScope < ::Liquid::Block
def initialize(tag_name, markup, tokens)
def initialize(tag_name, markup, tokens, context)
@attributes = {}
markup.scan(::Liquid::TagAttributes) do |key, value|
@attributes[key] = value

View File

@ -7,21 +7,21 @@ require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_
Mongoid.master.collection(collection).drop
end
puts "Starting benchmark..."
puts "Starting test..."
site = Site.create :name => 'Benchmark Website', :subdomain => 'benchmark'
layout_with_sidebar = site.layouts.create :name => 'with_sidebar', :value => %{
simple = site.pages.create :title => 'Simple', :slug => 'simple', :layout_template => %{
<html>
<head></head>
<body>
<div class="header"></div>
<div class="content">
<div class="sidebar">
{% block sidebar %}DEFAULT SIDEBAR CONTENT{% endblock %}
A sidebar here / INDEX sidebar
</div>
<div class="body">
{% block body %}DEFAULT BODY CONTENT{% endblock %}
<div class="wrapper">Lorem ipsum</div>
</div>
</div>
<div class="footer"></div>
@ -29,24 +29,48 @@ layout_with_sidebar = site.layouts.create :name => 'with_sidebar', :value => %{
</html>
}
custom_layout_with_sidebar = site.layouts.create :name => 'custom_with_sidebar', :value => %{
\{% extends 'with_sidebar' %\}
\{% block sidebar %\}A sidebar here\{% endblock %\}
\{% block body %\}<div class="wrapper">\{% block main %\}DEFAULT MAIN CONTENT\{% endblock %\}</div>\{% endblock %\}
base = site.pages.create :title => 'Base page', :slug => 'base', :layout_template => %{
<html>
<head></head>
<body>
<div class="header"></div>
<div class="content">
<div class="sidebar">
{% block sidebar %}My simple sidebar{% endblock %}
</div>
<div class="body">
{% block body %}Just to say hi{% endblock %}
</div>
</div>
<div class="footer"></div>
</body>
</html>
}
page = site.pages.create :title => 'Benchmark', :slug => 'benchmark', :layout_template => %{
\{% extends 'custom_with_sidebar' %\}
\{% block sidebar %\}\{\{ block.super \}\} / INDEX sidebar\{% endblock %\}
\{% block main %\}Lorem ipsum\{% endblock %\}
page_1 = site.pages.create :title => 'Page 1', :slug => 'page_1', :layout_template => %{
{% extends base %}
{% block sidebar %}A sidebar here{% endblock %}
{% block body %}<div class="wrapper">{% block main %}DEFAULT MAIN CONTENT{% endblock %}</div>{% endblock %}
}
page_2 = site.pages.create :title => 'Page 2', :slug => 'page_2', :layout_template => %{
{% extends page_1 %}
{% block sidebar %}{{ block.super }} / INDEX sidebar{% endblock %}
{% block main %}Lorem ipsum{% endblock %}
}
puts "OUTPUT = #{page_2.render(Liquid::Context.new)}"
context = Liquid::Context.new({}, { 'site' => site }, { :site => site })
puts "====> OUTPUT \n#{page.render(context)}"
Benchmark.bm do |bm|
bm.report("Rendering page 10k times") do
bm.report("Rendering a simple page 10k times") do
10000.times do
Page.where(:title => 'Simple').first.render(context)
end
end
bm.report("Rendering a complex page 10k times") do
10000.times do
Page.last.render(context)
end
@ -54,10 +78,13 @@ Benchmark.bm do |bm|
end
# # empty page (imac 27'): User System Total Real
# # Rendering page 10k times 13.390000 1.700000 15.090000 ( 15.654966)
# Rendering page 10k times 21.390000 1.820000 23.210000 ( 24.120529)
# # page with inherited template (imac 27'): User System Total Real
# Rendering page 10k times 85.840000 7.600000 93.440000 ( 97.841248)
# # with optimization (imac 27'): User System Total Real
# Rendering page 10k times 84.240000 7.280000 91.520000 ( 95.475565)
# # with locomotive liquid (imac 27'): User System Total Real
# Rendering page 10k times 38.750000 3.050000 41.800000 ( 42.880022)