make the link_to and path_to tags work with localized data (+ write specs + refactoring)

did committed Feb 09, 2015
commit 805811ffed52939af516867e4e6774b20b8bef6a
Showing 23 changed files with 526 additions and 122 deletions
locomotive/steam/decorators/i18n_decorator.rb b/lib/locomotive/steam/decorators/i18n_decorator.rb +25 -9
@@ @@ -4,20 +4,24 @@ module Locomotive
class I18nDecorator < SimpleDelegator
- attr_accessor :__translated_attributes__
+ attr_accessor :__localized_attributes__
+ attr_accessor :__frozen_locale__
attr_reader :__locale__
attr_reader :__default_locale__
- def initialize(object, attributes, locale, default_locale = nil)
- self.__translated_attributes__ = attributes
- self.__locale__ = locale
- self.__default_locale__ = default_locale
+ def initialize(object, attributes, locale = nil, default_locale = nil)
+ self.__localized_attributes__ = attributes
+ self.__frozen_locale__ = false
+ self.__locale__ = locale
+ self.__default_locale__ = default_locale
super(object)
end
def __locale__=(locale)
- @__locale__ = locale.to_sym
+ unless self.__frozen_locale__
+ @__locale__ = locale.try(:to_sym)
+ end
end
def __default_locale__=(locale)
@@ @@ -26,13 +30,23 @@ module Locomotive
def __with_locale__(locale, &block)
old_locale, self.__locale__ = __locale__, locale.to_sym
+ self.__freeze_locale__
yield.tap do
+ self.__unfreeze_locale__
self.__locale__ = old_locale
end
end
+ def __freeze_locale__
+ @__frozen_locale__ = true
+ end
+
+ def __unfreeze_locale__
+ @__frozen_locale__ = false
+ end
+
def method_missing(name, *args, &block)
- if __translated_attributes__.include?(name.to_sym)
+ if __localized_attributes__.include?(name.to_sym)
field = __getobj__.public_send(:attributes)[name.to_sym]
field[__locale__] || field[__default_locale__] || super
else
@@ @@ -42,10 +56,12 @@ module Locomotive
#:nocov:
def inspect
- "[Decorated #{__getobj__.class.name}][I18n] " + @__translated_attributes__.inspect + ', locale: ' + @__locale__.inspect
+ "[Decorated #{__getobj__.class.name}][I18n] attributes exist? " +
+ __getobj__.respond_to?(:attributes).inspect +
+ ', localized attributes: ' + @__localized_attributes__.inspect +
+ ', locale: ' + @__locale__.inspect
end
-
end
end
locomotive/steam/decorators/page_decorator.rb b/lib/locomotive/steam/decorators/page_decorator.rb +0 -1
@@ @@ -8,7 +8,6 @@ module Locomotive
#
# @return [ hash ] The safe full paths
#
-
def safe_fullpath
if index_or_404?
slug[current_locale]
locomotive/steam/liquid.rb b/lib/locomotive/steam/liquid.rb +1 -0
@@ @@ -3,6 +3,7 @@ require 'solid'
require_relative 'liquid/errors'
require_relative 'liquid/patches'
require_relative 'liquid/drops/base'
+ require_relative 'liquid/drops/i18n_base'
require_relative 'liquid/drops/proxy_collection'
require_relative 'liquid/tags/hybrid'
require_relative 'liquid/tags/path_helper'
locomotive/steam/liquid/drops/base.rb b/lib/locomotive/steam/liquid/drops/base.rb +4 -1
@@ @@ -1,4 +1,3 @@
- # Liquify taken from Mephisto sources (http://mephistoblog.com/)
module Locomotive
module Steam
module Liquid
@@ @@ -35,6 +34,10 @@ module Locomotive
self.class.liquify(*records, &block)
end
+ def _source
+ @_source
+ end
+
end
end
end
locomotive/steam/liquid/drops/content_entry.rb b/lib/locomotive/steam/liquid/drops/content_entry.rb +1 -1
@@ @@ -2,7 +2,7 @@ module Locomotive
module Steam
module Liquid
module Drops
- class ContentEntry < Base
+ class ContentEntry < I18nBase
delegate :_slug, :_translated, :seo_title, :meta_keywords, :meta_description, to: :@_source
locomotive/steam/liquid/drops/i18n_base.rb b/lib/locomotive/steam/liquid/drops/i18n_base.rb +37 -0
@@ @@ -0,0 +1,37 @@
+ module Locomotive
+ module Steam
+ module Liquid
+ module Drops
+ class I18nBase < Base
+
+ def initialize(source, localized_attributes = [])
+ decorated = Locomotive::Steam::Decorators::I18nDecorator.new(source, localized_attributes)
+ super(decorated)
+ end
+
+ def context=(context)
+ if locale = context.registers[:locale]
+ @_source.__locale__ = locale
+ end
+
+ @_source.__default_locale__ = context.registers[:site].default_locale
+
+ super
+ end
+
+ private
+
+ def _change_locale(locale)
+ @_source.__locale__ = locale
+ end
+
+ def _change_locale!(locale)
+ @_source.__locale__ = locale
+ @_source.__freeze_locale__
+ end
+
+ end
+ end
+ end
+ end
+ end
locomotive/steam/liquid/drops/page.rb b/lib/locomotive/steam/liquid/drops/page.rb +1 -1
@@ @@ -2,7 +2,7 @@ module Locomotive
module Steam
module Liquid
module Drops
- class Page < Base
+ class Page < I18nBase
delegate :fullpath, :depth, :seo_title, :meta_keywords, :meta_description, :redirect_url, :handle, to: :@_source
delegate :listed?, :published?, :redirect?, :is_layout?, :templatized?, to: :@_source
locomotive/steam/liquid/patches.rb b/lib/locomotive/steam/liquid/patches.rb +27 -0
@@ @@ -20,3 +20,30 @@ module Liquid
end
end
+
+ module Liquid
+ module OptionsBuilder
+
+ private
+
+ def parse_options_from_string(string)
+ string.try(:strip!)
+
+ return nil if string.blank?
+
+ string = string.gsub(/^(\s*,)/, '')
+ Solid::Arguments.parse(string)
+ end
+
+ def interpolate_options(options, context)
+ if options
+ options.interpolate(context).first
+ else
+ {}
+ end
+ end
+
+ end
+ end
+
+ Liquid::Tag.send(:include, Liquid::OptionsBuilder)
locomotive/steam/liquid/tags/consume.rb b/lib/locomotive/steam/liquid/tags/consume.rb +2 -7
@@ @@ -22,7 +22,7 @@ module Locomotive
@name = $1.to_s
self.prepare_url($2)
- self.prepare_api_arguments($3)
+ @api_options = parse_options_from_string($3)
else
raise ::Liquid::SyntaxError.new("Syntax Error in 'consume' - Valid syntax: consume <var> from \"<url>\" [username: value, password: value]")
end
@@ @@ -50,13 +50,8 @@ module Locomotive
end
end
- def prepare_api_arguments(string)
- string = string.gsub(/^(\s*,)/, '').strip
- @api_arguments = Solid::Arguments.parse(string)
- end
-
def set_api_options(context)
- @api_options = @api_arguments ? @api_arguments.interpolate(context).first || {} : {}
+ @api_options = interpolate_options(@api_options, context)
@expires_in = @api_options.delete(:expires_in) || 0
end
locomotive/steam/liquid/tags/hybrid.rb b/lib/locomotive/steam/liquid/tags/hybrid.rb +33 -14
@@ @@ -5,22 +5,41 @@ module Locomotive
class Hybrid < ::Liquid::Block
- def parse(tokens)
- nesting = 0
- tokens.each do |token|
- next unless token =~ IsTag
- if token =~ FullToken
- if nesting == 0 && $1 == block_delimiter
- @render_as_block = true
- super
- return
- elsif $1 == block_name
- nesting += 1
- elsif $1 == block_delimiter
- nesting -= 1
- end
+ class HybridTagDetectedException < Exception; end
+
+ def parse_body(body, tokens)
+ body.parse(tokens, options) do |end_tag_name, end_tag_params|
+ @blank &&= body.blank?
+
+ return false if end_tag_name == block_delimiter
+ unless end_tag_name
+ # tag never closed
+ raise HybridTagDetectedException.new
end
+
+ # this tag is not registered with the system
+ # pass it to the current block for special handling or error reporting
+ unknown_tag(end_tag_name, end_tag_params, tokens)
+ end
+
+ true
+ end
+
+ def render_as_block?
+ @render_as_block
+ end
+
+ def parse(tokens)
+ @render_as_block = true
+ begin
+ cloned_tokens = tokens.dup
+ super(cloned_tokens)
+ tokens.replace(cloned_tokens)
+ rescue HybridTagDetectedException
+ @body = nil
+ @render_as_block = false
end
+ @blank = false
end
end
locomotive/steam/liquid/tags/link_to.rb b/lib/locomotive/steam/liquid/tags/link_to.rb +9 -10
@@ @@ -10,9 +10,11 @@ module Locomotive
render_path(context) do |page, path|
label = label_from_page(page)
- if @render_as_block
- context.scopes.last['target'] = page
- label = super.html_safe
+ if render_as_block?
+ context.stack do
+ context.scopes.last['target'] = page
+ label = super.html_safe
+ end
end
%{<a href="#{path}">#{label}</a>}
@@ @@ -26,13 +28,10 @@ module Locomotive
protected
def label_from_page(page)
- # TODO: page is a liquid drop whose source is I18n decorated
- ::Mongoid::Fields::I18n.with_locale(@options['locale']) do
- if page.templatized?
- page.content_entry._label
- else
- page.title
- end
+ if page.templatized?
+ page.send(:_source).content_entry._label
+ else
+ page.title
end
end
locomotive/steam/liquid/tags/nav.rb b/lib/locomotive/steam/liquid/tags/nav.rb +4 -11
@@ @@ -31,7 +31,7 @@ module Locomotive
end
def render(context)
- self.set_accessors_from_context(context)
+ self.set_vars_from_context(context)
# get all the children of a source: site (index page), parent or page.
pages = children_of(fetch_starting_page)
@@ @@ -77,6 +77,7 @@ module Locomotive
when 'parent' then page_repository.parent_of(current_page) || current_page
when 'page' then current_page
else
+ # TODO: locale???
page_repository.by_fullpath(@source)
end
end
@@ @@ -168,13 +169,6 @@ module Locomotive
css << @_options[:active_class] if self.page_selected?(page)
css << extra_css if !extra_css.blank?
end.join ' '
-
- # _css = ['link']
-
- # _css = 'link'
- # _css += " #{@_options[:active_class]}" if self.page_selected?(page)
-
- # (_css + " #{css}").strip.tap { |p| puts p.inspect }
end
# Return the HTML output of a page and its children if requested.
@@ @@ -240,10 +234,9 @@ module Locomotive
end
end
- # Avoid to call context.registers to get the current page
- # and the mounting point.
+ # Avoid to call context.registers to get the current page.
#
- def set_accessors_from_context(context)
+ def set_vars_from_context(context)
self.current_page = context.registers[:page]
self.services = context.registers[:services]
self.page_repository = self.services.repositories.page
locomotive/steam/liquid/tags/path_helper.rb b/lib/locomotive/steam/liquid/tags/path_helper.rb +62 -49
@@ @@ -4,15 +4,12 @@ module Locomotive
module Tags
module PathHelper
- Syntax = /(#{::Liquid::VariableSignature}+)/o
+ Syntax = /(#{::Liquid::VariableSignature}+)(\s*,.+)?/o
def initialize(tag_name, markup, options)
if markup =~ Syntax
@handle = $1
- @path_options = {}
- markup.scan(::Liquid::TagAttributes) do |key, value|
- @path_options[key] = value
- end
+ @path_options = parse_options_from_string($2)
else
self.wrong_syntax!
end
@@ @@ -21,15 +18,16 @@ module Locomotive
end
def render_path(context, &block)
- site = context.registers[:site]
+ set_vars_from_context(context)
- if page = self.retrieve_page_from_handle(site, context)
- path = self.public_page_fullpath(site, page)
+ # return a drop or model?
+ if page = self.retrieve_page_drop_from_handle
+ # make sure we've got the page/content entry (if templatized)
+ # in the right locale
+ change_locale(locale, page) do
+ path = build_fullpath(page)
- if block_given?
- block.call page, path
- else
- path
+ block_given? ? block.call(page, path) : path
end
else
'' # no page found
@@ @@ -38,59 +36,74 @@ module Locomotive
protected
- def retrieve_page_from_handle(site, context)
- handle = context[@handle] || @handle
+ def services
+ @context.registers[:services]
+ end
+
+ def repository
+ services.repositories.page
+ end
+
+ def change_locale(locale, drop, &block)
+ page = drop.send(:_source)
+
+ page.__with_locale__(locale) do
+ if page.templatized?
+ page.content_entry.__with_locale__(locale) { yield }
+ else
+ yield
+ end
+ end
+ end
+
+ def retrieve_page_drop_from_handle
+ handle = @context[@handle] || @handle
- # Note/TODO: we manipulate here only Liquid drops!
case handle
- when String then fetch_page(site, handle)
- when Locomotive::Steam::Liquid::Drops::Page then handle.instance_variable_get(:@_source)
- when Locomotive::Steam::Liquid::Drops::ContentEntry then fetch_page(site, handle.instance_variable_get(:@_source), true)
+ when String
+ _retrieve_page_drop_from(handle)
+ when Locomotive::Steam::Liquid::Drops::ContentEntry
+ _retrieve_templatized_page_drop_from(handle)
+ when Locomotive::Steam::Liquid::Drops::Page
+ handle
else
nil
end
- # case handle
- # when Locomotive::Page then handle
- # when Locomotive::Liquid::Drops::Page then handle.instance_variable_get(:@_source)
- # when String then fetch_page(site, handle)
- # when Locomotive::ContentEntry then fetch_page(site, handle, true)
- # when Locomotive::Liquid::Drops::ContentEntry then fetch_page(site, handle.instance_variable_get(:@_source), true)
- # else
- # nil
- # end
end
- def fetch_page(site, handle, templatized = false)
- # TODO: responsability of the page repository, no need of I18n
- # since the source is a I18nDecorated Page model :-)
- ::Mongoid::Fields::I18n.with_locale(self.locale) do
- if templatized
- criteria = site.pages.where(target_klass_name: handle.class.to_s, templatized: true)
- criteria = criteria.where(handle: @path_options['with']) if @path_options['with']
- criteria.first.tap do |page|
- page.content_entry = handle if page
- end
- else
- site.pages.where(handle: handle).first
- end
+ def _retrieve_page_drop_from(handle)
+ if page = repository.by_handle(handle)
+ page.to_liquid.tap { |d| d.context = @context }
end
end
- def public_page_fullpath(site, page)
- # TODO: responsability of the url_builder service
+ def _retrieve_templatized_page_drop_from(drop)
+ entry = drop.send(:_source)
- fullpath = site.localized_page_fullpath(page, self.locale)
+ if page = repository.template_for(entry, @path_options[:with])
+ page.to_liquid.tap { |d| d.context = @context }
+ end
+ end
- if page.templatized?
- fullpath.gsub!('content_type_template', page.content_entry._slug)
+ def build_fullpath(page)
+ services.url_builder.url_for(page, locale).tap do |fullpath|
+ if page.templatized?
+ entry = page.send(:_source).content_entry
+ fullpath.gsub!('content_type_template', entry._slug)
+ end
end
+ end
- File.join('/', fullpath)
+ def locale
+ @path_options[:locale] || @locale
end
- # def locale
- # @path_options['locale'] || I18n.locale
- # end
+ def set_vars_from_context(context)
+ @context = context
+ @path_options = interpolate_options(@path_options, context)
+ @site = context.registers[:site]
+ @locale = context.registers[:locale]
+ end
end
end
locomotive/steam/repositories/page.rb b/lib/locomotive/steam/repositories/page.rb +8 -0
@@ @@ -16,6 +16,14 @@ module Locomotive
site.pages.where(fullpath: path).first
end
+ def template_for(entry, handle = nil)
+ criteria = site.pages.where(target_klass_name: entry.class.to_s, templatized: true)
+ criteria = criteria.where(handle: handle) if handle
+ criteria.first.tap do |page|
+ page.content_entry = entry if page
+ end
+ end
+
def root
site.pages.root.first
end
locomotive/steam/services/url_builder.rb b/lib/locomotive/steam/services/url_builder.rb +21 -7
@@ @@ -2,20 +2,34 @@ module Locomotive
module Steam
module Services
- class UrlBuilder < Struct.new(:site, :locale)
+ class UrlBuilder < Struct.new(:site, :current_locale)
- def url_for(page)
- if locale.to_s == site.default_locale.to_s
- "/#{page.fullpath}"
- else
- "/#{locale}/#{page.fullpath}"
- end
+ def url_for(page, locale = nil)
+ [''].tap do |segments|
+ locale ||= current_locale
+ same_locale = locale.to_sym == site.default_locale.to_sym
+
+ segments << locale unless same_locale
+
+ # fullpath
+ segments << sanitized_fullpath(page.fullpath, same_locale)
+ end.compact.join('/')
end
def public_submission_url_for(content_type)
"/entry_submissions/#{content_type.slug}"
end
+ private
+
+ def sanitized_fullpath(path, same_locale)
+ if path == 'index'
+ same_locale ? '' : nil
+ else
+ path
+ end
+ end
+
end
end
spec/unit/decorators/i18n_decorator_spec.rb +16 -5
@@ @@ -3,12 +3,12 @@ require 'spec_helper'
describe Locomotive::Steam::Decorators::I18nDecorator do
let(:page) { instance_double('Page', title: 'Hello world', published?: true, attributes: { title: { en: 'Hello world!', fr: 'Bonjour monde' } }) }
- let(:translated) { [:title] }
+ let(:localized) { [:title] }
let(:locale) { 'fr' }
let(:default_locale) { nil }
- let(:decorated) { Locomotive::Steam::Decorators::I18nDecorator.new(page, translated, locale, default_locale) }
+ let(:decorated) { Locomotive::Steam::Decorators::I18nDecorator.new(page, localized, locale, default_locale) }
- it 'uses the translated version of the title attribute' do
+ it 'uses the localized version of the title attribute' do
expect(decorated.title).to eq 'Bonjour monde'
end
@@ @@ -16,9 +16,9 @@ describe Locomotive::Steam::Decorators::I18nDecorator do
expect(decorated.published?).to eq true
end
- describe 'no translated attributes: use the default method' do
+ describe 'no localized attributes: use the default method' do
- let(:translated) { [] }
+ let(:localized) { [] }
it { expect(decorated.title).to eq 'Hello world' }
end
@@ @@ -39,6 +39,17 @@ describe Locomotive::Steam::Decorators::I18nDecorator do
end
+ describe 'freeze locale' do
+
+ before { decorated.__freeze_locale__ }
+
+ it 'forbids the modification of the locale' do
+ decorated.__locale__ = 'en'
+ expect(decorated.title).to eq 'Bonjour monde'
+ end
+
+ end
+
it 'uses another way to switch to a different locale' do
decorated.__with_locale__(:en) do
expect(decorated.title).to eq 'Hello world!'
spec/unit/liquid/drops/content_entry_spec.rb +20 -1
@@ @@ -2,10 +2,11 @@ require 'spec_helper'
describe Locomotive::Steam::Liquid::Drops::ContentEntry do
+ let(:site) { instance_double('Site', default_locale: 'en') }
let(:entry) { instance_double('Article', _id: 42, title: 'Hello world', _label: 'Hello world', _slug: 'hello-world', _translated: false, seo_title: 'seo title', meta_keywords: 'keywords', meta_description: 'description') }
let(:assigns) { {} }
let(:services) { Locomotive::Steam::Services.build_instance }
- let(:context) { ::Liquid::Context.new(assigns, {}, { services: services }) }
+ let(:context) { ::Liquid::Context.new(assigns, {}, { services: services, site: site, locale: 'en' }) }
let(:drop) { Locomotive::Steam::Liquid::Drops::ContentEntry.new(entry).tap { |d| d.context = context } }
subject { drop }
@@ @@ -77,4 +78,22 @@ describe Locomotive::Steam::Liquid::Drops::ContentEntry do
end
+ describe 'i18n' do
+
+ let(:entry) { instance_double('Article', attributes: { title: { en: 'Hello world', fr: 'Bonjour monde' } }) }
+ let(:drop) { Locomotive::Steam::Liquid::Drops::ContentEntry.new(entry, [:title]).tap { |d| d.context = context } }
+
+ subject { drop.before_method(:title) }
+
+ it { is_expected.to eq 'Hello world' }
+
+ context 'change the current locale of the context' do
+
+ let(:context) { ::Liquid::Context.new(assigns, {}, { locale: 'fr', site: site }) }
+ it { is_expected.to eq 'Bonjour monde' }
+
+ end
+
+ end
+
end
spec/unit/liquid/drops/page_spec.rb +34 -3
@@ @@ -4,8 +4,9 @@ describe Locomotive::Steam::Liquid::Drops::Page do
let(:assigns) { {} }
let(:services) { Locomotive::Steam::Services.build_instance }
- let(:context) { ::Liquid::Context.new(assigns, {}, { services: services }) }
- let(:page) { instance_double('Page', id: 42, title: 'Index', slug: 'index', fullpath: 'index', content_type: nil, depth: 1, templatized?: false, listed?: true, published?: true, is_layout?: true, redirect?: false, seo_title: 'seo title', redirect_url: '/', handle: 'index', meta_keywords: 'keywords', meta_description: 'description') }
+ let(:site) { instance_double('Site', default_locale: 'en') }
+ let(:context) { ::Liquid::Context.new(assigns, {}, { locale: 'en', services: services, site: site }) }
+ let(:page) { instance_double('Page', id: 42, localized_attributes: [], title: 'Index', slug: 'index', fullpath: 'index', content_type: nil, depth: 1, templatized?: false, listed?: true, published?: true, is_layout?: true, redirect?: false, seo_title: 'seo title', redirect_url: '/', handle: 'index', meta_keywords: 'keywords', meta_description: 'description') }
let(:drop) { Locomotive::Steam::Liquid::Drops::Page.new(page).tap { |d| d.context = context } }
subject { drop }
@@ @@ -83,7 +84,7 @@ describe Locomotive::Steam::Liquid::Drops::Page do
let(:entry) { liquid_instance_double('ContentEntry', _label: 'First Article', _slug: 'first-article') }
let(:assigns) { { 'entry' => entry } }
- let(:page) { instance_double('Page', id: 42, title: 'Index', slug: 'index', templatized?: true, content_type: 'articles') }
+ let(:page) { instance_double('Page', id: 42, title: 'Index', slug: 'index', localized_attributes: [], templatized?: true, content_type: 'articles') }
it { expect(subject.title).to eq 'First Article' }
it { expect(subject.slug).to eq 'first-article' }
@@ @@ -100,4 +101,34 @@ describe Locomotive::Steam::Liquid::Drops::Page do
end
+ describe 'i18n' do
+
+ let(:page) { instance_double('Page', attributes: { title: { en: 'About us', fr: 'A notre sujet' } }, templatized?: false) }
+ let(:drop) { Locomotive::Steam::Liquid::Drops::Page.new(page, [:title]).tap { |d| d.context = context } }
+
+ it { expect(subject.title).to eq 'About us' }
+
+ context 'change the current locale of the context' do
+
+ let(:context) { ::Liquid::Context.new(assigns, {}, { locale: 'fr', site: site }) }
+ it { expect(subject.title).to eq 'A notre sujet' }
+
+ end
+
+ context 'change the locale down the road' do
+
+ before { subject.send(:_change_locale, 'fr') }
+ it { expect(subject.title).to eq 'A notre sujet' }
+
+ end
+
+ it 'prevents further modifications of the locale' do
+ subject.send(:_change_locale!, 'fr')
+ expect(subject.title).to eq 'A notre sujet'
+ subject.send(:_change_locale, 'en')
+ expect(subject.title).to eq 'A notre sujet'
+ end
+
+ end
+
end
spec/unit/liquid/tags/consume_spec.rb +1 -1
@@ @@ -69,7 +69,7 @@ describe Locomotive::Steam::Liquid::Tags::Consume do
let(:response) { { 'title' => 'first response' } }
let(:url) { 'http://blog.locomotiveapp.org/api/read' }
- let(:source) { %{{% consume blog from "#{url}" timeout:5.0 %}{{ blog.title }}{% endconsume %}} }
+ let(:source) { %{{% consume blog from "#{url}" timeout: 5.0 %}{{ blog.title }}{% endconsume %}} }
it 'should pass the timeout option to httparty' do
expect(services.external_api).to receive(:consume).with(url, timeout: 5.0).and_return(response)
spec/unit/liquid/tags/link_to_spec.rb +105 -0
@@ @@ -0,0 +1,105 @@
+ require 'spec_helper'
+
+ describe Locomotive::Steam::Liquid::Tags::PathTo do
+
+ let(:assigns) { {} }
+ let(:services) { Locomotive::Steam::Services.build_instance }
+ let(:site) { instance_double('Site', default_locale: 'en') }
+ let(:context) { ::Liquid::Context.new(assigns, {}, { services: services, site: site, locale: 'en' }) }
+
+ subject { render_template(source, context) }
+
+ before { allow(services).to receive(:current_site).and_return(site) }
+
+ describe 'parsing' do
+
+ let(:source) { '{% link_to %}' }
+ it { expect { subject }.to raise_error("Syntax Error in 'link_to' - Valid syntax: link_to page_handle, locale es (locale is optional)") }
+
+ context 'unknown tag' do
+
+ let(:source) { '{% link_to index %}{% endbar %}{% endlink_to %}' }
+ it { expect { subject }.to raise_error("Liquid syntax error: Unknown tag 'endbar'") }
+
+ end
+
+ end
+
+ describe 'unknown page' do
+
+ let(:source) { '{% link_to index %}' }
+
+ before do
+ expect(services.repositories.page).to receive(:by_handle).with('index').and_return(nil)
+ end
+
+ it { is_expected.to eq '' }
+
+ end
+
+ describe '#render' do
+
+ let(:drop) { Locomotive::Steam::Liquid::Drops::Page.new(page, [:title, :fullpath]) }
+ let(:page) { liquid_instance_double('Index', handle: 'index', attributes: { title: { en: 'Home', fr: 'Accueil' }, fullpath: fullpath }, templatized?: false) }
+ let(:fullpath) { { en: 'index', fr: 'index' } }
+
+ before do
+ allow(services.repositories.page).to receive(:by_handle).with('index').and_return(page)
+ allow(page).to receive(:to_liquid).and_return(drop)
+ end
+
+ describe 'used as a tag' do
+
+ let(:source) { 'My link: {% link_to index %}!' }
+ it { is_expected.to eq 'My link: <a href="/">Home</a>!' }
+
+ context 'and a different locale' do
+
+ let(:source) { "{% link_to index, locale: 'fr' %}" }
+ it { is_expected.to eq '<a href="/fr">Accueil</a>' }
+
+ end
+
+ end
+
+ describe 'used as a block' do
+
+ let(:source) { 'My link: {% link_to index %}click here{% endlink_to %}!' }
+ it { is_expected.to eq 'My link: <a href="/">click here</a>!' }
+
+ context 'and a different locale' do
+
+ let(:source) { "{% link_to index, locale: 'fr' %}{{ target.title }}!{% endlink_to %}" }
+ it { is_expected.to eq '<a href="/fr">Accueil!</a>' }
+
+ end
+
+ end
+
+ describe 'link to a content entry (drop)' do
+
+ let(:assigns) { { 'article' => entry_drop } }
+ let(:entry_drop) { Locomotive::Steam::Liquid::Drops::ContentEntry.new(entry, [:_label, :_slug]) }
+ let(:entry) { liquid_instance_double('Article', attributes: { _label: { en: 'Hello world', fr: 'Bonjour monde' }, _slug: { en: 'hello-world', fr: 'bonjour-monde' } }) }
+ let(:drop) { Locomotive::Steam::Liquid::Drops::Page.new(page, [:fullpath]) }
+ let(:page) { liquid_instance_double('ArticleTemplate', title: 'Template of an article', handle: 'article', attributes: { fullpath: { en: 'my-articles/content_type_template', fr: 'mes-articles/content_type_template' } }, localized_attributes: [:fullpath], content_entry: entry_drop.send(:_source), templatized?: true) }
+ let(:source) { '{% link_to article %}' }
+
+ before do
+ expect(services.repositories.page).to receive(:template_for).with(entry, nil).and_return(page)
+ end
+
+ it { is_expected.to eq '<a href="/my-articles/hello-world">Hello world</a>' }
+
+ context 'with a different locale' do
+
+ let(:source) { "{% link_to article, locale: 'fr' %}" }
+ it { is_expected.to eq '<a href="/fr/mes-articles/bonjour-monde">Bonjour monde</a>' }
+
+ end
+
+ end
+
+ end
+
+ end
spec/unit/liquid/tags/nav_spec.rb +1 -1
@@ @@ -218,7 +218,7 @@ describe 'Locomotive::Steam::Liquid::Tags::Nav' do
let(:source) { %({% nav parent, active_class: "active" %}) }
before do
- services.url_builder.locale = 'fr'
+ services.url_builder.current_locale = 'fr'
allow(repository).to receive(:parent_of).with(page).and_return(index)
allow(repository).to receive(:children_of).with(index).and_return(depth_1)
end
spec/unit/liquid/tags/path_to_spec.rb +100 -0
@@ @@ -0,0 +1,100 @@
+ require 'spec_helper'
+
+ describe Locomotive::Steam::Liquid::Tags::PathTo do
+
+ let(:assigns) { {} }
+ let(:services) { Locomotive::Steam::Services.build_instance }
+ let(:site) { instance_double('Site', default_locale: 'en') }
+ let(:context) { ::Liquid::Context.new(assigns, {}, { services: services, site: site, locale: 'en' }) }
+
+ subject { render_template(source, context) }
+
+ before { allow(services).to receive(:current_site).and_return(site) }
+
+ describe 'parsing' do
+
+ let(:source) { '{% path_to %}' }
+ it { expect { subject }.to raise_error('Valid syntax: path_to <page|page_handle|content_entry>(, locale: [fr|de|...], with: <page_handle>') }
+
+ end
+
+ describe 'unknown page' do
+
+ let(:source) { '{% path_to index %}' }
+
+ before do
+ expect(services.repositories.page).to receive(:by_handle).with('index').and_return(nil)
+ end
+
+ it { is_expected.to eq '' }
+
+ end
+
+ describe 'from a handle of a page' do
+
+ let(:drop) { Locomotive::Steam::Liquid::Drops::Page.new(page, [:fullpath]) }
+ let(:page) { liquid_instance_double('Index', title: 'Index', handle: 'index', attributes: { fullpath: fullpath }, templatized?: false) }
+ let(:fullpath) { { en: 'index', fr: 'index' } }
+ let(:source) { '{% path_to index %}' }
+
+ before do
+ expect(services.repositories.page).to receive(:by_handle).with('index').and_return(page)
+ allow(page).to receive(:to_liquid).and_return(drop)
+ end
+
+ it { is_expected.to eq '/' }
+
+ context 'and a different locale' do
+
+ let(:source) { "{% path_to index, locale: 'fr' %}" }
+ it { is_expected.to eq '/fr' }
+
+ end
+
+ end
+
+ describe 'from a page (drop) itself' do
+
+ let(:assigns) { { 'about_us' => drop } }
+ let(:drop) { Locomotive::Steam::Liquid::Drops::Page.new(page, [:fullpath]) }
+ let(:page) { liquid_instance_double('AboutUs', title: 'About us', handle: 'index', attributes: { fullpath: fullpath }, localized_attributes: [:fullpath], templatized?: false) }
+ let(:fullpath) { { en: 'about-us', fr: 'a-notre-sujet' } }
+ let(:source) { '{% path_to about_us %}' }
+
+ it { is_expected.to eq '/about-us' }
+
+ context 'and a different locale' do
+
+ let(:source) { "{% path_to about_us, locale: 'fr' %}" }
+ it { is_expected.to eq '/fr/a-notre-sujet' }
+
+ end
+
+ end
+
+ describe 'from a content entry (drop)' do
+
+ let(:assigns) { { 'article' => entry_drop } }
+ let(:entry_drop) { Locomotive::Steam::Liquid::Drops::ContentEntry.new(entry, [:_slug]) }
+ let(:entry) { liquid_instance_double('Article', attributes: { _slug: { en: 'hello-world', fr: 'bonjour-monde' } }) }
+ let(:drop) { Locomotive::Steam::Liquid::Drops::Page.new(page, [:fullpath]) }
+ let(:page) { liquid_instance_double('ArticleTemplate', title: 'Template of an article', handle: 'article', attributes: { fullpath: { en: 'my-articles/content_type_template', fr: 'mes-articles/content_type_template' } }, localized_attributes: [:fullpath], content_entry: entry_drop.send(:_source), templatized?: true) }
+ let(:source) { '{% path_to article %}' }
+
+ before do
+ expect(services.repositories.page).to receive(:template_for).with(entry, nil).and_return(page)
+ allow(page).to receive(:to_liquid).and_return(drop)
+ end
+
+ it { is_expected.to eq '/my-articles/hello-world' }
+
+ context 'and a different locale' do
+
+ let(:source) { "{% path_to article, locale: 'fr' %}" }
+ it { is_expected.to eq '/fr/mes-articles/bonjour-monde' }
+
+ end
+
+ end
+
+ end
spec/unit/services/url_builder_spec.rb +14 -0
@@ @@ -21,6 +21,20 @@ describe Locomotive::Steam::Services::UrlBuilder do
end
+ describe 'no need to put the index slug' do
+
+ let(:page) { instance_double('Index', fullpath: 'index') }
+ it { is_expected.to eq '/' }
+
+ context 'different locale' do
+
+ let(:locale) { 'fr' }
+ it { is_expected.to eq '/fr' }
+
+ end
+
+ end
+
end
end