middleware to render templatized pages

did committed Feb 16, 2015
commit d430ab7fa073fe6ae7f0eb605f8b7df36792307b
Showing 17 changed files with 155 additions and 124 deletions
Rakefile +1 -1
@@ @@ -17,7 +17,7 @@ require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new('spec')
RSpec::Core::RakeTask.new('spec:integration') do |spec|
- spec.pattern = 'spec/unit/**/*_spec.rb'
+ spec.pattern = 'spec/integration/**/*_spec.rb'
end
RSpec::Core::RakeTask.new('spec:unit') do |spec|
locomotive/steam/liquid/filters/html.rb b/lib/locomotive/steam/liquid/filters/html.rb +6 -5
@@ @@ -15,7 +15,7 @@ module Locomotive
type = options[:type] || 'application/rss+xml'
title = options[:title] || 'RSS'
- %{<link rel="#{rel}" type="#{type}" title="#{title}" href="#{input}">}
+ %{<link rel="#{rel}" type="#{type}" title="#{title}" href="#{input}" />}
end
# Write the url of a theme stylesheet
@@ @@ -31,7 +31,7 @@ module Locomotive
input = stylesheet_url(input)
- %{<link href="#{input}" media="#{media}" rel="stylesheet" type="text/css">}
+ %{<link href="#{input}" media="#{media}" rel="stylesheet" type="text/css" />}
end
# Write the url to javascript resource
@@ @@ -44,10 +44,11 @@ module Locomotive
# input: url of the javascript file
def javascript_tag(input, *args)
return '' if input.nil?
+
javascript_options = inline_options(args_to_options(args))
input = javascript_url(input)
- "<script src=\"#{input}\" type=\"text/javascript\" #{javascript_options}></script>"
+ %{<script src="#{input}" type="text/javascript" #{javascript_options}></script>}
end
def theme_image_url(input)
@@ @@ -64,7 +65,7 @@ module Locomotive
def theme_image_tag(input, *args)
image_options = inline_options(args_to_options(args))
- "<img src=\"#{theme_image_url(input)}\" #{image_options}>"
+ %{<img src="#{theme_image_url(input)}" #{image_options}>}
end
# Write an image tag
@@ @@ -72,7 +73,7 @@ module Locomotive
def image_tag(input, *args)
image_options = inline_options(args_to_options(args))
- "<img src=\"#{get_url_from_asset(input)}\" #{image_options}>"
+ %{<img src="#{get_url_from_asset(input)}" #{image_options}>}
end
# Embed a flash movie into a page
locomotive/steam/middlewares.rb b/lib/locomotive/steam/middlewares.rb +2 -10
@@ @@ -8,22 +8,14 @@ require_relative 'middlewares/locale'
require_relative 'middlewares/timezone'
require_relative 'middlewares/logging'
require_relative 'middlewares/path'
+ # require_relative 'middlewares/entry_submission'
require_relative 'middlewares/page'
+ require_relative 'middlewares/templatized_page'
- require_relative 'middlewares/static_assets'
require_relative 'middlewares/dynamic_assets'
- # require_relative 'middlewares/entry_submission'
-
-
-
-
- # require_relative 'middlewares/templatized_page'
- # require_relative 'middlewares/site'
require_relative 'middlewares/renderer'
- require_relative 'middlewares/stack'
-
module Locomotive::Steam
module Middlewares
end
locomotive/steam/middlewares/default_env.rb b/lib/locomotive/steam/middlewares/default_env.rb +9 -2
@@ @@ -6,12 +6,19 @@ module Locomotive::Steam
def call(env)
request = Rack::Request.new(env)
- env['steam.request'] = request
- env['steam.services'] = Locomotive::Steam::Services.build_instance(request, options)
+ env['steam.request'] = request
+ env['steam.services'] = build_services(request)
+ env['steam.liquid_assigns'] = {}
app.call(env)
end
+ private
+
+ def build_services(request)
+ Locomotive::Steam::Services.build_instance(request, options)
+ end
+
end
end
locomotive/steam/middlewares/renderer.rb b/lib/locomotive/steam/middlewares/renderer.rb +1 -1
@@ @@ -73,7 +73,7 @@ module Locomotive::Steam
'contents' => Locomotive::Steam::Liquid::Drops::ContentTypes.new,
'current_user' => {},
'session' => Locomotive::Steam::Liquid::Drops::SessionProxy.new,
- }
+ }.merge(env['steam.liquid_assigns'])
end
def _locale_liquid_assigns
locomotive/steam/middlewares/static_assets.rb b/lib/locomotive/steam/middlewares/static_assets.rb +0 -25
@@ @@ -1,25 +0,0 @@
- # require 'rack/static'
-
- # module Locomotive::Steam
- # module Middlewares
-
- # class StaticAssets < ::Rack::Static
-
- # alias_method :call_without_threadsafety, :call
-
- # def call(env)
- # dup._call(env) # thread-safe purpose
- # end
-
- # def _call(env)
- # # mounting_point = env['steam.mounting_point']
-
- # @file_server = Rack::File.new(mounting_point.assets_path)
-
- # call_without_threadsafety(env)
- # end
-
- # end
-
- # end
- # end
locomotive/steam/middlewares/templatized_page.rb b/lib/locomotive/steam/middlewares/templatized_page.rb +40 -13
@@ @@ -1,32 +1,59 @@
module Locomotive::Steam
module Middlewares
- class TemplatizedPage < Base
+ class TemplatizedPage < ThreadSafe
- def _call(env)
- super
+ include Helpers
- if self.page && self.page.templatized?
- self.set_content_entry!(env)
+ def _call
+ if page && page.templatized?
+ self.set_content_entry!
end
-
- app.call(env)
end
protected
- def set_content_entry!(env)
- %r(^#{self.page.safe_fullpath.gsub('*', '([^\/]+)')}$) =~ self.path
+ def set_content_entry!
+ # extract the slug of the content entry
+ %r(^#{page.fullpath.gsub('content-type-template', '([^\/]+)')}$) =~ path
+
+ if entry = fetch_content_entry($1)
+ # the entry will be available in the template under different keys
+ ['content_entry', 'entry', entry.content_type.slug.singularize].each do |key|
+ env['steam.liquid_assigns'][key] = entry
+ end
- permalink = $1
+ env['steam.content_entry'] = page.content_entry = entry
- if content_entry = self.page.content_type.find_entry(permalink)
- env['steam.content_entry'] = content_entry
+ # log it
+ log "Found content entry: #{entry._label}"
else
+ # force the rendering of the 404 page
env['steam.page'] = nil
end
end
+ def fetch_content_entry(slug)
+ if type = content_type_repository.by_slug(page.content_type)
+ decorate(content_entry_repository.by_slug(type, slug))
+ else
+ nil
+ end
+ end
+
+ def decorate(entry)
+ return nil if entry.nil?
+ Locomotive::Steam::Decorators::I18nDecorator.new(entry, nil, default_locale)
+ end
+
+ def content_type_repository
+ services.repositories.content_type
+ end
+
+ def content_entry_repository
+ services.repositories.content_entry
+ end
+
end
end
- end
\ No newline at end of file
+ end
locomotive/steam/repositories/filesystem/models/content_type_field.rb b/lib/locomotive/steam/repositories/filesystem/models/content_type_field.rb +4 -0
@@ @@ -13,6 +13,10 @@ module Locomotive
}.merge(attributes))
end
+ def class_name
+ self[:class_name] || self[:target]
+ end
+
end
end
locomotive/steam/repositories/filesystem/sanitizers/content_entry.rb b/lib/locomotive/steam/repositories/filesystem/sanitizers/content_entry.rb +1 -1
@@ @@ -26,7 +26,7 @@ module Locomotive
end
def slugify(label, collection, locale = nil)
- base, index = label.singularize.parameterize('-'), nil
+ base, index = label.permalink(false), nil
_slugify = -> (i) { [base, i].compact.join('-') }
while !is_slug_unique?(_slugify.call(index), collection, locale)
locomotive/steam/repositories/filesystem/sanitizers/page.rb b/lib/locomotive/steam/repositories/filesystem/sanitizers/page.rb +10 -5
@@ @@ -49,15 +49,20 @@ module Locomotive
end
def modify_if_templatized(page, locale)
- content_type = fetch_content_type(parent_fullpath(page))
-
- if page.templatized? && content_type.nil?
+ if page.templatized?
# change the slug of a templatized page
- page[:slug][locale] = 'content_type_template'
+ page[:slug][locale] = 'content-type-template'
+
+ # this also means to change the fullpath
+ if page[:fullpath][locale]
+ page[:fullpath][locale].gsub!(/[^\/]+$/, 'content-type-template')
+ end
# make sure its children will have its content type
set_content_type(page._fullpath, page.content_type)
- else
+ elsif content_type = fetch_content_type(parent_fullpath(page))
+ # not a templatized page but it becomes one because
+ # its parent is one of them
page[:content_type] = content_type
end
end
locomotive/steam/server.rb b/lib/locomotive/steam/server.rb +1 -0
@@ @@ -38,6 +38,7 @@ module Locomotive::Steam
use Middlewares::Locale
use Middlewares::Timezone
use Middlewares::Page
+ use Middlewares::TemplatizedPage
run Middlewares::Renderer.new(nil)
end
spec/fixtures/default/app/views/pages/index.liquid.haml +12 -11
@@ @@ -3,14 +3,14 @@ title: Home page
---
!!! XML
!!!
- %html{ :lang => "en" }
+ %html{ lang: "en" }
%head
- %meta{ :charset => "utf-8" }
+ %meta{ charset: "utf-8" }
%title {{ site.name }}
- %meta{ :content => "{{ site.meta_description }}", :name => "description" }
- %meta{ :content => "{{ site.meta_keywords }}", :name => "keywords" }
+ %meta{ content: "{{ site.meta_description }}", name: "description" }
+ %meta{ content: "{{ site.meta_keywords }}", name: "keywords" }
{{ '/foo/bar' | auto_discovery_link_tag: 'rel:alternate', 'type:application/atom+xml', 'title:A title' }}
@@ @@ -25,9 +25,10 @@ title: Home page
{{ 'http://fonts.googleapis.com/css?family=Open+Sans:400,700' | stylesheet_tag }}
{{ 'reboot' | stylesheet_tag }}
{{ 'application' | stylesheet_tag }}
- %script{ :src => "{{ 'application.js' | javascript_url }}", :type => 'text/javascript' }
- %script{ :src => 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', :type => 'text/javascript' }
+ %script{ src: "{{ 'application.js' | javascript_url }}", type: "text/javascript" }
+
+ %script{ src: 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', type: 'text/javascript' }
{% inline_editor %}
@@ @@ -35,15 +36,15 @@ title: Home page
.container
#menu
%ul#nav
- %li#home{ :class => "{% if page.fullpath == 'index' %}on{% endif %} link" }
- %a{ :href => '/' } Home
+ %li#home{ class: "{% if page.fullpath == 'index' %}on{% endif %} link" }
+ %a{ href: '/' } Home
{% nav site, no_wrapper: true, exclude: 'events' %}
.clear
#banner
{% block banner %}
.photo
- %img{ :src => "{% editable_file 'Page image', hint: 'Top banner image in each page (602px by 397px)' %}/samples/photo.jpg{% endeditable_file %}" }
+ %img{ src: "{% editable_file 'Page image', hint: 'Top banner image in each page (602px by 397px)' %}/samples/photo.jpg{% endeditable_file %}" }
.text
{% editable_long_text 'pitch' %}
@@ @@ -51,7 +52,7 @@ title: Home page
%p
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse vitae egestas neque. Proin ac ante ante, sit amet egestas purus. Fusce tincidunt mattis sapien eget sodales. Cras aliquet odio eu nisl dapibus placerat.
%br
- %a{ :href => '/about_us' } read more...
+ %a{ href: '/about_us' } read more...
{% endeditable_long_text %}
{% endblock %}
@@ @@ -72,7 +73,7 @@ title: Home page
{% endfor %}
%p.more
- %a{ :href => '/events' } See more events ...
+ %a{ href: '/events' } See more events ...
#updates.unit.size1of2
%h2 Site updates
spec/integration/server/assets_spec.rb +10 -0
@@ @@ -8,6 +8,16 @@ describe Locomotive::Steam::Server do
run_server
end
+ describe 'theme assets' do
+
+ subject { get '/all'; last_response.body }
+
+ it { is_expected.to include('<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />') }
+ it { is_expected.to include('<script src="/javascripts/application.js" type=\'text/javascript\'></script>') }
+ it { is_expected.to include('<link rel="alternate" type="application/atom+xml" title="A title" href="/foo/bar" />') }
+
+ end
+
describe 'Static assets' do
it 'renders an image' do
spec/integration/server/basic_spec.rb +31 -35
@@ @@ -50,34 +50,42 @@ describe Locomotive::Steam::Server do
end
- # it 'shows a content type template', pending: true do
- # get '/songs/song-number-1'
- # last_response.body.should =~ /Song #1/
- # end
+ describe 'templatized page' do
- # it 'renders a page under a templatized one', pending: true do
- # get '/songs/song-number-1/band'
- # last_response.body.should =~ /Song #1/
- # last_response.body.should =~ /Leader: Eddie/
- # end
+ it 'shows a content type template' do
+ get '/songs/song-number-1'
+ expect(last_response.body).to include 'Song #1'
+ end
+
+ it 'renders a page under a templatized one' do
+ get '/songs/song-number-1/band'
+ expect(last_response.body).to include 'Song #1'
+ expect(last_response.body).to include 'Leader: Eddie'
+ end
- it 'translates strings' do
- get '/en'
- expect(last_response.body).to include 'Powered by'
- get '/fr'
- expect(last_response.body).to include 'Propulsé par'
end
- # it 'provides translation in scopes', pending: true do
- # get '/'
- # last_response.body.should =~ /scoped_translation=.French./
- # end
+ describe 'translations' do
- # it 'translates a page with link_to tags inside', pending: true do
- # get '/fr/notre-musique'
- # last_response.body.should =~ /<h3><a href="\/fr\/songs\/song-number-8">Song #8<\/a><\/h3>/
- # last_response.body.should =~ /Propulsé par/
- # end
+ it 'translates strings' do
+ get '/en'
+ expect(last_response.body).to include 'Powered by'
+ get '/fr'
+ expect(last_response.body).to include 'Propulsé par'
+ end
+
+ # it 'provides translation in scopes', pending: true do
+ # get '/'
+ # last_response.body.should =~ /scoped_translation=.French./
+ # end
+
+ # it 'translates a page with link_to tags inside', pending: true do
+ # get '/fr/notre-musique'
+ # last_response.body.should =~ /<h3><a href="\/fr\/songs\/song-number-8">Song #8<\/a><\/h3>/
+ # last_response.body.should =~ /Propulsé par/
+ # end
+
+ end
# it 'returns all the pages', pending: true do
# get '/all'
@@ @@ -101,18 +109,6 @@ describe Locomotive::Steam::Server do
# it { should_not match(/About Us/)}
# end
- # describe 'theme assets', pending: true do
-
- # subject { get '/all'; last_response.body }
-
- # it { should match(/<link href="\/stylesheets\/application.css" media="screen" rel="stylesheet" type="text\/css" \/>/) }
-
- # it { should match(/<script src="\/javascripts\/application.js" type='text\/javascript'><\/script>/) }
-
- # it { should match(/<link rel="alternate" type="application\/atom\+xml" title="A title" href="\/foo\/bar" \/>/) }
-
- # end
-
# describe 'session', pending: true do
# subject { get '/contest'; last_response.body }
spec/unit/liquid/filters/html_spec.rb +13 -13
@@ @@ -18,11 +18,11 @@ describe Locomotive::Steam::Liquid::Filters::Html do
it 'writes the tag to display a rss/atom feed' do
expect(auto_discovery_link_tag('/foo/bar')).to eq %(
- <link rel="alternate" type="application/rss+xml" title="RSS" href="/foo/bar">
+ <link rel="alternate" type="application/rss+xml" title="RSS" href="/foo/bar" />
).strip
expect(auto_discovery_link_tag('/foo/bar', 'rel:alternate2', 'type:atom', 'title:Hello world')).to eq %(
- <link rel="alternate2" type="atom" title="Hello world" href="/foo/bar">
+ <link rel="alternate2" type="atom" title="Hello world" href="/foo/bar" />
).strip
end
@@ @@ -80,31 +80,31 @@ describe Locomotive::Steam::Liquid::Filters::Html do
end
it 'returns a link tag for a stylesheet file' do
- result = "<link href=\"/sites/42/theme/stylesheets/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"/sites/42/theme/stylesheets/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('main.css')).to eq(result)
expect(stylesheet_tag('main')).to eq(result)
expect(stylesheet_tag(nil)).to eq('')
end
it 'returns a link tag for a stylesheet file with folder' do
- result = "<link href=\"/sites/42/theme/stylesheets/trash/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"/sites/42/theme/stylesheets/trash/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('trash/main.css')).to eq(result)
end
it 'returns a link tag for a stylesheet file without touching the url that starts with "/"' do
- result = "<link href=\"/trash/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"/trash/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('/trash/main.css')).to eq(result)
expect(stylesheet_tag('/trash/main')).to eq(result)
end
it 'returns a link tag for a stylesheet file without touching the url that starts with "http:"' do
- result = "<link href=\"http://cdn.example.com/trash/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"http://cdn.example.com/trash/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('http://cdn.example.com/trash/main.css')).to eq(result)
expect(stylesheet_tag('http://cdn.example.com/trash/main')).to eq(result)
end
it 'returns a link tag for a stylesheet file without touching the url that starts with "https:"' do
- result = "<link href=\"https://cdn.example.com/trash/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"https://cdn.example.com/trash/main.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('https://cdn.example.com/trash/main.css')).to eq(result)
expect(stylesheet_tag('https://cdn.example.com/trash/main')).to eq(result)
end
@@ @@ -112,36 +112,36 @@ describe Locomotive::Steam::Liquid::Filters::Html do
it 'returns a link tag for a stylesheet stored in Amazon S3' do
url = 'https://com.citrrus.locomotive.s3.amazonaws.com/sites/42/theme/stylesheets/bootstrap2.css'
allow(theme_asset_url).to receive(:build).and_return(url)
- result = "<link href=\"#{url}\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"#{url}\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('bootstrap2.css')).to eq(result)
end
it 'returns a link tag for a stylesheet file and media attribute set to print' do
- result = "<link href=\"/sites/42/theme/stylesheets/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"/sites/42/theme/stylesheets/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('main.css','print')).to eq(result)
expect(stylesheet_tag('main','print')).to eq(result)
expect(stylesheet_tag(nil)).to eq('')
end
it 'returns a link tag for a stylesheet file with folder and media attribute set to print' do
- result = "<link href=\"/sites/42/theme/stylesheets/trash/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"/sites/42/theme/stylesheets/trash/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('trash/main.css','print')).to eq(result)
end
it 'returns a link tag for a stylesheet file without touching the url that starts with "/" and media attribute set to print' do
- result = "<link href=\"/trash/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"/trash/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('/trash/main.css','print')).to eq(result)
expect(stylesheet_tag('/trash/main','print')).to eq(result)
end
it 'returns a link tag for a stylesheet file without touching the url that starts with "http:" and media attribute set to print' do
- result = "<link href=\"http://cdn.example.com/trash/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"http://cdn.example.com/trash/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('http://cdn.example.com/trash/main.css','print')).to eq(result)
expect(stylesheet_tag('http://cdn.example.com/trash/main','print')).to eq(result)
end
it 'returns a link tag for a stylesheet file without touching the url that starts with "https:" and media attribute set to print' do
- result = "<link href=\"https://cdn.example.com/trash/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\">"
+ result = "<link href=\"https://cdn.example.com/trash/main.css\" media=\"print\" rel=\"stylesheet\" type=\"text/css\" />"
expect(stylesheet_tag('https://cdn.example.com/trash/main.css','print')).to eq(result)
expect(stylesheet_tag('https://cdn.example.com/trash/main','print')).to eq(result)
end
spec/unit/repositories/filesystem/content_entry_spec.rb +2 -2
@@ @@ -23,7 +23,7 @@ describe Locomotive::Steam::Repositories::Filesystem::ContentEntry do
it { expect(subject.class).to eq Locomotive::Steam::Repositories::Filesystem::Models::ContentEntry }
it { expect(subject.title).to eq({ en: 'Update #1', fr: 'Mise a jour #1' }) }
- it { expect(subject._slug).to eq({ en: 'update-1', fr: 'mise-a-jour-1' }) }
+ it { expect(subject._slug).to eq({ en: 'update-number-1', fr: 'mise-a-jour-number-1' }) }
it { expect(subject.content_type).to eq type }
end
@@ @@ -47,7 +47,7 @@ describe Locomotive::Steam::Repositories::Filesystem::ContentEntry do
it { is_expected.to eq nil }
context 'existing slug' do
- let(:slug) { 'update-1' }
+ let(:slug) { 'update-number-1' }
it { expect(subject.title).to eq({ en: 'Update #1', fr: 'Mise a jour #1' }) }
end
spec/unit/repositories/filesystem/page_spec.rb +12 -0
@@ @@ -104,6 +104,18 @@ describe Locomotive::Steam::Repositories::Filesystem::Page do
end
+ context 'templatized page' do
+
+ let(:paths) { ['articles/content-type-template', 'content-type-template/hello-world', 'articles/hello-world'] }
+
+ let(:pages) do
+ [{ title: { en: 'Templatized article' }, slug: { en: 'template' }, content_type: 'articles', _fullpath: 'articles/template', template_path: { en: 'articles/template.liquid' } }]
+ end
+
+ it { expect(subject.first.title).to eq({ en: 'Templatized article' }) }
+
+ end
+
end
describe '#template_for' do