mirror of
https://github.com/kemko/liquid.git
synced 2026-01-03 08:45:42 +03:00
Compare commits
3 Commits
inline-com
...
warning-li
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10173c3315 | ||
|
|
1c1aa4094a | ||
|
|
627ef9e29d |
@@ -54,6 +54,7 @@ require 'liquid/interrupts'
|
|||||||
require 'liquid/strainer'
|
require 'liquid/strainer'
|
||||||
require 'liquid/expression'
|
require 'liquid/expression'
|
||||||
require 'liquid/context'
|
require 'liquid/context'
|
||||||
|
require 'liquid/parser_switching'
|
||||||
require 'liquid/tag'
|
require 'liquid/tag'
|
||||||
require 'liquid/block'
|
require 'liquid/block'
|
||||||
require 'liquid/document'
|
require 'liquid/document'
|
||||||
@@ -66,11 +67,11 @@ require 'liquid/standardfilters'
|
|||||||
require 'liquid/condition'
|
require 'liquid/condition'
|
||||||
require 'liquid/module_ex'
|
require 'liquid/module_ex'
|
||||||
require 'liquid/utils'
|
require 'liquid/utils'
|
||||||
|
require 'liquid/token'
|
||||||
|
|
||||||
# Load all the tags of the standard library
|
# Load all the tags of the standard library
|
||||||
#
|
#
|
||||||
Dir[File.dirname(__FILE__) + '/liquid/tags/*.rb'].each { |f| require f }
|
Dir[File.dirname(__FILE__) + '/liquid/tags/*.rb'].each { |f| require f }
|
||||||
|
|
||||||
require 'liquid/profiler'
|
require 'liquid/profiler'
|
||||||
require 'liquid/profiler/token'
|
|
||||||
require 'liquid/profiler/hooks'
|
require 'liquid/profiler/hooks'
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ module Liquid
|
|||||||
|
|
||||||
# fetch the tag from registered blocks
|
# fetch the tag from registered blocks
|
||||||
if tag = Template.tags[$1]
|
if tag = Template.tags[$1]
|
||||||
new_tag = tag.parse($1, $2, tokens, @options)
|
markup = token.is_a?(Token) ? token.child($2) : $2
|
||||||
|
new_tag = tag.parse($1, markup, tokens, @options)
|
||||||
new_tag.line_number = token.line_number if token.is_a?(Token)
|
new_tag.line_number = token.line_number if token.is_a?(Token)
|
||||||
@blank &&= new_tag.blank?
|
@blank &&= new_tag.blank?
|
||||||
@nodelist << new_tag
|
@nodelist << new_tag
|
||||||
@@ -103,7 +104,8 @@ module Liquid
|
|||||||
|
|
||||||
def create_variable(token)
|
def create_variable(token)
|
||||||
token.scan(ContentOfVariable) do |content|
|
token.scan(ContentOfVariable) do |content|
|
||||||
return Variable.new(content.first, @options)
|
markup = token.is_a?(Token) ? token.child(content.first) : content.first
|
||||||
|
return Variable.new(markup, @options)
|
||||||
end
|
end
|
||||||
raise SyntaxError.new(options[:locale].t("errors.syntax.variable_termination".freeze, :token => token, :tag_end => VariableEnd.inspect))
|
raise SyntaxError.new(options[:locale].t("errors.syntax.variable_termination".freeze, :token => token, :tag_end => VariableEnd.inspect))
|
||||||
end
|
end
|
||||||
@@ -144,7 +146,7 @@ module Liquid
|
|||||||
rescue MemoryError => e
|
rescue MemoryError => e
|
||||||
raise e
|
raise e
|
||||||
rescue ::StandardError => e
|
rescue ::StandardError => e
|
||||||
output << (context.handle_error(e))
|
output << (context.handle_error(e, token))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -91,17 +91,12 @@ module Liquid
|
|||||||
@interrupts.pop
|
@interrupts.pop
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_error(e)
|
|
||||||
|
def handle_error(e, token)
|
||||||
|
e = Liquid::Error.error_with_line_number(e, token)
|
||||||
errors.push(e)
|
errors.push(e)
|
||||||
|
|
||||||
raise if exception_handler && exception_handler.call(e)
|
raise if exception_handler && exception_handler.call(e)
|
||||||
|
Liquid::Error.render(e)
|
||||||
case e
|
|
||||||
when SyntaxError
|
|
||||||
"Liquid syntax error: #{e.message}"
|
|
||||||
else
|
|
||||||
"Liquid error: #{e.message}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def invoke(method, *args)
|
def invoke(method, *args)
|
||||||
|
|||||||
@@ -1,5 +1,35 @@
|
|||||||
module Liquid
|
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 ArgumentError < Error; end
|
||||||
class ContextError < Error; end
|
class ContextError < Error; end
|
||||||
|
|||||||
31
lib/liquid/parser_switching.rb
Normal file
31
lib/liquid/parser_switching.rb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
module Liquid
|
||||||
|
module ParserSwitching
|
||||||
|
def parse_with_selected_parser(markup)
|
||||||
|
case @options[:error_mode] || Template.error_mode
|
||||||
|
when :strict then strict_parse_with_error_context(markup)
|
||||||
|
when :lax then lax_parse(markup)
|
||||||
|
when :warn
|
||||||
|
begin
|
||||||
|
return strict_parse_with_error_context(markup)
|
||||||
|
rescue SyntaxError => e
|
||||||
|
e.line_number = markup.line_number if markup.is_a?(Token)
|
||||||
|
@warnings ||= []
|
||||||
|
@warnings << e
|
||||||
|
return lax_parse(markup)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def strict_parse_with_error_context(markup)
|
||||||
|
strict_parse(markup)
|
||||||
|
rescue SyntaxError => e
|
||||||
|
e.message << markup_context(markup)
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
|
||||||
|
def markup_context(markup)
|
||||||
|
" in \"#{markup.strip}\""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -2,6 +2,7 @@ module Liquid
|
|||||||
class Tag
|
class Tag
|
||||||
attr_accessor :options, :line_number
|
attr_accessor :options, :line_number
|
||||||
attr_reader :nodelist, :warnings
|
attr_reader :nodelist, :warnings
|
||||||
|
include ParserSwitching
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def parse(tag_name, markup, tokens, options)
|
def parse(tag_name, markup, tokens, options)
|
||||||
@@ -37,29 +38,5 @@ module Liquid
|
|||||||
def blank?
|
def blank?
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_with_selected_parser(markup)
|
|
||||||
case @options[:error_mode] || Template.error_mode
|
|
||||||
when :strict then strict_parse_with_error_context(markup)
|
|
||||||
when :lax then lax_parse(markup)
|
|
||||||
when :warn
|
|
||||||
begin
|
|
||||||
return strict_parse_with_error_context(markup)
|
|
||||||
rescue SyntaxError => e
|
|
||||||
@warnings ||= []
|
|
||||||
@warnings << e
|
|
||||||
return lax_parse(markup)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def strict_parse_with_error_context(markup)
|
|
||||||
strict_parse(markup)
|
|
||||||
rescue SyntaxError => e
|
|
||||||
e.message << " in \"#{markup.strip}\""
|
|
||||||
raise e
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ module Liquid
|
|||||||
# Returns self for easy chaining
|
# Returns self for easy chaining
|
||||||
def parse(source, options = {})
|
def parse(source, options = {})
|
||||||
@profiling = options.delete(:profile)
|
@profiling = options.delete(:profile)
|
||||||
|
@line_numbers = options.delete(:line_numbers) || @profiling
|
||||||
@root = Document.parse(tokenize(source), DEFAULT_OPTIONS.merge(options))
|
@root = Document.parse(tokenize(source), DEFAULT_OPTIONS.merge(options))
|
||||||
@warnings = nil
|
@warnings = nil
|
||||||
self
|
self
|
||||||
@@ -196,7 +197,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
result.respond_to?(:join) ? result.join : result
|
result.respond_to?(:join) ? result.join : result
|
||||||
rescue Liquid::MemoryError => e
|
rescue Liquid::MemoryError => e
|
||||||
context.handle_error(e)
|
context.handle_error(e, nil)
|
||||||
ensure
|
ensure
|
||||||
@errors = context.errors
|
@errors = context.errors
|
||||||
end
|
end
|
||||||
@@ -223,7 +224,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def calculate_line_numbers(raw_tokens)
|
def calculate_line_numbers(raw_tokens)
|
||||||
return raw_tokens unless @profiling
|
return raw_tokens unless @line_numbers
|
||||||
|
|
||||||
current_line = 1
|
current_line = 1
|
||||||
raw_tokens.map do |token|
|
raw_tokens.map do |token|
|
||||||
@@ -247,6 +248,5 @@ module Liquid
|
|||||||
yield
|
yield
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
module Liquid
|
module Liquid
|
||||||
class Token < String
|
class Token < String
|
||||||
|
|
||||||
attr_reader :line_number
|
attr_reader :line_number
|
||||||
|
|
||||||
def initialize(content, line_number)
|
def initialize(content, line_number)
|
||||||
@@ -12,5 +11,8 @@ module Liquid
|
|||||||
"<raw>"
|
"<raw>"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def child(string)
|
||||||
|
Token.new(string, @line_number)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -15,30 +15,24 @@ module Liquid
|
|||||||
EasyParse = /\A *(\w+(?:\.\w+)*) *\z/
|
EasyParse = /\A *(\w+(?:\.\w+)*) *\z/
|
||||||
attr_accessor :filters, :name, :warnings
|
attr_accessor :filters, :name, :warnings
|
||||||
attr_accessor :line_number
|
attr_accessor :line_number
|
||||||
|
include ParserSwitching
|
||||||
|
|
||||||
def initialize(markup, options = {})
|
def initialize(markup, options = {})
|
||||||
@markup = markup
|
@markup = markup
|
||||||
@name = nil
|
@name = nil
|
||||||
@options = options || {}
|
@options = options || {}
|
||||||
|
|
||||||
case @options[:error_mode] || Template.error_mode
|
parse_with_selected_parser(markup)
|
||||||
when :strict then strict_parse(markup)
|
|
||||||
when :lax then lax_parse(markup)
|
|
||||||
when :warn
|
|
||||||
begin
|
|
||||||
strict_parse(markup)
|
|
||||||
rescue SyntaxError => e
|
|
||||||
@warnings ||= []
|
|
||||||
@warnings << e
|
|
||||||
lax_parse(markup)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def raw
|
def raw
|
||||||
@markup
|
@markup
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def markup_context(markup)
|
||||||
|
" in \"{{#{markup}}}\""
|
||||||
|
end
|
||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
@filters = []
|
@filters = []
|
||||||
if markup =~ /\s*(#{QuotedFragment})(.*)/om
|
if markup =~ /\s*(#{QuotedFragment})(.*)/om
|
||||||
@@ -74,9 +68,6 @@ module Liquid
|
|||||||
@filters << [filtername, filterargs]
|
@filters << [filtername, filterargs]
|
||||||
end
|
end
|
||||||
p.consume(:end_of_string)
|
p.consume(:end_of_string)
|
||||||
rescue SyntaxError => e
|
|
||||||
e.message << " in \"{{#{markup}}}\""
|
|
||||||
raise e
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_filterargs(p)
|
def parse_filterargs(p)
|
||||||
|
|||||||
@@ -22,6 +22,39 @@ end
|
|||||||
class ErrorHandlingTest < Minitest::Test
|
class ErrorHandlingTest < Minitest::Test
|
||||||
include Liquid
|
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
|
def test_standard_error
|
||||||
template = Liquid::Template.parse( ' {{ errors.standard_error }} ' )
|
template = Liquid::Template.parse( ' {{ errors.standard_error }} ' )
|
||||||
assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
|
assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
|
||||||
@@ -59,7 +92,7 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_lax_unrecognized_operator
|
def test_lax_unrecognized_operator
|
||||||
template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :lax)
|
template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :lax)
|
||||||
assert_equal ' Liquid error: Unknown operator =! ', template.render
|
assert_equal ' Liquid error: Unknown operator =! ', template.render
|
||||||
@@ -88,11 +121,17 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
assert_equal '', template.render
|
assert_equal '', template.render
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_warning_line_numbers
|
||||||
|
template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", :error_mode => :warn, :line_numbers => true)
|
||||||
|
assert_equal 3, template.warnings.size
|
||||||
|
assert_equal [1,2,3], template.warnings.map(&:line_number)
|
||||||
|
end
|
||||||
|
|
||||||
# Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
|
# Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
|
||||||
def test_exceptions_propagate
|
def test_exceptions_propagate
|
||||||
assert_raises Exception do
|
assert_raises Exception do
|
||||||
template = Liquid::Template.parse( ' {{ errors.exception }} ' )
|
template = Liquid::Template.parse('{{ errors.exception }}')
|
||||||
template.render('errors' => ErrorDrop.new)
|
template.render('errors' => ErrorDrop.new)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end # ErrorHandlingTest
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user