better support of liquid syntax errors as well as action errors. Wagon will now display the line where the error happens and the line of codes around the wrong statement

did committed Jan 12, 2017
commit b1feb8b6e04a892225344aafa5da2d074fd6ee90
Showing 16 changed files with 121 additions and 24 deletions
locomotive/steam/decorators/template_decorator.rb b/lib/locomotive/steam/decorators/template_decorator.rb +1 -1
@@ @@ -38,7 +38,7 @@ module Locomotive
begin
Haml::Engine.new(source).render
rescue Haml::SyntaxError => e
- raise Steam::RenderError.new(e.message, template_path, source, e.line, e.backtrace)
+ raise Steam::RenderError.new(e, template_path, source)
end
end
locomotive/steam/errors.rb b/lib/locomotive/steam/errors.rb +26 -7
@@ @@ -3,18 +3,15 @@ module Locomotive::Steam
class NoSiteException < ::Exception
end
- class ActionException < ::Exception
- end
-
class RedirectionException < ::Exception
alias url message
end
- class RenderError < ::StandardError
+ class ParsingRenderingError < ::StandardError
LINES_RANGE = 10
- attr_reader :file, :source, :line, :original_backtrace
+ attr_accessor :file, :line, :source, :original_backtrace
def initialize(message, file, source, line, original_backtrace)
@file, @source, @line, @original_backtrace = file, source, line, original_backtrace
@@ @@ -27,10 +24,10 @@ module Locomotive::Steam
lines = source.split("\n")
start = line - (LINES_RANGE / 2)
- start = 0 if start < 0
+ start = 1 if start <= 0
finish = line + (LINES_RANGE / 2)
- (start..finish).map { |i| [i, lines[i]] }
+ (start..finish).map { |i| [i, lines[i - 1]] }
end
def backtrace
@@ @@ -39,4 +36,26 @@ module Locomotive::Steam
end
+ class RenderError < ParsingRenderingError
+
+ def initialize(error, file, source)
+ message = error.message
+ line = error.respond_to?(:line_number) ? error.line_number : error.line
+ backtrace = error.backtrace
+
+ super(message, file, source, line, backtrace)
+ end
+
+ end
+
+ class ActionError < ParsingRenderingError
+
+ attr_accessor :action
+
+ def initialize(error, script)
+ super(error.message, nil, script, 0, error.backtrace)
+ end
+
+ end
+
end
locomotive/steam/liquid/tags/action.rb b/lib/locomotive/steam/liquid/tags/action.rb +6 -1
@@ @@ -38,7 +38,12 @@ module Locomotive
def render(context)
Locomotive::Common::Logger.info "[action] executing #{@description}"
- service(context).run(super, safe_params(context), context)
+ begin
+ service(context).run(super, safe_params(context), context)
+ rescue Locomotive::Steam::ActionError => e
+ e.action = @description
+ raise e
+ end
''
end
locomotive/steam/liquid/tags/snippet.rb b/lib/locomotive/steam/liquid/tags/snippet.rb +7 -1
@@ @@ -19,7 +19,13 @@ module Locomotive
@template_name = evaluate_snippet_name(context)
# @options doesn't include the page key if cache is on
@options[:page] = context.registers[:page]
- super
+
+ begin
+ super
+ rescue Locomotive::Steam::ParsingRenderingError => e
+ e.file = @template_name + ' [Snippet]'
+ raise e
+ end
end
private
locomotive/steam/liquid/template.rb b/lib/locomotive/steam/liquid/template.rb +3 -1
@@ @@ -21,7 +21,9 @@ module Locomotive
def parse(source, options = {})
template = new
- template.parse(source, options)
+ template.parse(source, options.merge({
+ line_numbers: true
+ }))
end
end
locomotive/steam/middlewares/renderer.rb b/lib/locomotive/steam/middlewares/renderer.rb +6 -1
@@ @@ -37,7 +37,12 @@ module Locomotive::Steam
def parse_and_render_liquid
document = services.liquid_parser.parse(page)
- document.render(liquid_context)
+ begin
+ document.render(liquid_context)
+ rescue Locomotive::Steam::ParsingRenderingError => e
+ e.file = page.template_path if e.file.blank?
+ raise e
+ end
end
def liquid_context
locomotive/steam/services/action_service.rb b/lib/locomotive/steam/services/action_service.rb +6 -5
@@ @@ -36,11 +36,12 @@ module Locomotive
}
JS
- # puts script.inspect # DEBUG
-
- context.exec_string script
-
- context.call_prop('locomotiveAction', site.as_json, params)
+ begin
+ context.exec_string script
+ context.call_prop('locomotiveAction', site.as_json, params)
+ rescue Exception => e
+ raise Locomotive::Steam::ActionError.new(e, script)
+ end
end
private
locomotive/steam/services/liquid_parser_service.rb b/lib/locomotive/steam/services/liquid_parser_service.rb +5 -1
@@ @@ -22,7 +22,11 @@ module Locomotive
def _parse(object, options = {})
# Note: the template must not be parsed here
- Locomotive::Steam::Liquid::Template.parse(object.liquid_source, options)
+ begin
+ Locomotive::Steam::Liquid::Template.parse(object.liquid_source, options)
+ rescue ::Liquid::Error => e
+ raise Locomotive::Steam::RenderError.new(e, object.template_path, object.liquid_source)
+ end
end
end
spec/fixtures/default/app/views/pages/about_us/john_doe.fr.liquid.haml +5 -1
@@ @@ -2,4 +2,8 @@
title: Jean Personne
slug: jean-personne
---
- {% extends parent %}
\ No newline at end of file
+ {% action "fake action" %}
+
+ foo(32);
+
+ {% endaction %}
spec/fixtures/default/app/views/pages/about_us/john_doe.liquid.haml +1 -1
@@ @@ -3,4 +3,4 @@ position: 1
published: true
listed: true
---
- {% extends parent %}
\ No newline at end of file
+ {% for %} <!-- Liquid syntax error -->
spec/integration/server/basic_spec.rb +18 -0
@@ @@ -173,4 +173,22 @@ describe Locomotive::Steam::Server do
end
+ describe 'page with parse or render errors' do
+
+ context 'liquid parsing error' do
+
+ subject { get '/about-us/john-doe'; last_response.body }
+ it { expect { subject }.to raise_error(Locomotive::Steam::RenderError, "Liquid syntax error (line 1): Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]") }
+
+ end
+
+ context 'rendering error' do
+
+ subject { get '/fr/a-notre-sujet/jean-personne'; last_response.body }
+ it { expect { subject }.to raise_error(Locomotive::Steam::ActionError, "identifier 'foo' undefined") }
+
+ end
+
+ end
+
end
spec/unit/errors_spec.rb +2 -2
@@ @@ -1,6 +1,6 @@
require 'spec_helper'
- describe Locomotive::Steam::RenderError do
+ describe Locomotive::Steam::ParsingRenderingError do
let(:message) { 'Wrong syntax' }
let(:file) { 'template.liquid.haml' }
@@ @@ -13,7 +13,7 @@ describe Locomotive::Steam::RenderError do
subject { error.code_lines }
- it { is_expected.to eq [[5, 'f'], [6, 'g'], [7, 'h'], [8, 'i'], [9, 'j'], [10, 'k'], [11, 'l'], [12, 'm'], [13, 'n'], [14, 'o'], [15, 'p']] }
+ it { is_expected.to eq [[5, 'e'], [6, 'f'], [7, 'g'], [8, 'h'], [9, 'i'], [10, 'j'], [11, 'k'], [12, 'l'], [13, 'm'], [14, 'n'], [15, 'o']] }
end
spec/unit/liquid/tags/action_spec.rb +9 -0
@@ @@ -12,6 +12,15 @@ describe Locomotive::Steam::Liquid::Tags::Action do
subject { render_template(source, context) }
+ describe 'parsing' do
+
+ describe 'raises an error if the syntax is incorrect' do
+ let(:source) { '{% action %}{% endaction %}' }
+ it { expect { subject }.to raise_exception(Liquid::SyntaxError) }
+ end
+
+ end
+
describe 'rendering' do
it { is_expected.to eq '' }
spec/unit/liquid/tags/link_to_spec.rb +1 -1
@@ @@ -20,7 +20,7 @@ describe Locomotive::Steam::Liquid::Tags::PathTo do
context 'unknown tag' do
let(:source) { '{% link_to index %}{% endbar %}{% endlink_to %}' }
- it { expect { subject }.to raise_error("Liquid syntax error: Unknown tag 'endbar'") }
+ it { expect { subject }.to raise_error("Liquid syntax error (line 1): Unknown tag 'endbar'") }
end
spec/unit/liquid/tags/paginate_spec.rb +1 -1
@@ @@ -45,7 +45,7 @@ EOF
subject { output }
- it { expect { subject }.to raise_error(::Liquid::ArgumentError, "Liquid error: Cannot paginate 'projects'. Not found.") }
+ it { expect { subject }.to raise_error(::Liquid::ArgumentError, "Liquid error (line 1): Cannot paginate 'projects'. Not found.") }
end
spec/unit/services/action_service_spec.rb +24 -0
@@ @@ -21,6 +21,30 @@ describe Locomotive::Steam::ActionService do
it { is_expected.to eq 2.0 }
+ describe 'deal with exceptions' do
+
+ context 'wrong syntax' do
+
+ let(:script) { 'a +/ b * var;' }
+
+ it 'raises a meaningful exception' do
+ expect { subject }.to raise_error(Locomotive::Steam::ActionError, "eof or line terminator while parsing regexp (line 2)")
+ end
+
+ end
+
+ context 'other error' do
+
+ let(:script) { 'a.b' }
+
+ it 'raises a meaningful exception' do
+ expect { subject }.to raise_error(Locomotive::Steam::ActionError, "identifier 'a' undefined")
+ end
+
+ end
+
+ end
+
describe 'with params' do
let(:params) { { 'foo' => 'hello' } }