diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb index 985a492..c9dbfbd 100644 --- a/lib/liquid/block_body.rb +++ b/lib/liquid/block_body.rb @@ -130,6 +130,26 @@ module Liquid @blank end + # Remove blank strings in the block body for a control flow tag (e.g. `if`, `for`, `case`, `unless`) + # with a blank body. + # + # For example, in a conditional assignment like the following + # + # ``` + # {% if size > max_size %} + # {% assign size = max_size %} + # {% endif %} + # ``` + # + # we assume the intention wasn't to output the blank spaces in the `if` tag's block body, so this method + # will remove them to reduce the render output size. + # + # Note that it is now preferred to use the `liquid` tag for this use case. + def remove_blank_strings + raise "remove_blank_strings only support being called on a blank block body" unless @blank + @nodelist.reject! { |node| node.instance_of?(String) } + end + def render(context) render_to_output_buffer(context, +'') end @@ -143,10 +163,8 @@ module Liquid if node.instance_of?(String) output << node - elsif node.instance_of?(Variable) - render_node(context, output, node) else - render_node(context, node.blank? ? +'' : output, node) + render_node(context, output, node) # If we get an Interrupt that means the block must stop processing. An # Interrupt is any command that stops block execution such as {% break %} # or {% continue %}. These tags may also occur through Block or Include tags. diff --git a/lib/liquid/tags/capture.rb b/lib/liquid/tags/capture.rb index 1cace9c..425032d 100644 --- a/lib/liquid/tags/capture.rb +++ b/lib/liquid/tags/capture.rb @@ -25,10 +25,9 @@ module Liquid end def render_to_output_buffer(context, output) - previous_output_size = output.bytesize - super - context.scopes.last[@to] = output - context.resource_limits.assign_score += (output.bytesize - previous_output_size) + capture_output = render(context) + context.scopes.last[@to] = capture_output + context.resource_limits.assign_score += capture_output.bytesize output end diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb index 30484c6..f6e0e70 100644 --- a/lib/liquid/tags/case.rb +++ b/lib/liquid/tags/case.rb @@ -21,6 +21,9 @@ module Liquid def parse(tokens) body = BlockBody.new body = @blocks.last.attachment while parse_body(body, tokens) + if blank? + @blocks.each { |condition| condition.attachment.remove_blank_strings } + end end def nodelist diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb index 44e0d37..bb03392 100644 --- a/lib/liquid/tags/for.rb +++ b/lib/liquid/tags/for.rb @@ -59,8 +59,13 @@ module Liquid end def parse(tokens) - return unless parse_body(@for_block, tokens) - parse_body(@else_block, tokens) + if parse_body(@for_block, tokens) + parse_body(@else_block, tokens) + end + if blank? + @for_block.remove_blank_strings + @else_block&.remove_blank_strings + end end def nodelist diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb index d0e64c9..43c8b0a 100644 --- a/lib/liquid/tags/if.rb +++ b/lib/liquid/tags/if.rb @@ -31,6 +31,9 @@ module Liquid def parse(tokens) while parse_body(@blocks.last.attachment, tokens) end + if blank? + @blocks.each { |condition| condition.attachment.remove_blank_strings } + end end def unknown_tag(tag, markup, tokens) diff --git a/test/integration/template_test.rb b/test/integration/template_test.rb index 014f951..1c12ff6 100644 --- a/test/integration/template_test.rb +++ b/test/integration/template_test.rb @@ -176,7 +176,7 @@ class TemplateTest < Minitest::Test end def test_resource_limits_hash_in_template_gets_updated_even_if_no_limits_are_set - t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}") + t = Template.parse("{% for a in (1..100) %}x{% assign foo = 1 %} {% endfor %}") t.render! assert(t.resource_limits.assign_score > 0) assert(t.resource_limits.render_score > 0) @@ -215,7 +215,7 @@ class TemplateTest < Minitest::Test def test_default_resource_limits_unaffected_by_render_with_context context = Context.new - t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}") + t = Template.parse("{% for a in (1..100) %}x{% assign foo = 1 %} {% endfor %}") t.render!(context) assert(context.resource_limits.assign_score > 0) assert(context.resource_limits.render_score > 0)