refactor the extends and inherited_block tags, uncouple them from the persistence layer + add specs
did
committed Feb 03, 2015
commit a005442454050bc4d41091690700010004bca10e
Showing 13
changed files with
242 additions
and 56 deletions
Gemfile
+2
-1
| @@ | @@ -6,7 +6,8 @@ group :development do |
| # gem 'locomotivecms_common', '~> 0.0.2', path: '../common' | |
| # gem 'locomotivecms_models', '~> 0.0.1', path: '../models' | |
| # gem 'locomotivecms_models', '0.0.1.pre.alpha' | |
| - | gem 'thin' |
| + | # gem 'locomotivecms-liquid', path: '/Users/didier/Documents/LocomotiveCMS/gems/liquid' |
| + | # gem 'thin' |
| end | |
| group :test do | |
Gemfile.lock
+4
-11
| @@ | @@ -11,7 +11,7 @@ PATH |
| httparty (~> 0.13.3) | |
| kaminari (~> 0.16.2) | |
| kramdown (~> 1.5.0) | |
| - | locomotivecms-solid (~> 4.0.0.alpha) |
| + | locomotivecms-solid (~> 4.0.0.alpha1) |
| locomotivecms_common (~> 0.0.2) | |
| mimetype-fu (~> 0.1.2) | |
| moneta (~> 0.8.0) | |
| @@ | @@ -71,7 +71,6 @@ GEM |
| simplecov (~> 0.9.1) | |
| term-ansicolor (~> 1.3) | |
| thor (~> 0.19.1) | |
| - | daemons (1.1.9) |
| diff-lcs (1.2.5) | |
| docile (1.1.5) | |
| dragonfly (1.0.7) | |
| @@ | @@ -79,7 +78,6 @@ GEM |
| multi_json (~> 1.0) | |
| rack | |
| erubis (2.7.0) | |
| - | eventmachine (1.0.4) |
| execjs (2.2.2) | |
| ffi (1.9.6) | |
| haml (4.0.6) | |
| @@ | @@ -101,9 +99,9 @@ GEM |
| actionpack (>= 3.0.0) | |
| activesupport (>= 3.0.0) | |
| kramdown (1.5.0) | |
| - | locomotivecms-liquid (4.0.0.alpha) |
| - | locomotivecms-solid (4.0.0.alpha) |
| - | locomotivecms-liquid (= 4.0.0.alpha) |
| + | locomotivecms-liquid (4.0.0.alpha1) |
| + | locomotivecms-solid (4.0.0.alpha1) |
| + | locomotivecms-liquid (= 4.0.0.alpha1) |
| locomotivecms_common (0.0.2) | |
| colorize | |
| loofah (2.0.1) | |
| @@ | @@ -175,10 +173,6 @@ GEM |
| tilt (~> 1.1) | |
| term-ansicolor (1.3.0) | |
| tins (~> 1.0) | |
| - | thin (1.6.3) |
| - | daemons (~> 1.0, >= 1.0.9) |
| - | eventmachine (~> 1.0) |
| - | rack (~> 1.0) |
| thor (0.19.1) | |
| thread_safe (0.3.4) | |
| tilt (1.4.1) | |
| @@ | @@ -198,4 +192,3 @@ DEPENDENCIES |
| pry | |
| rake (~> 10.4.2) | |
| rspec (~> 3.1.0) | |
| - | thin |
locomotive/steam/liquid/tags/extends.rb b/lib/locomotive/steam/liquid/tags/extends.rb
+40
-28
| @@ | @@ -4,40 +4,20 @@ module Locomotive |
| module Tags | |
| class Extends < ::Liquid::Extends | |
| - | def prepare_parsing |
| - | super |
| - | |
| - | parent_page = @context[:parent_page] |
| - | |
| - | @context[:page].merge_editable_elements_from_page(parent_page) |
| - | |
| - | @context[:snippets] = parent_page.snippet_dependencies |
| - | @context[:templates] = ([*parent_page.template_dependencies] + [parent_page.id]).compact |
| - | end |
| - | |
| private | |
| def parse_parent_template | |
| - | if @template_name == 'parent' |
| - | @context[:parent_page] = @context[:cached_parent] || @context[:page].parent |
| - | else |
| - | locale = ::Mongoid::Fields::I18n.locale |
| + | parent = options[:parent_finder].find(options[:page], @template_name) |
| - | @context[:parent_page] = @context[:cached_pages].try(:[], @template_name) || |
| - | @context[:site].pages.where("fullpath.#{locale}" => @template_name).first |
| - | end |
| + | # no need to go further if the parent does not exist |
| + | raise PageNotFound.new("Page with fullpath '#{@template_name}' was not found") if parent.nil? |
| - | raise PageNotFound.new("Page with fullpath '#{@template_name}' was not found") if @context[:parent_page].nil? |
| - | |
| - | # be sure to work with a copy of the parent template otherwise there will be conflicts |
| - | parent_template = @context[:parent_page].template.try(:clone) |
| - | |
| - | raise PageNotTranslated.new("Page with fullpath '#{@template_name}' was not translated") if parent_template.nil? |
| - | |
| - | # force the page to restore the original version of its template (from the serialized version) |
| - | @context[:parent_page].instance_variable_set(:@template, nil) |
| + | if listener = options[:events_listener] |
| + | listener.emit(:extends, page: options[:page], parent: parent) |
| + | end |
| - | parent_template |
| + | # the source has already been parsed before |
| + | parent.template || ::Liquid::Template.parse(parent.source, options.merge(page: parent)) |
| end | |
| end | |
| @@ | @@ -47,3 +27,35 @@ module Locomotive |
| end | |
| end | |
| end | |
| + | |
| + | # def prepare_parsing |
| + | # super |
| + | |
| + | # parent_page = @context[:parent_page] |
| + | |
| + | # @context[:page].merge_editable_elements_from_page(parent_page) |
| + | |
| + | # @context[:snippets] = parent_page.snippet_dependencies |
| + | # @context[:templates] = ([*parent_page.template_dependencies] + [parent_page.id]).compact |
| + | # end |
| + | |
| + | # if @template_name == 'parent' |
| + | # @context[:parent_page] = @context[:cached_parent] || @context[:page].parent |
| + | # else |
| + | # locale = ::Mongoid::Fields::I18n.locale |
| + | |
| + | # @context[:parent_page] = @context[:cached_pages].try(:[], @template_name) || |
| + | # @context[:site].pages.where("fullpath.#{locale}" => @template_name).first |
| + | # end |
| + | |
| + | # raise PageNotFound.new("Page with fullpath '#{@template_name}' was not found") if @context[:parent_page].nil? |
| + | |
| + | # # be sure to work with a copy of the parent template otherwise there will be conflicts |
| + | # parent_template = @context[:parent_page].template.try(:clone) |
| + | |
| + | # raise PageNotTranslated.new("Page with fullpath '#{@template_name}' was not translated") if parent_template.nil? |
| + | |
| + | # # force the page to restore the original version of its template (from the serialized version) |
| + | # @context[:parent_page].instance_variable_set(:@template, nil) |
| + | |
| + | # parent_template |
locomotive/steam/liquid/tags/fetch_page.rb b/lib/locomotive/steam/liquid/tags/fetch_page.rb
+1
-1
| @@ | @@ -25,7 +25,7 @@ module Locomotive |
| end | |
| def render(context) | |
| - | page = context.registers[:repositories].page.find_by_handle(@handle) |
| + | page = context.registers[:repositories].page.by_handle(@handle) |
| context.scopes.last[@var] = page | |
| '' | |
| end | |
locomotive/steam/liquid/tags/inherited_block.rb b/lib/locomotive/steam/liquid/tags/inherited_block.rb
+15
-9
| @@ | @@ -4,26 +4,32 @@ module Locomotive |
| module Tags | |
| class InheritedBlock < ::Liquid::InheritedBlock | |
| - | def end_tag |
| - | super |
| - | |
| - | if !self.contains_super?(@nodelist) # then disable all editable_elements coming from the parent block too and not used |
| - | @context[:page].disable_parent_editable_elements(@name) unless @context[:page].nil? |
| + | def parse(tokens) |
| + | super.tap do |
| + | if listener = options[:events_listener] |
| + | listener.emit(:inherited_block, page: options[:page], name: @name, found_super: self.contains_super?(nodelist)) |
| + | end |
| end | |
| end | |
| protected | |
| - | def contains_super?(nodelist) |
| - | nodelist.any? do |node| |
| - | if node.is_a?(::Liquid::Variable) && node.name == 'block.super' |
| + | def contains_super?(nodes) |
| + | nodes.any? do |node| |
| + | if is_node_block_super?(node) |
| true | |
| - | elsif node.respond_to?(:nodelist) && !node.nodelist.nil? && !node.is_a?(Locomotive::Liquid::Tags::InheritedBlock) |
| + | elsif node.respond_to?(:nodelist) && !node.nodelist.nil? && !node.is_a?(Locomotive::Steam::Liquid::Tags::InheritedBlock) |
| contains_super?(node.nodelist) | |
| end | |
| end | |
| end | |
| + | def is_node_block_super?(node) |
| + | return unless node.is_a?(::Liquid::Variable) |
| + | |
| + | node.raw.strip == 'block.super' |
| + | end |
| + | |
| end | |
| ::Liquid::Template.register_tag('block', InheritedBlock) | |
locomotive/steam/repositories/page.rb b/lib/locomotive/steam/repositories/page.rb
+9
-1
| @@ | @@ -4,10 +4,18 @@ module Locomotive |
| class Page < Struct.new(:site) | |
| - | def find_by_handle(handle) |
| + | def by_handle(handle) |
| site.pages.where(handle: handle).first | |
| end | |
| + | def parent_of(page) |
| + | page.parent |
| + | end |
| + | |
| + | def by_fullpath(path) |
| + | site.pages.where(fullpath: path).first |
| + | end |
| + | |
| end | |
| end | |
locomotive/steam/services/parent_finder.rb b/lib/locomotive/steam/services/parent_finder.rb
+27
-0
| @@ | @@ -0,0 +1,27 @@ |
| + | module Locomotive |
| + | module Steam |
| + | module Services |
| + | |
| + | class ParentFinder < Struct.new(:site) |
| + | |
| + | include Morphine |
| + | |
| + | register :repository do |
| + | Repositories::Page.new(site) |
| + | end |
| + | |
| + | def find(page, fullpath) |
| + | return nil if fullpath.blank? |
| + | |
| + | if fullpath.strip == 'parent' |
| + | repository.parent_of(page) |
| + | else |
| + | repository.by_fullpath(fullpath) |
| + | end |
| + | end |
| + | |
| + | end |
| + | |
| + | end |
| + | end |
| + | end |
locomotivecms_steam.gemspec
+1
-4
| @@ | @@ -40,11 +40,8 @@ Gem::Specification.new do |spec| |
| spec.add_dependency 'haml', '~> 4.0.6' | |
| spec.add_dependency 'mimetype-fu', '~> 0.1.2' | |
| - | |
| - | |
| - | |
| # spec.add_dependency 'locomotivecms_models', '~> 0.0.1.pre.alpha' | |
| - | spec.add_dependency 'locomotivecms-solid', '~> 4.0.0.alpha' |
| + | spec.add_dependency 'locomotivecms-solid', '~> 4.0.0.alpha1' |
| spec.add_dependency 'locomotivecms_common', '~> 0.0.2' | |
| # spec.required_ruby_version = '~> 2.0' | |
spec/support/liquid.rb
+18
-0
| @@ | @@ -3,3 +3,21 @@ def render_template(template, context = nil) |
| context.exception_handler = ->(e) { true } | |
| ::Liquid::Template.parse(template).render(context) | |
| end | |
| + | |
| + | def parse_template(template, options = nil) |
| + | ::Liquid::Template.parse(template, options || {}) |
| + | end |
| + | |
| + | module Liquid |
| + | class SimpleEventsListener |
| + | def emit(name, options = {}) |
| + | (@stack ||= []) << [name, options] |
| + | end |
| + | def event_names |
| + | @stack.map { |(name, _)| name } |
| + | end |
| + | def events |
| + | @stack |
| + | end |
| + | end |
| + | end |
spec/unit/liquid/tags/extends_spec.rb
+51
-0
| @@ | @@ -0,0 +1,51 @@ |
| + | require 'spec_helper' |
| + | |
| + | describe Locomotive::Steam::Liquid::Tags::Extends do |
| + | |
| + | let(:source) { '{% extends parent %} ' } |
| + | let(:page) { instance_double('Page', title: 'About us') } |
| + | let(:listener) { Liquid::SimpleEventsListener.new } |
| + | let(:finder) { Locomotive::Steam::Services::ParentFinder.new(nil) } |
| + | let(:options) { { events_listener: listener, parent_finder: finder, page: page } } |
| + | |
| + | before do |
| + | allow(finder.repository).to receive(:parent_of).and_return(parent) |
| + | end |
| + | |
| + | describe 'no parent page found' do |
| + | |
| + | let(:parent) { nil } |
| + | let(:template) { parse_template(source, options) } |
| + | |
| + | it { expect { template }.to raise_exception Locomotive::Steam::Liquid::PageNotFound } |
| + | |
| + | end |
| + | |
| + | describe 'parent page exists' do |
| + | |
| + | let!(:template) { parse_template(source, options) } |
| + | |
| + | describe 'parent template already parsed' do |
| + | |
| + | let(:parent_template) { parse_template('Hello world') } |
| + | let(:parent) { instance_double('Index', template: parent_template) } |
| + | |
| + | it { expect(listener.event_names.first).to eq :extends } |
| + | it { expect(template.render).to eq 'Hello world' } |
| + | it { expect(options[:page]).to eq page } |
| + | |
| + | end |
| + | |
| + | describe 'parent template not parsed yet' do |
| + | |
| + | let(:parent) { instance_double('Index', source: 'Hello world!', template: nil) } |
| + | |
| + | it { expect(listener.event_names.first).to eq :extends } |
| + | it { expect(template.render).to eq 'Hello world!' } |
| + | it { expect(options[:page]).to eq page } |
| + | |
| + | end |
| + | |
| + | end |
| + | |
| + | end |
spec/unit/liquid/tags/fetch_page_spec.rb
+1
-1
| @@ | @@ -8,7 +8,7 @@ describe Locomotive::Steam::Liquid::Tags::FetchPage do |
| let(:context) { ::Liquid::Context.new(assigns, {}, { repositories: repositories }) } | |
| let(:page) { instance_double('Page', to_liquid: { 'title' => 'About Us' }) } | |
| - | before { allow(repositories.page).to receive(:find_by_handle).and_return(page) } |
| + | before { allow(repositories.page).to receive(:by_handle).and_return(page) } |
| subject { render_template(template, context) } | |
spec/unit/liquid/tags/inherited_block_spec.rb
+33
-0
| @@ | @@ -0,0 +1,33 @@ |
| + | require 'spec_helper' |
| + | |
| + | describe Locomotive::Steam::Liquid::Tags::InheritedBlock do |
| + | |
| + | let(:parent_source) { 'My product: {% block product %}Random{% endblock %}' } |
| + | let(:parent) { instance_double('Index', source: parent_source, template: nil) } |
| + | let(:source) { '{% extends parent %}{% block product %}Skis{% endblock %}' } |
| + | let(:page) { instance_double('Page') } |
| + | |
| + | let(:listener) { Liquid::SimpleEventsListener.new } |
| + | let(:finder) { instance_double('Finder', find: parent) } |
| + | let(:options) { { page: page, events_listener: listener, parent_finder: finder } } |
| + | |
| + | let!(:template) { parse_template(source, options) } |
| + | |
| + | describe 'without a super block' do |
| + | |
| + | it { expect(listener.events.size).to eq 3 } |
| + | it { expect(listener.events.first.last[:found_super]).to eq false } |
| + | it { expect(template.render).to eq 'My product: Skis' } |
| + | |
| + | end |
| + | |
| + | describe 'with a super block' do |
| + | |
| + | let(:source) { '{% extends parent %}{% block product %}Skis (previous: {{ block.super }}){% endblock %}' } |
| + | |
| + | it { expect(listener.events.first.last[:found_super]).to eq true } |
| + | it { expect(template.render).to eq 'My product: Skis (previous: Random)' } |
| + | |
| + | end |
| + | |
| + | end |
spec/unit/services/parent_finder_spec.rb
+40
-0
| @@ | @@ -0,0 +1,40 @@ |
| + | require 'spec_helper' |
| + | |
| + | describe Locomotive::Steam::Services::ParentFinder do |
| + | |
| + | let(:service) { Locomotive::Steam::Services::ParentFinder.new(nil) } |
| + | let(:repository) { service.repository } |
| + | |
| + | describe '#find' do |
| + | |
| + | let(:name) { '' } |
| + | let(:another_page) { instance_double('Index', title: 'Index') } |
| + | let(:page) { instance_double('AboutUs', title: 'About us') } |
| + | |
| + | subject { service.find(page, name) } |
| + | |
| + | it { is_expected.to eq nil } |
| + | |
| + | describe 'using the parent keyword' do |
| + | |
| + | let(:name) { 'parent' } |
| + | |
| + | before { expect(repository).to receive(:parent_of).and_return(another_page) } |
| + | |
| + | it { is_expected.to eq another_page } |
| + | |
| + | end |
| + | |
| + | describe 'using the fullpath' do |
| + | |
| + | let(:name) { 'index' } |
| + | |
| + | before { expect(repository).to receive(:by_fullpath).with('index').and_return(another_page) } |
| + | |
| + | it { is_expected.to eq another_page } |
| + | |
| + | end |
| + | |
| + | end |
| + | |
| + | end |