From 87b8ee7341772f98854aa90c28c200c5a1e84945 Mon Sep 17 00:00:00 2001 From: Tristan Hume Date: Fri, 26 Jul 2013 11:45:13 -0400 Subject: [PATCH] Add error mode switching --- Rakefile | 4 ++++ lib/liquid/tags/if.rb | 20 ++++++++++++++++++-- lib/liquid/template.rb | 12 ++++++++++++ lib/liquid/variable.rb | 23 +++++++++++++++++++---- performance/benchmark.rb | 1 + test/liquid/error_handling_test.rb | 1 + test/liquid/parsing_quirks_test.rb | 3 +++ 7 files changed, 58 insertions(+), 6 deletions(-) diff --git a/Rakefile b/Rakefile index 862e80f..9bdd344 100755 --- a/Rakefile +++ b/Rakefile @@ -30,6 +30,10 @@ namespace :benchmark do ruby "./performance/benchmark.rb" end + desc "Run the liquid benchmark with lax parsing" + task :lax do + ruby "./performance/benchmark.rb lax" + end end diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb index c5f455a..027620a 100644 --- a/lib/liquid/tags/if.rb +++ b/lib/liquid/tags/if.rb @@ -29,6 +29,7 @@ module Liquid end def render(context) + context.errors += @warnings if @warnings context.stack do @blocks.each do |block| if block.evaluate(context) @@ -52,7 +53,22 @@ module Liquid @nodelist = block.attach(Array.new) end - def old_parse(markup) + def parse_condition(markup) + case Template.error_mode + when :strict then strict_parse(markup) + when :lax then lax_parse(markup) + when :warn + begin + return strict_parse(markup) + rescue SyntaxError => e + @warnings ||= [] + @warnings << e + return lax_parse(markup) + end + end + end + + def lax_parse(markup) expressions = markup.scan(ExpressionsAndOperators).reverse raise(SyntaxError, SyntaxHelp) unless expressions.shift =~ Syntax @@ -71,7 +87,7 @@ module Liquid condition end - def parse_condition(markup) + def strict_parse(markup) p = Parser.new(markup) condition = parse_comparison(p) diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb index 5e0675f..2e3e583 100644 --- a/lib/liquid/template.rb +++ b/lib/liquid/template.rb @@ -34,6 +34,18 @@ module Liquid @tags ||= {} end + # Sets how strict the parser should be. + # :lax acts like liquid 2.5 and silently ignores malformed tags in most cases. + # :warn is the default and will give deprecation warnings when invalid syntax is used. + # :strict will enforce correct syntax. + def error_mode=(mode) + @error_mode = mode + end + + def error_mode + @error_mode || :warn + end + # Pass a module with filter methods which should be available # to all liquid views. Good for registering the standard library def register_filter(mod) diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb index ac0ad72..26db181 100644 --- a/lib/liquid/variable.rb +++ b/lib/liquid/variable.rb @@ -17,11 +17,24 @@ module Liquid def initialize(markup) @markup = markup @name = nil - @filters = [] - parse(markup) + @warning = nil + + + case Template.error_mode + when :strict then strict_parse(markup) + when :lax then lax_parse(markup) + when :warn + begin + strict_parse(markup) + rescue SyntaxError => e + @warning = e + lax_parse(markup) + end + end end - def old_parse(markup) + def lax_parse(markup) + @filters = [] if match = markup.match(/\s*(#{QuotedFragment})(.*)/o) @name = match[1] if match[2].match(/#{FilterSeparator}\s*(.*)/o) @@ -37,7 +50,8 @@ module Liquid end end - def parse(markup) + def strict_parse(markup) + @filters = [] p = Parser.new(markup) # Could be just filters with no input @name = p.look(:pipe) ? '' : p.expression @@ -61,6 +75,7 @@ module Liquid def render(context) return '' if @name.nil? + context.errors << @warning if @warning @filters.inject(context[@name]) do |output, filter| filterargs = [] keyword_args = {} diff --git a/performance/benchmark.rb b/performance/benchmark.rb index afb6ffa..d206c65 100644 --- a/performance/benchmark.rb +++ b/performance/benchmark.rb @@ -2,6 +2,7 @@ require 'rubygems' require 'benchmark' require File.dirname(__FILE__) + '/theme_runner' +Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first profiler = ThemeRunner.new Benchmark.bmbm do |x| diff --git a/test/liquid/error_handling_test.rb b/test/liquid/error_handling_test.rb index 6eb722a..b92660a 100644 --- a/test/liquid/error_handling_test.rb +++ b/test/liquid/error_handling_test.rb @@ -63,6 +63,7 @@ class ErrorHandlingTest < Test::Unit::TestCase end def test_unrecognized_operator + Template.error_mode = :strict assert_raise(SyntaxError) do Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ') end diff --git a/test/liquid/parsing_quirks_test.rb b/test/liquid/parsing_quirks_test.rb index 2ff95ec..cbe8c50 100644 --- a/test/liquid/parsing_quirks_test.rb +++ b/test/liquid/parsing_quirks_test.rb @@ -30,6 +30,7 @@ class ParsingQuirksTest < Test::Unit::TestCase end def test_error_on_empty_filter + Template.error_mode = :strict assert_nothing_raised do Template.parse("{{test}}") Template.parse("{{|test}}") @@ -40,6 +41,7 @@ class ParsingQuirksTest < Test::Unit::TestCase end def test_meaningless_parens + Template.error_mode = :strict assert_raise(SyntaxError) do markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false" Template.parse("{% if #{markup} %} YES {% endif %}") @@ -47,6 +49,7 @@ class ParsingQuirksTest < Test::Unit::TestCase end def test_unexpected_characters_silently_eat_logic + Template.error_mode = :strict assert_raise(SyntaxError) do markup = "true && false" Template.parse("{% if #{markup} %} YES {% endif %}")