mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-19 10:52:48 -07:00
Merge pull request #1005 from christopheraue/render_refactor
Refactored and optimized rendering
This commit is contained in:
+33
-29
@@ -70,33 +70,27 @@ module Liquid
|
|||||||
output = []
|
output = []
|
||||||
context.resource_limits.render_score += @nodelist.length
|
context.resource_limits.render_score += @nodelist.length
|
||||||
|
|
||||||
@nodelist.each do |token|
|
idx = 0
|
||||||
# Break out if we have any unhanded interrupts.
|
while node = @nodelist[idx]
|
||||||
break if context.interrupt?
|
case node
|
||||||
|
when String
|
||||||
begin
|
check_resources(context, node)
|
||||||
|
output << node
|
||||||
|
when Variable
|
||||||
|
render_node_to_output(node, output, context)
|
||||||
|
when Block
|
||||||
|
render_node_to_output(node, output, context, node.blank?)
|
||||||
|
break if context.interrupt? # might have happened in a for-block
|
||||||
|
when Continue, Break
|
||||||
# If we get an Interrupt that means the block must stop processing. An
|
# If we get an Interrupt that means the block must stop processing. An
|
||||||
# Interrupt is any command that stops block execution such as {% break %}
|
# Interrupt is any command that stops block execution such as {% break %}
|
||||||
# or {% continue %}
|
# or {% continue %}
|
||||||
if token.is_a?(Continue) || token.is_a?(Break)
|
context.push_interrupt(node.interrupt)
|
||||||
context.push_interrupt(token.interrupt)
|
break
|
||||||
break
|
else # Other non-Block tags
|
||||||
end
|
render_node_to_output(node, output, context)
|
||||||
|
|
||||||
node_output = render_node(token, context)
|
|
||||||
|
|
||||||
unless token.is_a?(Block) && token.blank?
|
|
||||||
output << node_output
|
|
||||||
end
|
|
||||||
rescue MemoryError => e
|
|
||||||
raise e
|
|
||||||
rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e
|
|
||||||
context.handle_error(e, token.line_number)
|
|
||||||
output << nil
|
|
||||||
rescue ::StandardError => e
|
|
||||||
line_number = token.is_a?(String) ? nil : token.line_number
|
|
||||||
output << context.handle_error(e, line_number)
|
|
||||||
end
|
end
|
||||||
|
idx += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
output.join
|
output.join
|
||||||
@@ -104,15 +98,25 @@ module Liquid
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def render_node(node, context)
|
def render_node_to_output(node, output, context, skip_output = false)
|
||||||
node_output = node.is_a?(String) ? node : node.render(context)
|
node_output = node.render(context)
|
||||||
node_output = node_output.is_a?(Array) ? node_output.join : node_output.to_s
|
node_output = node_output.is_a?(Array) ? node_output.join : node_output.to_s
|
||||||
|
check_resources(context, node_output)
|
||||||
|
output << node_output unless skip_output
|
||||||
|
rescue MemoryError => e
|
||||||
|
raise e
|
||||||
|
rescue UndefinedVariable, UndefinedDropMethod, UndefinedFilter => e
|
||||||
|
context.handle_error(e, node.line_number)
|
||||||
|
output << nil
|
||||||
|
rescue ::StandardError => e
|
||||||
|
line_number = node.is_a?(String) ? nil : node.line_number
|
||||||
|
output << context.handle_error(e, line_number)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_resources(context, node_output)
|
||||||
context.resource_limits.render_length += node_output.length
|
context.resource_limits.render_length += node_output.length
|
||||||
if context.resource_limits.reached?
|
return unless context.resource_limits.reached?
|
||||||
raise MemoryError.new("Memory limits exceeded".freeze)
|
raise MemoryError.new("Memory limits exceeded".freeze)
|
||||||
end
|
|
||||||
node_output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_variable(token, parse_context)
|
def create_variable(token, parse_context)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
module Liquid
|
module Liquid
|
||||||
class BlockBody
|
class BlockBody
|
||||||
def render_node_with_profiling(node, context)
|
def render_node_with_profiling(node, output, context, skip_output = false)
|
||||||
Profiler.profile_node_render(node) do
|
Profiler.profile_node_render(node) do
|
||||||
render_node_without_profiling(node, context)
|
render_node_without_profiling(node, output, context, skip_output)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :render_node_without_profiling, :render_node
|
alias_method :render_node_without_profiling, :render_node_to_output
|
||||||
alias_method :render_node, :render_node_with_profiling
|
alias_method :render_node_to_output, :render_node_with_profiling
|
||||||
end
|
end
|
||||||
|
|
||||||
class Include < Tag
|
class Include < Tag
|
||||||
|
|||||||
Reference in New Issue
Block a user