mirror of
https://github.com/kemko/liquid.git
synced 2026-01-05 01:35:41 +03:00
Optional line numbers for liquid errors
This commit is contained in:
@@ -66,11 +66,11 @@ require 'liquid/standardfilters'
|
||||
require 'liquid/condition'
|
||||
require 'liquid/module_ex'
|
||||
require 'liquid/utils'
|
||||
require 'liquid/token'
|
||||
|
||||
# Load all the tags of the standard library
|
||||
#
|
||||
Dir[File.dirname(__FILE__) + '/liquid/tags/*.rb'].each { |f| require f }
|
||||
|
||||
require 'liquid/profiler'
|
||||
require 'liquid/profiler/token'
|
||||
require 'liquid/profiler/hooks'
|
||||
|
||||
@@ -144,7 +144,7 @@ module Liquid
|
||||
rescue MemoryError => e
|
||||
raise e
|
||||
rescue ::StandardError => e
|
||||
output << (context.handle_error(e))
|
||||
output << (context.handle_error(e, token))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -91,17 +91,12 @@ module Liquid
|
||||
@interrupts.pop
|
||||
end
|
||||
|
||||
def handle_error(e)
|
||||
|
||||
def handle_error(e, token)
|
||||
e = Liquid::Error.error_with_line_number(e, token)
|
||||
errors.push(e)
|
||||
|
||||
raise if exception_handler && exception_handler.call(e)
|
||||
|
||||
case e
|
||||
when SyntaxError
|
||||
"Liquid syntax error: #{e.message}"
|
||||
else
|
||||
"Liquid error: #{e.message}"
|
||||
end
|
||||
Liquid::Error.render(e)
|
||||
end
|
||||
|
||||
def invoke(method, *args)
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
module Liquid
|
||||
class Error < ::StandardError; end
|
||||
class Error < ::StandardError
|
||||
attr_accessor :line_number
|
||||
|
||||
def self.render(e)
|
||||
msg = if e.is_a?(Liquid::Error) && e.line_number
|
||||
"#{e.line_number}: #{e.message}"
|
||||
else
|
||||
e.message
|
||||
end
|
||||
|
||||
case e
|
||||
when SyntaxError
|
||||
"Liquid syntax error: #{msg}"
|
||||
else
|
||||
"Liquid error: #{msg}"
|
||||
end
|
||||
end
|
||||
|
||||
def self.error_with_line_number(e, token)
|
||||
if e.is_a?(Liquid::Error)
|
||||
e.set_line_number_from_token(token)
|
||||
end
|
||||
|
||||
e
|
||||
end
|
||||
|
||||
def set_line_number_from_token(token)
|
||||
return unless token.respond_to?(:line_number)
|
||||
self.line_number = token.line_number
|
||||
end
|
||||
end
|
||||
|
||||
class ArgumentError < Error; end
|
||||
class ContextError < Error; end
|
||||
|
||||
@@ -104,6 +104,7 @@ module Liquid
|
||||
# Returns self for easy chaining
|
||||
def parse(source, options = {})
|
||||
@profiling = options.delete(:profile)
|
||||
@line_numbers = options.delete(:line_numbers) || @profiling
|
||||
@root = Document.parse(tokenize(source), DEFAULT_OPTIONS.merge(options))
|
||||
@warnings = nil
|
||||
self
|
||||
@@ -196,7 +197,7 @@ module Liquid
|
||||
end
|
||||
result.respond_to?(:join) ? result.join : result
|
||||
rescue Liquid::MemoryError => e
|
||||
context.handle_error(e)
|
||||
context.handle_error(e, nil)
|
||||
ensure
|
||||
@errors = context.errors
|
||||
end
|
||||
@@ -223,7 +224,7 @@ module Liquid
|
||||
end
|
||||
|
||||
def calculate_line_numbers(raw_tokens)
|
||||
return raw_tokens unless @profiling
|
||||
return raw_tokens unless @line_numbers
|
||||
|
||||
current_line = 1
|
||||
raw_tokens.map do |token|
|
||||
@@ -247,6 +248,5 @@ module Liquid
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module Liquid
|
||||
class Token < String
|
||||
|
||||
attr_reader :line_number
|
||||
|
||||
def initialize(content, line_number)
|
||||
@@ -11,6 +10,5 @@ module Liquid
|
||||
def raw
|
||||
"<raw>"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -22,6 +22,39 @@ end
|
||||
class ErrorHandlingTest < Minitest::Test
|
||||
include Liquid
|
||||
|
||||
def test_templates_parsed_with_line_numbers_renders_them_in_errors
|
||||
template = <<-LIQUID
|
||||
Hello,
|
||||
|
||||
{{ errors.standard_error }} will raise a standard error.
|
||||
|
||||
Bla bla test.
|
||||
|
||||
{{ errors.syntax_error }} will raise a syntax error.
|
||||
|
||||
This is an argument error: {{ errors.argument_error }}
|
||||
|
||||
Bla.
|
||||
LIQUID
|
||||
|
||||
expected = <<-TEXT
|
||||
Hello,
|
||||
|
||||
Liquid error: 3: standard error will raise a standard error.
|
||||
|
||||
Bla bla test.
|
||||
|
||||
Liquid syntax error: 7: syntax error will raise a syntax error.
|
||||
|
||||
This is an argument error: Liquid error: 9: argument error
|
||||
|
||||
Bla.
|
||||
TEXT
|
||||
|
||||
output = Liquid::Template.parse(template, line_numbers: true).render('errors' => ErrorDrop.new)
|
||||
assert_equal expected, output
|
||||
end
|
||||
|
||||
def test_standard_error
|
||||
template = Liquid::Template.parse( ' {{ errors.standard_error }} ' )
|
||||
assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
|
||||
@@ -59,7 +92,7 @@ class ErrorHandlingTest < Minitest::Test
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def test_lax_unrecognized_operator
|
||||
template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :lax)
|
||||
assert_equal ' Liquid error: Unknown operator =! ', template.render
|
||||
@@ -91,8 +124,8 @@ class ErrorHandlingTest < Minitest::Test
|
||||
# Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
|
||||
def test_exceptions_propagate
|
||||
assert_raises Exception do
|
||||
template = Liquid::Template.parse( ' {{ errors.exception }} ' )
|
||||
template = Liquid::Template.parse('{{ errors.exception }}')
|
||||
template.render('errors' => ErrorDrop.new)
|
||||
end
|
||||
end
|
||||
end # ErrorHandlingTest
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user