Compare commits

...

4 Commits

Author SHA1 Message Date
Dylan Thacker-Smith
8daaad3b76 Make error locations available for non-Liquid::Error exceptions. 2015-05-21 19:03:17 -04:00
Dylan Thacker-Smith
d36c6822da Include template name with line numbers in render errors. 2015-05-21 16:50:05 -04:00
Dylan Thacker-Smith
3d87d9ab1e Raise Liquid::ZeroDivisionError instead of ZeroDivisionError. 2015-05-21 12:18:58 -04:00
Dylan Thacker-Smith
71ff1f283a Make liquid rendering optional.
Although the author of the liquid template wants to see these errors, they
probably don't want the visitor to see the liquid errors.  Probably the
best fallback when rendering the page for visitors is to render the empty
string for tags with errors.
2015-05-21 10:49:32 -04:00
6 changed files with 51 additions and 25 deletions

View File

@@ -50,6 +50,7 @@ require 'liquid/i18n'
require 'liquid/drop' require 'liquid/drop'
require 'liquid/extensions' require 'liquid/extensions'
require 'liquid/errors' require 'liquid/errors'
require 'liquid/error_location'
require 'liquid/interrupts' require 'liquid/interrupts'
require 'liquid/strainer' require 'liquid/strainer'
require 'liquid/expression' require 'liquid/expression'

View File

@@ -12,16 +12,18 @@ module Liquid
# #
# context['bob'] #=> nil class Context # context['bob'] #=> nil class Context
class Context class Context
attr_reader :scopes, :errors, :registers, :environments, :resource_limits attr_reader :scopes, :errors, :error_locations, :registers, :environments, :resource_limits
attr_accessor :exception_handler attr_accessor :exception_handler, :render_errors, :template_name
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil) def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, render_errors = true)
@environments = [environments].flatten @environments = [environments].flatten
@scopes = [(outer_scope || {})] @scopes = [(outer_scope || {})]
@registers = registers @registers = registers
@errors = [] @errors = []
@error_locations = []
@resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits) @resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits)
squash_instance_assigns_with_environments squash_instance_assigns_with_environments
@render_errors = render_errors
@this_stack_used = false @this_stack_used = false
@@ -64,12 +66,14 @@ module Liquid
def handle_error(e, token = nil) def handle_error(e, token = nil)
if e.is_a?(Liquid::Error) if e.is_a?(Liquid::Error)
e.template_name = template_name
e.set_line_number_from_token(token) e.set_line_number_from_token(token)
end end
errors.push(e) errors.push(e)
error_locations.push(ErrorLocation.from_token(template_name, token))
raise if exception_handler && exception_handler.call(e) raise if exception_handler && exception_handler.call(e)
Liquid::Error.render(e) render_errors ? Liquid::Error.render(e) : ''
end end
def invoke(method, *args) def invoke(method, *args)

View File

@@ -0,0 +1,11 @@
module Liquid
ErrorLocation = Struct.new(:template_name, :line_number) do
def self.line_number_from_token(token)
token.respond_to?(:line_number) ? token.line_number : nil
end
def self.from_token(template_name, token)
new(template_name, line_number_from_token(token))
end
end
end

View File

@@ -1,6 +1,7 @@
module Liquid module Liquid
class Error < ::StandardError class Error < ::StandardError
attr_accessor :line_number attr_accessor :line_number
attr_accessor :template_name
attr_accessor :markup_context attr_accessor :markup_context
def to_s(with_prefix = true) def to_s(with_prefix = true)
@@ -17,9 +18,8 @@ module Liquid
end end
def set_line_number_from_token(token) def set_line_number_from_token(token)
return unless token.respond_to?(:line_number)
return if line_number return if line_number
self.line_number = token.line_number self.line_number = ErrorLocation.line_number_from_token(token)
end end
def self.render(e) def self.render(e)
@@ -41,7 +41,9 @@ module Liquid
end end
if line_number if line_number
str << " (line #{line_number})" str << " ("
str << template_name << " " if template_name
str << "line " << line_number.to_s << ")"
end end
str << ": " str << ": "

View File

@@ -41,9 +41,9 @@ module Liquid
end end
def render(context) def render(context)
partial = load_cached_partial(context)
template_name = context.evaluate(@template_name_expr) template_name = context.evaluate(@template_name_expr)
partial = load_cached_partial(template_name, context)
context_variable_name = template_name.split('/'.freeze).last context_variable_name = template_name.split('/'.freeze).last
variable = if @variable_name_expr variable = if @variable_name_expr
@@ -52,28 +52,33 @@ module Liquid
context.find_variable(template_name) context.find_variable(template_name)
end end
context.stack do old_template_name = context.template_name
@attributes.each do |key, value| begin
context[key] = context.evaluate(value) context.template_name = template_name
end context.stack do
@attributes.each do |key, value|
context[key] = context.evaluate(value)
end
if variable.is_a?(Array) if variable.is_a?(Array)
variable.collect do |var| variable.collect do |var|
context[context_variable_name] = var context[context_variable_name] = var
partial.render(context)
end
else
context[context_variable_name] = variable
partial.render(context) partial.render(context)
end end
else
context[context_variable_name] = variable
partial.render(context)
end end
ensure
context.template_name = old_template_name
end end
end end
private private
def load_cached_partial(context) def load_cached_partial(template_name, context)
cached_partials = context.registers[:cached_partials] || {} cached_partials = context.registers[:cached_partials] || {}
template_name = context.evaluate(@template_name_expr)
if cached = cached_partials[template_name] if cached = cached_partials[template_name]
return cached return cached

View File

@@ -17,7 +17,7 @@ module Liquid
locale: I18n.new locale: I18n.new
} }
attr_accessor :root attr_accessor :root, :render_errors
attr_reader :resource_limits attr_reader :resource_limits
@@file_system = BlankFileSystem.new @@file_system = BlankFileSystem.new
@@ -112,6 +112,7 @@ module Liquid
def initialize def initialize
@resource_limits = ResourceLimits.new(self.class.default_resource_limits) @resource_limits = ResourceLimits.new(self.class.default_resource_limits)
@render_errors = true
end end
# Parse source code. # Parse source code.
@@ -163,6 +164,8 @@ module Liquid
def render(*args) def render(*args)
return ''.freeze if @root.nil? return ''.freeze if @root.nil?
render_errors = self.render_errors
context = case args.first context = case args.first
when Liquid::Context when Liquid::Context
c = args.shift c = args.shift
@@ -174,11 +177,11 @@ module Liquid
c c
when Liquid::Drop when Liquid::Drop
drop = args.shift drop = args.shift
drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits) drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits, render_errors)
when Hash when Hash
Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits) Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits, render_errors)
when nil when nil
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits) Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits, render_errors)
else else
raise ArgumentError, "Expected Hash or Liquid::Context as parameter" raise ArgumentError, "Expected Hash or Liquid::Context as parameter"
end end