implement liquid inheritance (in progress)
This commit is contained in:
parent
cf3a177580
commit
4f06dab51e
@ -4,13 +4,16 @@ module Models
|
|||||||
module Render
|
module Render
|
||||||
|
|
||||||
def render(context)
|
def render(context)
|
||||||
|
# ::Liquid::Template.parse(self.layout_template)
|
||||||
self.template.render(context)
|
self.template.render(context)
|
||||||
|
|
||||||
if self.layout
|
# self.template.render(context)
|
||||||
self.layout.template.render(context)
|
#
|
||||||
else
|
# if self.layout
|
||||||
::Liquid::Template.parse("{{ content_for_layout }}").render(context)
|
# self.layout.template.render(context)
|
||||||
end
|
# else
|
||||||
|
# ::Liquid::Template.parse("{{ content_for_layout }}").render(context)
|
||||||
|
# end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -5,11 +5,11 @@ class Layout < LiquidTemplate
|
|||||||
embeds_many :parts, :class_name => 'PagePart'
|
embeds_many :parts, :class_name => 'PagePart'
|
||||||
|
|
||||||
## callbacks ##
|
## callbacks ##
|
||||||
before_save :build_parts_from_value
|
# before_save :build_parts_from_value
|
||||||
after_save :update_parts_in_pages
|
# after_save :update_parts_in_pages
|
||||||
|
|
||||||
## validations ##
|
## validations ##
|
||||||
validates_format_of :value, :with => Locomotive::Regexps::CONTENT_FOR_LAYOUT, :message => :missing_content_for_layout
|
# validates_format_of :value, :with => Locomotive::Regexps::CONTENT_FOR_LAYOUT, :message => :missing_content_for_layout
|
||||||
|
|
||||||
## methods ##
|
## methods ##
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ class Page
|
|||||||
|
|
||||||
## Extensions ##
|
## Extensions ##
|
||||||
include Models::Extensions::Page::Tree
|
include Models::Extensions::Page::Tree
|
||||||
include Models::Extensions::Page::Parts
|
# include Models::Extensions::Page::Parts
|
||||||
include Models::Extensions::Page::Render
|
include Models::Extensions::Page::Render
|
||||||
include Models::Extensions::Page::Templatized
|
include Models::Extensions::Page::Templatized
|
||||||
|
|
||||||
@ -15,6 +15,8 @@ class Page
|
|||||||
field :published, :type => Boolean, :default => false
|
field :published, :type => Boolean, :default => false
|
||||||
field :cache_strategy, :default => 'none'
|
field :cache_strategy, :default => 'none'
|
||||||
|
|
||||||
|
field :layout_template # FIXME: liquid inheritance
|
||||||
|
|
||||||
# allows newly pages to have a default body
|
# allows newly pages to have a default body
|
||||||
attr_accessor :body
|
attr_accessor :body
|
||||||
|
|
||||||
@ -40,7 +42,8 @@ class Page
|
|||||||
scope :published, :where => { :published => true }
|
scope :published, :where => { :published => true }
|
||||||
|
|
||||||
## behaviours ##
|
## behaviours ##
|
||||||
liquify_template :joined_parts
|
# liquify_template :joined_parts
|
||||||
|
liquify_template :layout_template
|
||||||
|
|
||||||
## methods ##
|
## methods ##
|
||||||
|
|
||||||
|
4
doc/TODO
4
doc/TODO
@ -3,6 +3,10 @@ BOARD:
|
|||||||
- refactor slugify method (use parameterize + create a module)
|
- refactor slugify method (use parameterize + create a module)
|
||||||
- [content types] the "display column" selector should not include file types
|
- [content types] the "display column" selector should not include file types
|
||||||
|
|
||||||
|
- add dom_id and css_class fields in page (body structure ?)
|
||||||
|
- liquid inheritance:
|
||||||
|
|
||||||
|
|
||||||
BACKLOG:
|
BACKLOG:
|
||||||
|
|
||||||
- notify accounts when new instance of models (opt): none, one or many accounts. Used for contact form.
|
- notify accounts when new instance of models (opt): none, one or many accounts. Used for contact form.
|
||||||
|
@ -5,84 +5,188 @@ Feature: Engine
|
|||||||
Background:
|
Background:
|
||||||
Given I have the site: "test site" set up
|
Given I have the site: "test site" set up
|
||||||
|
|
||||||
Scenario: Simple Page
|
# Scenario: Simple Page
|
||||||
Given a simple page named "hello-world" with the body:
|
# Given a page named "hello-world" with the template:
|
||||||
"""
|
# """
|
||||||
Hello World
|
# Hello World
|
||||||
"""
|
# """
|
||||||
When I view the rendered page at "/hello-world"
|
# When I view the rendered page at "/hello-world"
|
||||||
Then the rendered output should look like:
|
# Then the rendered output should look like:
|
||||||
"""
|
# """
|
||||||
Hello World
|
# Hello World
|
||||||
"""
|
# """
|
||||||
|
#
|
||||||
|
# Scenario: Simple Page extending a layout with multiple blocks
|
||||||
|
# Given a layout named "layout_with_sidebar" with the source:
|
||||||
|
# """
|
||||||
|
# <div class="header"></div>
|
||||||
|
# <div class="content">
|
||||||
|
# <div class="sidebar">{% block sidebar %}DEFAULT SIDEBAR CONTENT{% endblock %}</div>
|
||||||
|
# <div class="body">
|
||||||
|
# {% block body %}DEFAULT BODY CONTENT{% endblock %}
|
||||||
|
# </div>
|
||||||
|
# </div>
|
||||||
|
# <div class="footer"></div>
|
||||||
|
# """
|
||||||
|
# And a page named "hello-world-multiblocks" with the template:
|
||||||
|
# """
|
||||||
|
# {% extends 'layout_with_sidebar' %}
|
||||||
|
# {% block body %}Hello world{% endblock %}
|
||||||
|
# """
|
||||||
|
# When I view the rendered page at "/hello-world-multiblocks"
|
||||||
|
# Then the rendered output should look like:
|
||||||
|
# """
|
||||||
|
# <div class="header"></div>
|
||||||
|
# <div class="content">
|
||||||
|
# <div class="sidebar">DEFAULT SIDEBAR CONTENT</div>
|
||||||
|
# <div class="body">
|
||||||
|
# Hello world
|
||||||
|
# </div>
|
||||||
|
# </div>
|
||||||
|
# <div class="footer"></div>
|
||||||
|
# """
|
||||||
|
|
||||||
Scenario: Simple Page with layout
|
# Scenario: Simple Page extending a layout with multiple blocks which extends another template
|
||||||
Given a layout named "above_and_below" with the source:
|
# Given a layout named "layout_with_sidebar" with the source:
|
||||||
"""
|
# """
|
||||||
<div class="header"></div>
|
# <div class="header"></div>
|
||||||
{{ content_for_layout }}
|
# <div class="content">
|
||||||
<div class="footer"></div>
|
# <div class="sidebar">{% block sidebar %}DEFAULT SIDEBAR CONTENT{% endblock %}</div>
|
||||||
"""
|
# <div class="body">
|
||||||
|
# {% block body %}DEFAULT BODY CONTENT{% endblock %}
|
||||||
|
# </div>
|
||||||
|
# </div>
|
||||||
|
# <div class="footer"></div>
|
||||||
|
# """
|
||||||
|
# And a layout named "custom_layout_with_sidebar" with the source:
|
||||||
|
# """
|
||||||
|
# {% 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' %}
|
||||||
|
# {% block body %}{{ block.super }} world{% endblock %}
|
||||||
|
# """
|
||||||
|
# When I view the rendered page at "/hello-world-multiblocks"
|
||||||
|
# Then the rendered output should look like:
|
||||||
|
# """
|
||||||
|
# <div class="header"></div>
|
||||||
|
# <div class="content">
|
||||||
|
# <div class="sidebar">Custom sidebar</div>
|
||||||
|
# <div class="body">
|
||||||
|
# Hello world
|
||||||
|
# </div>
|
||||||
|
# </div>
|
||||||
|
# <div class="footer"></div>
|
||||||
|
# """
|
||||||
|
|
||||||
And a page named "hello-world-with-layout" with the layout "above_and_below" and the body:
|
Scenario: Simple Page extending a layout with multiple embedded blocks which extends another template
|
||||||
"""
|
|
||||||
Hello World
|
|
||||||
"""
|
|
||||||
|
|
||||||
When I view the rendered page at "/hello-world-with-layout"
|
|
||||||
Then the rendered output should look like:
|
|
||||||
"""
|
|
||||||
<div class="header"></div>
|
|
||||||
Hello World
|
|
||||||
<div class="footer"></div>
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Page with Parts
|
|
||||||
Given a layout named "layout_with_sidebar" with the source:
|
Given a layout named "layout_with_sidebar" with the source:
|
||||||
"""
|
"""
|
||||||
<div class="header"></div>
|
<div class="header"></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="sidebar">{{ content_for_sidebar }}</div>
|
<div class="sidebar">{% block sidebar %}DEFAULT SIDEBAR CONTENT{% endblock %}</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
{{ content_for_layout }}
|
{% block body %}Hello{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer"></div>
|
<div class="footer"></div>
|
||||||
"""
|
"""
|
||||||
And a page named "hello-world-multipart" with the layout "layout_with_sidebar" and the body:
|
And a layout named "custom_layout_with_sidebar" with the source:
|
||||||
"""
|
"""
|
||||||
IM IN UR BODY OUTPUTTING SUM CODEZ!!
|
{% extends 'layout_with_sidebar' %}
|
||||||
|
{% block body %}{{ block.super }} {% block main %}mister{% endblock %}{% endblock %}
|
||||||
"""
|
"""
|
||||||
|
And a page named "hello-world-multiblocks" with the template:
|
||||||
And the page named "hello-world-multipart" has the part "sidebar" with the content:
|
|
||||||
"""
|
"""
|
||||||
IM IN UR SIDEBAR PUTTING OUT LINKZ
|
{% extends 'custom_layout_with_sidebar' %}
|
||||||
|
{% block main %}{{ block.super }} Jacques{% endblock %}
|
||||||
"""
|
"""
|
||||||
|
When I view the rendered page at "/hello-world-multiblocks"
|
||||||
When I view the rendered page at "/hello-world-multipart"
|
|
||||||
Then the rendered output should look like:
|
Then the rendered output should look like:
|
||||||
"""
|
"""
|
||||||
<div class="header"></div>
|
<div class="header"></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="sidebar">IM IN UR SIDEBAR PUTTING OUT LINKZ</div>
|
<div class="sidebar">DEFAULT SIDEBAR CONTENT</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
IM IN UR BODY OUTPUTTING SUM CODEZ!!
|
Hello mister Jacques
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer"></div>
|
<div class="footer"></div>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@wip
|
# Scenario: Simple Page with layout
|
||||||
Scenario: Simple Page with Admin Inline Editing
|
# Given a layout named "above_and_below" with the source:
|
||||||
Given a simple page named "hello-world-inline" with the body:
|
# """
|
||||||
"""
|
# <div class="header"></div>
|
||||||
{% block hello %}Hello World{% endblock %}
|
# {{ content_for_layout }}
|
||||||
"""
|
# <div class="footer"></div>
|
||||||
When And I'm an admin
|
# """
|
||||||
And I view the rendered page at "/hello-world-inline"
|
#
|
||||||
Then the rendered output shoud look like:
|
# And a page named "hello-world-with-layout" with the layout "above_and_below" and the body:
|
||||||
"""
|
# """
|
||||||
<div class="inline-editing" data-url="/admin/parts/XXXX" data-title="hello">Hello World</div>
|
# Hello World
|
||||||
"""
|
# """
|
||||||
|
#
|
||||||
|
# When I view the rendered page at "/hello-world-with-layout"
|
||||||
|
# Then the rendered output should look like:
|
||||||
|
# """
|
||||||
|
# <div class="header"></div>
|
||||||
|
# Hello World
|
||||||
|
# <div class="footer"></div>
|
||||||
|
# """
|
||||||
|
#
|
||||||
|
# Scenario: Page with Parts
|
||||||
|
# Given a layout named "layout_with_sidebar" with the source:
|
||||||
|
# """
|
||||||
|
# <div class="header"></div>
|
||||||
|
# <div class="content">
|
||||||
|
# <div class="sidebar">{{ content_for_sidebar }}</div>
|
||||||
|
# <div class="body">
|
||||||
|
# {{ content_for_layout }}
|
||||||
|
# </div>
|
||||||
|
# </div>
|
||||||
|
# <div class="footer"></div>
|
||||||
|
# """
|
||||||
|
# And a page named "hello-world-multipart" with the layout "layout_with_sidebar" and the body:
|
||||||
|
# """
|
||||||
|
# IM IN UR BODY OUTPUTTING SUM CODEZ!!
|
||||||
|
# """
|
||||||
|
#
|
||||||
|
# And the page named "hello-world-multipart" has the part "sidebar" with the content:
|
||||||
|
# """
|
||||||
|
# IM IN UR SIDEBAR PUTTING OUT LINKZ
|
||||||
|
# """
|
||||||
|
#
|
||||||
|
# When I view the rendered page at "/hello-world-multipart"
|
||||||
|
# Then the rendered output should look like:
|
||||||
|
# """
|
||||||
|
# <div class="header"></div>
|
||||||
|
# <div class="content">
|
||||||
|
# <div class="sidebar">IM IN UR SIDEBAR PUTTING OUT LINKZ</div>
|
||||||
|
# <div class="body">
|
||||||
|
# IM IN UR BODY OUTPUTTING SUM CODEZ!!
|
||||||
|
# </div>
|
||||||
|
# </div>
|
||||||
|
# <div class="footer"></div>
|
||||||
|
# """
|
||||||
|
#
|
||||||
|
# @wip
|
||||||
|
# Scenario: Simple Page with Admin Inline Editing
|
||||||
|
# Given a simple page named "hello-world-inline" with the body:
|
||||||
|
# """
|
||||||
|
# {% block hello %}Hello World{% endblock %}
|
||||||
|
# """
|
||||||
|
# When And I'm an admin
|
||||||
|
# And I view the rendered page at "/hello-world-inline"
|
||||||
|
# Then the rendered output shoud look like:
|
||||||
|
# """
|
||||||
|
# <div class="inline-editing" data-url="/admin/parts/XXXX" data-title="hello">Hello World</div>
|
||||||
|
# """
|
||||||
|
|
||||||
|
# {% block main %}Didier{% endblock %}
|
||||||
|
|
||||||
|
# {% block body %}{% block main %}{{ block.super }}Jacques{% endblock %}{% endblock %}
|
||||||
|
# {% block body %}Hello mister Jacques{% endblock %}
|
@ -1,9 +1,9 @@
|
|||||||
### Pages
|
### Pages
|
||||||
|
|
||||||
# helps create a simple content page (parent: "index") with a slug, contents, and layout
|
# helps create a simple content page (parent: "index") with a slug, contents, and layout
|
||||||
def create_content_page(page_slug, page_contents, layout = nil)
|
def create_content_page(page_slug, page_contents, layout = nil, template = nil)
|
||||||
@home = @site.pages.where(:slug => "index").first || Factory(:page)
|
@home = @site.pages.where(:slug => "index").first || Factory(:page)
|
||||||
page = @site.pages.create(:slug => page_slug, :body => page_contents, :layout => layout, :parent => @home, :title => "some title", :published => true)
|
page = @site.pages.create(:slug => page_slug, :body => page_contents, :layout => layout, :parent => @home, :title => "some title", :published => true, :layout_template => template)
|
||||||
page.should be_valid
|
page.should be_valid
|
||||||
page
|
page
|
||||||
end
|
end
|
||||||
@ -21,6 +21,10 @@ Given /^a page named "([^"]*)" with the layout "([^"]*)" and the body:$/ do |pag
|
|||||||
@page = create_content_page(page_slug, page_contents, layout)
|
@page = create_content_page(page_slug, page_contents, layout)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Given /^a page named "([^"]*)" with the template:$/ do |page_slug, template|
|
||||||
|
@page = create_content_page(page_slug, '', nil, template)
|
||||||
|
end
|
||||||
|
|
||||||
# creates a layout
|
# creates a layout
|
||||||
Given /^a layout named "([^"]*)" with the source:$/ do |layout_name, layout_body|
|
Given /^a layout named "([^"]*)" with the source:$/ do |layout_name, layout_body|
|
||||||
@layout = Factory(:layout, :name => layout_name, :value => layout_body, :site => @site)
|
@layout = Factory(:layout, :name => layout_name, :value => layout_body, :site => @site)
|
||||||
|
16
lib/locomotive/liquid/drops/block.rb
Normal file
16
lib/locomotive/liquid/drops/block.rb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
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
|
52
lib/locomotive/liquid/tags/block.rb
Normal file
52
lib/locomotive/liquid/tags/block.rb
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
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
|
||||||
|
# puts "** [Block/initialize] #{tag_name}, #{@name}, #{tokens.inspect}"
|
||||||
|
|
||||||
|
super if tokens
|
||||||
|
end
|
||||||
|
|
||||||
|
def render(context)
|
||||||
|
# puts "** [Block/render] #{@name} / #{@parent.inspect}"
|
||||||
|
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
|
117
lib/locomotive/liquid/tags/extends.rb
Normal file
117
lib/locomotive/liquid/tags/extends.rb
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
module Locomotive
|
||||||
|
module Liquid
|
||||||
|
module Tags
|
||||||
|
class Extends < ::Liquid::Block
|
||||||
|
Syntax = /(#{::Liquid::QuotedFragment})/
|
||||||
|
|
||||||
|
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]")
|
||||||
|
end
|
||||||
|
|
||||||
|
super
|
||||||
|
|
||||||
|
@blocks = @nodelist.inject({}) do |m, node|
|
||||||
|
m[node.name] = node if node.is_a?(Locomotive::Liquid::Tags::Block); m
|
||||||
|
end
|
||||||
|
|
||||||
|
# puts "** Extends #{@template_name} / #{@blocks.inspect} / #{@nodelist.inspect}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse(tokens)
|
||||||
|
parse_all(tokens)
|
||||||
|
end
|
||||||
|
|
||||||
|
def render(context)
|
||||||
|
template = load_template(context)
|
||||||
|
parent_blocks = find_blocks(template.root)
|
||||||
|
|
||||||
|
# puts "** [Extends/render] parent_blocks = #{parent_blocks.inspect}"
|
||||||
|
|
||||||
|
@blocks.each do |name, block|
|
||||||
|
# puts "** [Extends/render] #{name}, #{block.inspect}"
|
||||||
|
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)
|
||||||
|
# puts "** [parse_all] #{tokens.inspect}"
|
||||||
|
|
||||||
|
@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]
|
||||||
|
# puts "** [parse_all] tag = #{$1}, #{$2}"
|
||||||
|
@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)
|
||||||
|
# puts "** load_template (#{context[@template_name]})"
|
||||||
|
layout = context.registers[:site].layouts.where(:slug => context[@template_name]).first
|
||||||
|
layout.template
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_blocks(node, blocks={})
|
||||||
|
# puts "** find_blocks #{node.class.inspect} / #{blocks.keys.inspect}"
|
||||||
|
if node.respond_to?(:nodelist) && node.nodelist
|
||||||
|
# puts " ==> find_blocks nodelist = #{node.nodelist.inspect}"
|
||||||
|
node.nodelist.inject(blocks) do |b, node|
|
||||||
|
if node.is_a?(Locomotive::Liquid::Tags::Block)
|
||||||
|
b[node.name] = node
|
||||||
|
end
|
||||||
|
# else
|
||||||
|
find_blocks(node, b) # FIXME: add nested blocks
|
||||||
|
# end
|
||||||
|
|
||||||
|
b
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
blocks
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_extending?(template)
|
||||||
|
template.root.nodelist.any? { |node| node.is_a?(Extends) }
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
::Liquid::Template.register_tag('extends', Extends)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
63
perf/benchmark.rb
Executable file
63
perf/benchmark.rb
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
# require "rubygems"
|
||||||
|
# require "ruby-prof"
|
||||||
|
ENV["RAILS_ENV"] ||= 'test'
|
||||||
|
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
|
||||||
|
|
||||||
|
# require File.dirname(__FILE__) + "/../config/application.rb"
|
||||||
|
|
||||||
|
# Mongoid.configure do |config|
|
||||||
|
# config.master = Mongo::Connection.new.db("locomotive_perf_test")
|
||||||
|
# end
|
||||||
|
|
||||||
|
%w{sites pages layouts}.each do |collection|
|
||||||
|
Mongoid.master.collection(collection).drop
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Starting benchmark..."
|
||||||
|
|
||||||
|
site = Site.create :name => 'Benchmark Website', :subdomain => 'benchmark'
|
||||||
|
|
||||||
|
layout_with_sidebar = site.layouts.create :name => 'with_sidebar', :value => %{
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body>
|
||||||
|
<div class="header"></div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="sidebar">
|
||||||
|
{% block sidebar %}DEFAULT SIDEBAR CONTENT{% endblock %}
|
||||||
|
</div>
|
||||||
|
<div class="body">
|
||||||
|
{% block body %}DEFAULT BODY CONTENT{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer"></div>
|
||||||
|
</body>
|
||||||
|
</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 %\}
|
||||||
|
}
|
||||||
|
|
||||||
|
page = site.pages.create :title => 'Index', :slug => 'index', :layout_template => %{
|
||||||
|
\{% extends 'custom_with_sidebar' %\}
|
||||||
|
\{% block sidebar %\}\{\{ block.super \}\} / INDEX sidebar\{% endblock %\}
|
||||||
|
\{% block main %\}Lorem ipsum\{% endblock %\}
|
||||||
|
}
|
||||||
|
|
||||||
|
context = Liquid::Context.new({}, { 'site' => site }, { :site => site })
|
||||||
|
|
||||||
|
puts "====> \n#{page.render(context)}"
|
||||||
|
|
||||||
|
Benchmark.bm do |bm|
|
||||||
|
bm.report("Rendering page 10k times") do
|
||||||
|
10000.times do
|
||||||
|
Page.first.render(context)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# without liquify (macbook white): User System Total Real
|
||||||
|
# Rendering page 10k times 22.650000 6.220000 28.870000 ( 30.294338)
|
@ -69,6 +69,28 @@ end
|
|||||||
|
|
||||||
## Layouts ##
|
## Layouts ##
|
||||||
Factory.define :layout do |l|
|
Factory.define :layout do |l|
|
||||||
|
l.name '1 main column + sidebar'
|
||||||
|
l.value %{<html>
|
||||||
|
<head>
|
||||||
|
<title>My website</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="sidebar">
|
||||||
|
\{% block sidebar %\}
|
||||||
|
DEFAULT SIDEBAR CONTENT
|
||||||
|
\{% endblock %\}
|
||||||
|
</div>
|
||||||
|
<div id="main">
|
||||||
|
\{% block main %\}
|
||||||
|
DEFAULT MAIN CONTENT
|
||||||
|
\{% endblock %\}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>}
|
||||||
|
l.site { Site.where(:subdomain => "acme").first || Factory(:site) }
|
||||||
|
end
|
||||||
|
|
||||||
|
Factory.define :base_layout, :parent => :layout do |l|
|
||||||
l.name '1 main column + sidebar'
|
l.name '1 main column + sidebar'
|
||||||
l.value %{<html>
|
l.value %{<html>
|
||||||
<head>
|
<head>
|
||||||
@ -79,7 +101,6 @@ Factory.define :layout do |l|
|
|||||||
<div id="main">\{\{ content_for_layout | textile \}\}</div>
|
<div id="main">\{\{ content_for_layout | textile \}\}</div>
|
||||||
</body>
|
</body>
|
||||||
</html>}
|
</html>}
|
||||||
l.site { Site.where(:subdomain => "acme").first || Factory(:site) }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,59 +6,59 @@ describe Layout do
|
|||||||
Factory.build(:layout).should be_valid
|
Factory.build(:layout).should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
## validations ##
|
# ## validations ##
|
||||||
|
#
|
||||||
it 'should validate presence of content_for_layout in value' do
|
# it 'should validate presence of content_for_layout in value' do
|
||||||
layout = Factory.build(:layout, :value => 'without content_for_layout')
|
# layout = Factory.build(:layout, :value => 'without content_for_layout')
|
||||||
layout.should_not be_valid
|
# layout.should_not be_valid
|
||||||
layout.errors[:value].should == ["should contain 'content_for_layout' liquid tag"]
|
# layout.errors[:value].should == ["should contain 'content_for_layout' liquid tag"]
|
||||||
end
|
# end
|
||||||
|
#
|
||||||
context 'dealing with page parts' do
|
# context 'dealing with page parts' do
|
||||||
|
#
|
||||||
before(:each) do
|
# before(:each) do
|
||||||
@layout = Factory.build(:layout)
|
# @layout = Factory.build(:layout)
|
||||||
end
|
# end
|
||||||
|
#
|
||||||
it 'should have 2 parts' do
|
# it 'should have 2 parts' do
|
||||||
@layout.send(:build_parts_from_value)
|
# @layout.send(:build_parts_from_value)
|
||||||
@layout.parts.size.should == 2
|
# @layout.parts.size.should == 2
|
||||||
|
#
|
||||||
@layout.parts.first.name.should == 'Body'
|
# @layout.parts.first.name.should == 'Body'
|
||||||
@layout.parts.first.slug.should == 'layout'
|
# @layout.parts.first.slug.should == 'layout'
|
||||||
|
#
|
||||||
@layout.parts.last.name.should == 'Left sidebar'
|
# @layout.parts.last.name.should == 'Left sidebar'
|
||||||
@layout.parts.last.slug.should == 'left_sidebar'
|
# @layout.parts.last.slug.should == 'left_sidebar'
|
||||||
end
|
# end
|
||||||
|
#
|
||||||
it 'should not add parts to pages if layout does not change' do
|
# it 'should not add parts to pages if layout does not change' do
|
||||||
@layout.stubs(:value_changed?).returns(false)
|
# @layout.stubs(:value_changed?).returns(false)
|
||||||
page = Factory.build(:page, :layout => @layout, :site => nil)
|
# page = Factory.build(:page, :layout => @layout, :site => nil)
|
||||||
page.expects(:update_parts!).never
|
# page.expects(:update_parts!).never
|
||||||
@layout.pages << page
|
# @layout.pages << page
|
||||||
@layout.save
|
# @layout.save
|
||||||
end
|
# end
|
||||||
|
#
|
||||||
it 'should add parts to pages if layout changes' do
|
# it 'should add parts to pages if layout changes' do
|
||||||
@layout.value = @layout.value + "..."
|
# @layout.value = @layout.value + "..."
|
||||||
page = Factory.build(:page, :layout => @layout, :site => nil)
|
# page = Factory.build(:page, :layout => @layout, :site => nil)
|
||||||
page.expects(:update_parts!)
|
# page.expects(:update_parts!)
|
||||||
@layout.pages << page
|
# @layout.pages << page
|
||||||
@layout.save
|
# @layout.save
|
||||||
end
|
# end
|
||||||
|
#
|
||||||
end
|
# end
|
||||||
|
#
|
||||||
context 'parsing liquid template' do
|
# context 'parsing liquid template' do
|
||||||
|
#
|
||||||
before(:each) do
|
# before(:each) do
|
||||||
@layout = Factory.build(:layout)
|
# @layout = Factory.build(:layout)
|
||||||
end
|
# end
|
||||||
|
#
|
||||||
it 'should not raise an error if template is empty' do
|
# it 'should not raise an error if template is empty' do
|
||||||
@layout.template.should be_nil
|
# @layout.template.should be_nil
|
||||||
end
|
# end
|
||||||
|
#
|
||||||
end
|
# end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user