diff --git a/History.md b/History.md index 9e18adec..cbe5ef45 100644 --- a/History.md +++ b/History.md @@ -3,6 +3,7 @@ ## 3.0.0 / not yet released / branch "master" * ... +* Add exception_handler feature, see #397 and #254 [Bogdan Gusiev, bogdan and Florian Weingarten, fw42] * Optimize variable parsing to avoid repeated regex evaluation during template rendering #383 [Jason Hiltz-Laforge, jasonhl] * Optimize checking for block interrupts to reduce object allocation #380 [Jason Hiltz-Laforge, jasonhl] * Properly set context rethrow_errors on render! #349 [Thierry Joyal, tjoyal] diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb index 4e74f56d..d3b063c5 100644 --- a/lib/liquid/context.rb +++ b/lib/liquid/context.rb @@ -14,8 +14,7 @@ module Liquid # context['bob'] #=> nil class Context class Context attr_reader :scopes, :errors, :registers, :environments, :resource_limits - - attr_accessor :rethrow_errors + attr_accessor :exception_handler SQUARE_BRACKETED = /\A\[(.*)\]\z/m @@ -24,10 +23,13 @@ module Liquid @scopes = [(outer_scope || {})] @registers = registers @errors = [] - @rethrow_errors = rethrow_errors @resource_limits = (resource_limits || {}).merge!({ :render_score_current => 0, :assign_score_current => 0 }) squash_instance_assigns_with_environments + if rethrow_errors + self.exception_handler = ->(e) { true } + end + @interrupts = [] @filters = [] @parsed_variables = Hash.new{ |cache, markup| cache[markup] = variable_parse(markup) } @@ -91,7 +93,8 @@ module Liquid def handle_error(e) errors.push(e) - raise if @rethrow_errors + + raise if exception_handler && exception_handler.call(e) case e when SyntaxError @@ -300,5 +303,4 @@ module Liquid end end # squash_instance_assigns_with_environments end # Context - end # Liquid diff --git a/lib/liquid/template.rb b/lib/liquid/template.rb index 34172dbb..e2a0c45a 100644 --- a/lib/liquid/template.rb +++ b/lib/liquid/template.rb @@ -142,7 +142,11 @@ module Liquid context = case args.first when Liquid::Context c = args.shift - c.rethrow_errors = true if @rethrow_errors + + if @rethrow_errors + c.exception_handler = ->(e) { true } + end + c when Liquid::Drop drop = args.shift @@ -167,6 +171,9 @@ module Liquid context.add_filters(options[:filters]) end + if options[:exception_handler] + context.exception_handler = options[:exception_handler] + end when Module context.add_filters(args.pop) when Array diff --git a/test/integration/template_test.rb b/test/integration/template_test.rb index 54c1d422..20adf8c1 100644 --- a/test/integration/template_test.rb +++ b/test/integration/template_test.rb @@ -153,4 +153,18 @@ class TemplateTest < Test::Unit::TestCase end assert_equal 'ruby error in drop', e.message end + + def test_exception_handler_doesnt_reraise_if_it_returns_false + exception = nil + Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_handler: ->(e) { exception = e; false }) + assert exception.is_a?(ZeroDivisionError) + end + + def test_exception_handler_does_reraise_if_it_returns_true + exception = nil + assert_raises(ZeroDivisionError) do + Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_handler: ->(e) { exception = e; true }) + end + assert exception.is_a?(ZeroDivisionError) + end end