liquid 3.0.6 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
 - data/History.md +243 -58
 - data/README.md +43 -4
 - data/lib/liquid/block.rb +57 -123
 - data/lib/liquid/block_body.rb +217 -85
 - data/lib/liquid/condition.rb +92 -45
 - data/lib/liquid/context.rb +154 -89
 - data/lib/liquid/document.rb +57 -9
 - data/lib/liquid/drop.rb +20 -17
 - data/lib/liquid/errors.rb +27 -29
 - data/lib/liquid/expression.rb +32 -20
 - data/lib/liquid/extensions.rb +21 -7
 - data/lib/liquid/file_system.rb +17 -15
 - data/lib/liquid/forloop_drop.rb +92 -0
 - data/lib/liquid/i18n.rb +10 -8
 - data/lib/liquid/interrupts.rb +4 -3
 - data/lib/liquid/lexer.rb +37 -26
 - data/lib/liquid/locales/en.yml +13 -6
 - data/lib/liquid/parse_context.rb +54 -0
 - data/lib/liquid/parse_tree_visitor.rb +42 -0
 - data/lib/liquid/parser.rb +30 -18
 - data/lib/liquid/parser_switching.rb +20 -6
 - data/lib/liquid/partial_cache.rb +24 -0
 - data/lib/liquid/profiler/hooks.rb +26 -14
 - data/lib/liquid/profiler.rb +72 -92
 - data/lib/liquid/range_lookup.rb +28 -3
 - data/lib/liquid/registers.rb +51 -0
 - data/lib/liquid/resource_limits.rb +62 -0
 - data/lib/liquid/standardfilters.rb +715 -132
 - data/lib/liquid/strainer_factory.rb +41 -0
 - data/lib/liquid/strainer_template.rb +62 -0
 - data/lib/liquid/tablerowloop_drop.rb +121 -0
 - data/lib/liquid/tag/disableable.rb +22 -0
 - data/lib/liquid/tag/disabler.rb +21 -0
 - data/lib/liquid/tag.rb +35 -12
 - data/lib/liquid/tags/assign.rb +57 -18
 - data/lib/liquid/tags/break.rb +15 -5
 - data/lib/liquid/tags/capture.rb +24 -18
 - data/lib/liquid/tags/case.rb +79 -30
 - data/lib/liquid/tags/comment.rb +19 -4
 - data/lib/liquid/tags/continue.rb +16 -12
 - data/lib/liquid/tags/cycle.rb +47 -27
 - data/lib/liquid/tags/decrement.rb +23 -24
 - data/lib/liquid/tags/echo.rb +41 -0
 - data/lib/liquid/tags/for.rb +155 -124
 - data/lib/liquid/tags/if.rb +97 -63
 - data/lib/liquid/tags/ifchanged.rb +11 -12
 - data/lib/liquid/tags/include.rb +82 -73
 - data/lib/liquid/tags/increment.rb +23 -17
 - data/lib/liquid/tags/inline_comment.rb +43 -0
 - data/lib/liquid/tags/raw.rb +50 -8
 - data/lib/liquid/tags/render.rb +109 -0
 - data/lib/liquid/tags/table_row.rb +57 -41
 - data/lib/liquid/tags/unless.rb +38 -20
 - data/lib/liquid/template.rb +71 -103
 - data/lib/liquid/template_factory.rb +9 -0
 - data/lib/liquid/tokenizer.rb +39 -0
 - data/lib/liquid/usage.rb +8 -0
 - data/lib/liquid/utils.rb +63 -9
 - data/lib/liquid/variable.rb +74 -56
 - data/lib/liquid/variable_lookup.rb +31 -15
 - data/lib/liquid/version.rb +3 -1
 - data/lib/liquid.rb +27 -12
 - metadata +30 -106
 - data/lib/liquid/module_ex.rb +0 -62
 - data/lib/liquid/strainer.rb +0 -59
 - data/lib/liquid/token.rb +0 -18
 - data/test/fixtures/en_locale.yml +0 -9
 - data/test/integration/assign_test.rb +0 -48
 - data/test/integration/blank_test.rb +0 -106
 - data/test/integration/capture_test.rb +0 -50
 - data/test/integration/context_test.rb +0 -32
 - data/test/integration/drop_test.rb +0 -271
 - data/test/integration/error_handling_test.rb +0 -207
 - data/test/integration/filter_test.rb +0 -138
 - data/test/integration/hash_ordering_test.rb +0 -23
 - data/test/integration/output_test.rb +0 -124
 - data/test/integration/parsing_quirks_test.rb +0 -116
 - data/test/integration/render_profiling_test.rb +0 -154
 - data/test/integration/security_test.rb +0 -64
 - data/test/integration/standard_filter_test.rb +0 -396
 - data/test/integration/tags/break_tag_test.rb +0 -16
 - data/test/integration/tags/continue_tag_test.rb +0 -16
 - data/test/integration/tags/for_tag_test.rb +0 -375
 - data/test/integration/tags/if_else_tag_test.rb +0 -190
 - data/test/integration/tags/include_tag_test.rb +0 -234
 - data/test/integration/tags/increment_tag_test.rb +0 -24
 - data/test/integration/tags/raw_tag_test.rb +0 -25
 - data/test/integration/tags/standard_tag_test.rb +0 -297
 - data/test/integration/tags/statements_test.rb +0 -113
 - data/test/integration/tags/table_row_test.rb +0 -63
 - data/test/integration/tags/unless_else_tag_test.rb +0 -26
 - data/test/integration/template_test.rb +0 -182
 - data/test/integration/variable_test.rb +0 -82
 - data/test/test_helper.rb +0 -89
 - data/test/unit/block_unit_test.rb +0 -55
 - data/test/unit/condition_unit_test.rb +0 -149
 - data/test/unit/context_unit_test.rb +0 -492
 - data/test/unit/file_system_unit_test.rb +0 -35
 - data/test/unit/i18n_unit_test.rb +0 -37
 - data/test/unit/lexer_unit_test.rb +0 -48
 - data/test/unit/module_ex_unit_test.rb +0 -87
 - data/test/unit/parser_unit_test.rb +0 -82
 - data/test/unit/regexp_unit_test.rb +0 -44
 - data/test/unit/strainer_unit_test.rb +0 -69
 - data/test/unit/tag_unit_test.rb +0 -16
 - data/test/unit/tags/case_tag_unit_test.rb +0 -10
 - data/test/unit/tags/for_tag_unit_test.rb +0 -13
 - data/test/unit/tags/if_tag_unit_test.rb +0 -8
 - data/test/unit/template_unit_test.rb +0 -69
 - data/test/unit/tokenizer_unit_test.rb +0 -38
 - data/test/unit/variable_unit_test.rb +0 -145
 - /data/{MIT-LICENSE → LICENSE} +0 -0
 
    
        data/lib/liquid/block.rb
    CHANGED
    
    | 
         @@ -1,93 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
4 
     | 
    
         
             
              class Block < Tag
         
     | 
| 
       3 
     | 
    
         
            -
                 
     | 
| 
       4 
     | 
    
         
            -
                ContentOfVariable = /\A#{VariableStart}(.*)#{VariableEnd}\z/om
         
     | 
| 
       5 
     | 
    
         
            -
                TAGSTART = "{%".freeze
         
     | 
| 
       6 
     | 
    
         
            -
                VARSTART = "{{".freeze
         
     | 
| 
      
 5 
     | 
    
         
            +
                MAX_DEPTH = 100
         
     | 
| 
       7 
6 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                def  
     | 
| 
       9 
     | 
    
         
            -
                   
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(tag_name, markup, options)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  super
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @blank = true
         
     | 
| 
       10 
10 
     | 
    
         
             
                end
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                def parse(tokens)
         
     | 
| 
       13 
     | 
    
         
            -
                  @ 
     | 
| 
       14 
     | 
    
         
            -
                  @ 
     | 
| 
       15 
     | 
    
         
            -
                  @nodelist.clear
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                  while token = tokens.shift
         
     | 
| 
       18 
     | 
    
         
            -
                    begin
         
     | 
| 
       19 
     | 
    
         
            -
                      unless token.empty?
         
     | 
| 
       20 
     | 
    
         
            -
                        case
         
     | 
| 
       21 
     | 
    
         
            -
                        when token.start_with?(TAGSTART)
         
     | 
| 
       22 
     | 
    
         
            -
                          if token =~ FullToken
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                            # if we found the proper block delimiter just end parsing here and let the outer block
         
     | 
| 
       25 
     | 
    
         
            -
                            # proceed
         
     | 
| 
       26 
     | 
    
         
            -
                            return if block_delimiter == $1
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
                            # fetch the tag from registered blocks
         
     | 
| 
       29 
     | 
    
         
            -
                            if tag = Template.tags[$1]
         
     | 
| 
       30 
     | 
    
         
            -
                              markup = token.is_a?(Token) ? token.child($2) : $2
         
     | 
| 
       31 
     | 
    
         
            -
                              new_tag = tag.parse($1, markup, tokens, @options)
         
     | 
| 
       32 
     | 
    
         
            -
                              new_tag.line_number = token.line_number if token.is_a?(Token)
         
     | 
| 
       33 
     | 
    
         
            -
                              @blank &&= new_tag.blank?
         
     | 
| 
       34 
     | 
    
         
            -
                              @nodelist << new_tag
         
     | 
| 
       35 
     | 
    
         
            -
                            else
         
     | 
| 
       36 
     | 
    
         
            -
                              # this tag is not registered with the system
         
     | 
| 
       37 
     | 
    
         
            -
                              # pass it to the current block for special handling or error reporting
         
     | 
| 
       38 
     | 
    
         
            -
                              unknown_tag($1, $2, tokens)
         
     | 
| 
       39 
     | 
    
         
            -
                            end
         
     | 
| 
       40 
     | 
    
         
            -
                          else
         
     | 
| 
       41 
     | 
    
         
            -
                            raise SyntaxError.new(options[:locale].t("errors.syntax.tag_termination".freeze, :token => token, :tag_end => TagEnd.inspect))
         
     | 
| 
       42 
     | 
    
         
            -
                          end
         
     | 
| 
       43 
     | 
    
         
            -
                        when token.start_with?(VARSTART)
         
     | 
| 
       44 
     | 
    
         
            -
                          new_var = create_variable(token)
         
     | 
| 
       45 
     | 
    
         
            -
                          new_var.line_number = token.line_number if token.is_a?(Token)
         
     | 
| 
       46 
     | 
    
         
            -
                          @nodelist << new_var
         
     | 
| 
       47 
     | 
    
         
            -
                          @blank = false
         
     | 
| 
       48 
     | 
    
         
            -
                        else
         
     | 
| 
       49 
     | 
    
         
            -
                          @nodelist << token
         
     | 
| 
       50 
     | 
    
         
            -
                          @blank &&= (token =~ /\A\s*\z/)
         
     | 
| 
       51 
     | 
    
         
            -
                        end
         
     | 
| 
       52 
     | 
    
         
            -
                      end
         
     | 
| 
       53 
     | 
    
         
            -
                    rescue SyntaxError => e
         
     | 
| 
       54 
     | 
    
         
            -
                      e.set_line_number_from_token(token)
         
     | 
| 
       55 
     | 
    
         
            -
                      raise
         
     | 
| 
       56 
     | 
    
         
            -
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @body = new_body
         
     | 
| 
      
 14 
     | 
    
         
            +
                  while parse_body(@body, tokens)
         
     | 
| 
       57 
15 
     | 
    
         
             
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @body.freeze
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
       58 
18 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
                   
     | 
| 
       62 
     | 
    
         
            -
                  assert_missing_delimitation!
         
     | 
| 
      
 19 
     | 
    
         
            +
                # For backwards compatibility
         
     | 
| 
      
 20 
     | 
    
         
            +
                def render(context)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @body.render(context)
         
     | 
| 
       63 
22 
     | 
    
         
             
                end
         
     | 
| 
       64 
23 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
                 
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                  all_warnings.concat(@warnings) if @warnings
         
     | 
| 
      
 24 
     | 
    
         
            +
                def blank?
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @blank
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
       69 
27 
     | 
    
         | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
                def nodelist
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @body.nodelist
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
       73 
31 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
      
 32 
     | 
    
         
            +
                def unknown_tag(tag_name, _markup, _tokenizer)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  Block.raise_unknown_tag(tag_name, block_name, block_delimiter, parse_context)
         
     | 
| 
       75 
34 
     | 
    
         
             
                end
         
     | 
| 
       76 
35 
     | 
    
         | 
| 
       77 
     | 
    
         
            -
                 
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
                   
     | 
| 
       80 
     | 
    
         
            -
                    raise SyntaxError. 
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                   
     | 
| 
       83 
     | 
    
         
            -
                    raise SyntaxError. 
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
      
 36 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 37 
     | 
    
         
            +
                def self.raise_unknown_tag(tag, block_name, block_delimiter, parse_context)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  if tag == 'else'
         
     | 
| 
      
 39 
     | 
    
         
            +
                    raise SyntaxError, parse_context.locale.t("errors.syntax.unexpected_else",
         
     | 
| 
      
 40 
     | 
    
         
            +
                      block_name: block_name)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  elsif tag.start_with?('end')
         
     | 
| 
      
 42 
     | 
    
         
            +
                    raise SyntaxError, parse_context.locale.t("errors.syntax.invalid_delimiter",
         
     | 
| 
      
 43 
     | 
    
         
            +
                      tag: tag,
         
     | 
| 
      
 44 
     | 
    
         
            +
                      block_name: block_name,
         
     | 
| 
      
 45 
     | 
    
         
            +
                      block_delimiter: block_delimiter)
         
     | 
| 
       86 
46 
     | 
    
         
             
                  else
         
     | 
| 
       87 
     | 
    
         
            -
                    raise SyntaxError. 
     | 
| 
      
 47 
     | 
    
         
            +
                    raise SyntaxError, parse_context.locale.t("errors.syntax.unknown_tag", tag: tag)
         
     | 
| 
       88 
48 
     | 
    
         
             
                  end
         
     | 
| 
       89 
49 
     | 
    
         
             
                end
         
     | 
| 
       90 
50 
     | 
    
         | 
| 
      
 51 
     | 
    
         
            +
                def raise_tag_never_closed(block_name)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  raise SyntaxError, parse_context.locale.t("errors.syntax.tag_never_closed", block_name: block_name)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
       91 
55 
     | 
    
         
             
                def block_name
         
     | 
| 
       92 
56 
     | 
    
         
             
                  @tag_name
         
     | 
| 
       93 
57 
     | 
    
         
             
                end
         
     | 
| 
         @@ -96,65 +60,35 @@ module Liquid 
     | 
|
| 
       96 
60 
     | 
    
         
             
                  @block_delimiter ||= "end#{block_name}"
         
     | 
| 
       97 
61 
     | 
    
         
             
                end
         
     | 
| 
       98 
62 
     | 
    
         | 
| 
       99 
     | 
    
         
            -
                 
     | 
| 
       100 
     | 
    
         
            -
                  token.scan(ContentOfVariable) do |content|
         
     | 
| 
       101 
     | 
    
         
            -
                    markup = token.is_a?(Token) ? token.child(content.first) : content.first
         
     | 
| 
       102 
     | 
    
         
            -
                    return Variable.new(markup, @options)
         
     | 
| 
       103 
     | 
    
         
            -
                  end
         
     | 
| 
       104 
     | 
    
         
            -
                  raise SyntaxError.new(options[:locale].t("errors.syntax.variable_termination".freeze, :token => token, :tag_end => VariableEnd.inspect))
         
     | 
| 
       105 
     | 
    
         
            -
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
                private
         
     | 
| 
       106 
64 
     | 
    
         | 
| 
       107 
     | 
    
         
            -
                 
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
                # @api public
         
     | 
| 
      
 66 
     | 
    
         
            +
                def new_body
         
     | 
| 
      
 67 
     | 
    
         
            +
                  parse_context.new_block_body
         
     | 
| 
       109 
68 
     | 
    
         
             
                end
         
     | 
| 
       110 
69 
     | 
    
         | 
| 
       111 
     | 
    
         
            -
                 
     | 
| 
      
 70 
     | 
    
         
            +
                # @api public
         
     | 
| 
      
 71 
     | 
    
         
            +
                def parse_body(body, tokens)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  if parse_context.depth >= MAX_DEPTH
         
     | 
| 
      
 73 
     | 
    
         
            +
                    raise StackLevelError, "Nesting too deep"
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                  parse_context.depth += 1
         
     | 
| 
      
 76 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 77 
     | 
    
         
            +
                    body.parse(tokens, parse_context) do |end_tag_name, end_tag_params|
         
     | 
| 
      
 78 
     | 
    
         
            +
                      @blank &&= body.blank?
         
     | 
| 
       112 
79 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
                      return false if end_tag_name == block_delimiter
         
     | 
| 
      
 81 
     | 
    
         
            +
                      raise_tag_never_closed(block_name) unless end_tag_name
         
     | 
| 
       116 
82 
     | 
    
         | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
                  context.resource_limits[:render_score_current] += list.length
         
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
     | 
    
         
            -
                  list.each do |token|
         
     | 
| 
       123 
     | 
    
         
            -
                    # Break out if we have any unhanded interrupts.
         
     | 
| 
       124 
     | 
    
         
            -
                    break if context.has_interrupt?
         
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
                    begin
         
     | 
| 
       127 
     | 
    
         
            -
                      # If we get an Interrupt that means the block must stop processing. An
         
     | 
| 
       128 
     | 
    
         
            -
                      # Interrupt is any command that stops block execution such as {% break %}
         
     | 
| 
       129 
     | 
    
         
            -
                      # or {% continue %}
         
     | 
| 
       130 
     | 
    
         
            -
                      if token.is_a? Continue or token.is_a? Break
         
     | 
| 
       131 
     | 
    
         
            -
                        context.push_interrupt(token.interrupt)
         
     | 
| 
       132 
     | 
    
         
            -
                        break
         
     | 
| 
       133 
     | 
    
         
            -
                      end
         
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
                      token_output = render_token(token, context)
         
     | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
       137 
     | 
    
         
            -
                      unless token.is_a?(Block) && token.blank?
         
     | 
| 
       138 
     | 
    
         
            -
                        output << token_output
         
     | 
| 
       139 
     | 
    
         
            -
                      end
         
     | 
| 
       140 
     | 
    
         
            -
                    rescue MemoryError => e
         
     | 
| 
       141 
     | 
    
         
            -
                      raise e
         
     | 
| 
       142 
     | 
    
         
            -
                    rescue ::StandardError => e
         
     | 
| 
       143 
     | 
    
         
            -
                      output << (context.handle_error(e, token))
         
     | 
| 
      
 83 
     | 
    
         
            +
                      # this tag is not registered with the system
         
     | 
| 
      
 84 
     | 
    
         
            +
                      # pass it to the current block for special handling or error reporting
         
     | 
| 
      
 85 
     | 
    
         
            +
                      unknown_tag(end_tag_name, end_tag_params, tokens)
         
     | 
| 
       144 
86 
     | 
    
         
             
                    end
         
     | 
| 
      
 87 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 88 
     | 
    
         
            +
                    parse_context.depth -= 1
         
     | 
| 
       145 
89 
     | 
    
         
             
                  end
         
     | 
| 
       146 
90 
     | 
    
         | 
| 
       147 
     | 
    
         
            -
                   
     | 
| 
       148 
     | 
    
         
            -
                end
         
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
                def render_token(token, context)
         
     | 
| 
       151 
     | 
    
         
            -
                  token_output = (token.respond_to?(:render) ? token.render(context) : token)
         
     | 
| 
       152 
     | 
    
         
            -
                  context.increment_used_resources(:render_length_current, token_output)
         
     | 
| 
       153 
     | 
    
         
            -
                  if context.resource_limits_reached?
         
     | 
| 
       154 
     | 
    
         
            -
                    context.resource_limits[:reached] = true
         
     | 
| 
       155 
     | 
    
         
            -
                    raise MemoryError.new("Memory limits exceeded".freeze)
         
     | 
| 
       156 
     | 
    
         
            -
                  end
         
     | 
| 
       157 
     | 
    
         
            -
                  token_output
         
     | 
| 
      
 91 
     | 
    
         
            +
                  true
         
     | 
| 
       158 
92 
     | 
    
         
             
                end
         
     | 
| 
       159 
93 
     | 
    
         
             
              end
         
     | 
| 
       160 
94 
     | 
    
         
             
            end
         
     | 
    
        data/lib/liquid/block_body.rb
    CHANGED
    
    | 
         @@ -1,123 +1,255 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'English'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       1 
5 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
6 
     | 
    
         
             
              class BlockBody
         
     | 
| 
       3 
     | 
    
         
            -
                 
     | 
| 
       4 
     | 
    
         
            -
                 
     | 
| 
       5 
     | 
    
         
            -
                 
     | 
| 
       6 
     | 
    
         
            -
                 
     | 
| 
      
 7 
     | 
    
         
            +
                LiquidTagToken      = /\A\s*(#{TagName})\s*(.*?)\z/o
         
     | 
| 
      
 8 
     | 
    
         
            +
                FullToken           = /\A#{TagStart}#{WhitespaceControl}?(\s*)(#{TagName})(\s*)(.*?)#{WhitespaceControl}?#{TagEnd}\z/om
         
     | 
| 
      
 9 
     | 
    
         
            +
                ContentOfVariable   = /\A#{VariableStart}#{WhitespaceControl}?(.*?)#{WhitespaceControl}?#{VariableEnd}\z/om
         
     | 
| 
      
 10 
     | 
    
         
            +
                WhitespaceOrNothing = /\A\s*\z/
         
     | 
| 
      
 11 
     | 
    
         
            +
                TAGSTART            = "{%"
         
     | 
| 
      
 12 
     | 
    
         
            +
                VARSTART            = "{{"
         
     | 
| 
       7 
13 
     | 
    
         | 
| 
       8 
14 
     | 
    
         
             
                attr_reader :nodelist
         
     | 
| 
       9 
15 
     | 
    
         | 
| 
       10 
16 
     | 
    
         
             
                def initialize
         
     | 
| 
       11 
17 
     | 
    
         
             
                  @nodelist = []
         
     | 
| 
       12 
     | 
    
         
            -
                  @blank 
     | 
| 
       13 
     | 
    
         
            -
                end
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                def parse( 
     | 
| 
       16 
     | 
    
         
            -
                   
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
                         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
                          @blank &&= !!(token =~ /\A\s*\z/)
         
     | 
| 
       47 
     | 
    
         
            -
                        end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @blank    = true
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def parse(tokenizer, parse_context, &block)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  raise FrozenError, "can't modify frozen Liquid::BlockBody" if frozen?
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  parse_context.line_number = tokenizer.line_number
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  if tokenizer.for_liquid_tag
         
     | 
| 
      
 27 
     | 
    
         
            +
                    parse_for_liquid_tag(tokenizer, parse_context, &block)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  else
         
     | 
| 
      
 29 
     | 
    
         
            +
                    parse_for_document(tokenizer, parse_context, &block)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def freeze
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @nodelist.freeze
         
     | 
| 
      
 35 
     | 
    
         
            +
                  super
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                private def parse_for_liquid_tag(tokenizer, parse_context)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  while (token = tokenizer.shift)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    unless token.empty? || token.match?(WhitespaceOrNothing)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      unless token =~ LiquidTagToken
         
     | 
| 
      
 42 
     | 
    
         
            +
                        # line isn't empty but didn't match tag syntax, yield and let the
         
     | 
| 
      
 43 
     | 
    
         
            +
                        # caller raise a syntax error
         
     | 
| 
      
 44 
     | 
    
         
            +
                        return yield token, token
         
     | 
| 
      
 45 
     | 
    
         
            +
                      end
         
     | 
| 
      
 46 
     | 
    
         
            +
                      tag_name = Regexp.last_match(1)
         
     | 
| 
      
 47 
     | 
    
         
            +
                      markup   = Regexp.last_match(2)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      unless (tag = registered_tags[tag_name])
         
     | 
| 
      
 49 
     | 
    
         
            +
                        # end parsing if we reach an unknown tag and let the caller decide
         
     | 
| 
      
 50 
     | 
    
         
            +
                        # determine how to proceed
         
     | 
| 
      
 51 
     | 
    
         
            +
                        return yield tag_name, markup
         
     | 
| 
       48 
52 
     | 
    
         
             
                      end
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
                       
     | 
| 
       51 
     | 
    
         
            -
                       
     | 
| 
      
 53 
     | 
    
         
            +
                      new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      @blank &&= new_tag.blank?
         
     | 
| 
      
 55 
     | 
    
         
            +
                      @nodelist << new_tag
         
     | 
| 
       52 
56 
     | 
    
         
             
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
                    parse_context.line_number = tokenizer.line_number
         
     | 
| 
       53 
58 
     | 
    
         
             
                  end
         
     | 
| 
       54 
59 
     | 
    
         | 
| 
       55 
60 
     | 
    
         
             
                  yield nil, nil
         
     | 
| 
       56 
61 
     | 
    
         
             
                end
         
     | 
| 
       57 
62 
     | 
    
         | 
| 
       58 
     | 
    
         
            -
                 
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
      
 63 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 64 
     | 
    
         
            +
                def self.unknown_tag_in_liquid_tag(tag, parse_context)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  Block.raise_unknown_tag(tag, 'liquid', '%}', parse_context)
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 69 
     | 
    
         
            +
                def self.raise_missing_tag_terminator(token, parse_context)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  raise SyntaxError, parse_context.locale.t("errors.syntax.tag_termination", token: token, tag_end: TagEnd.inspect)
         
     | 
| 
       60 
71 
     | 
    
         
             
                end
         
     | 
| 
       61 
72 
     | 
    
         | 
| 
       62 
     | 
    
         
            -
                 
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
                   
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
      
 73 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 74 
     | 
    
         
            +
                def self.raise_missing_variable_terminator(token, parse_context)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  raise SyntaxError, parse_context.locale.t("errors.syntax.variable_termination", token: token, tag_end: VariableEnd.inspect)
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 79 
     | 
    
         
            +
                def self.render_node(context, output, node)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  node.render_to_output_buffer(context, output)
         
     | 
| 
      
 81 
     | 
    
         
            +
                rescue => exc
         
     | 
| 
      
 82 
     | 
    
         
            +
                  blank_tag = !node.instance_of?(Variable) && node.blank?
         
     | 
| 
      
 83 
     | 
    
         
            +
                  rescue_render_node(context, output, node.line_number, exc, blank_tag)
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 87 
     | 
    
         
            +
                def self.rescue_render_node(context, output, line_number, exc, blank_tag)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  case exc
         
     | 
| 
      
 89 
     | 
    
         
            +
                  when MemoryError
         
     | 
| 
      
 90 
     | 
    
         
            +
                    raise
         
     | 
| 
      
 91 
     | 
    
         
            +
                  when UndefinedVariable, UndefinedDropMethod, UndefinedFilter
         
     | 
| 
      
 92 
     | 
    
         
            +
                    context.handle_error(exc, line_number)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  else
         
     | 
| 
      
 94 
     | 
    
         
            +
                    error_message = context.handle_error(exc, line_number)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    unless blank_tag # conditional for backwards compatibility
         
     | 
| 
      
 96 
     | 
    
         
            +
                      output << error_message
         
     | 
| 
      
 97 
     | 
    
         
            +
                    end
         
     | 
| 
       66 
98 
     | 
    
         
             
                  end
         
     | 
| 
       67 
     | 
    
         
            -
                  all_warnings
         
     | 
| 
       68 
99 
     | 
    
         
             
                end
         
     | 
| 
       69 
100 
     | 
    
         | 
| 
       70 
     | 
    
         
            -
                def  
     | 
| 
       71 
     | 
    
         
            -
                   
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                   
     | 
| 
      
 101 
     | 
    
         
            +
                private def parse_liquid_tag(markup, parse_context)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  liquid_tag_tokenizer = parse_context.new_tokenizer(
         
     | 
| 
      
 103 
     | 
    
         
            +
                    markup, start_line_number: parse_context.line_number, for_liquid_tag: true
         
     | 
| 
      
 104 
     | 
    
         
            +
                  )
         
     | 
| 
      
 105 
     | 
    
         
            +
                  parse_for_liquid_tag(liquid_tag_tokenizer, parse_context) do |end_tag_name, _end_tag_markup|
         
     | 
| 
      
 106 
     | 
    
         
            +
                    if end_tag_name
         
     | 
| 
      
 107 
     | 
    
         
            +
                      BlockBody.unknown_tag_in_liquid_tag(end_tag_name, parse_context)
         
     | 
| 
      
 108 
     | 
    
         
            +
                    end
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
       74 
111 
     | 
    
         | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
                     
     | 
| 
      
 112 
     | 
    
         
            +
                private def parse_for_document(tokenizer, parse_context)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  while (token = tokenizer.shift)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    next if token.empty?
         
     | 
| 
      
 115 
     | 
    
         
            +
                    case
         
     | 
| 
      
 116 
     | 
    
         
            +
                    when token.start_with?(TAGSTART)
         
     | 
| 
      
 117 
     | 
    
         
            +
                      whitespace_handler(token, parse_context)
         
     | 
| 
      
 118 
     | 
    
         
            +
                      unless token =~ FullToken
         
     | 
| 
      
 119 
     | 
    
         
            +
                        BlockBody.raise_missing_tag_terminator(token, parse_context)
         
     | 
| 
      
 120 
     | 
    
         
            +
                      end
         
     | 
| 
      
 121 
     | 
    
         
            +
                      tag_name = Regexp.last_match(2)
         
     | 
| 
      
 122 
     | 
    
         
            +
                      markup   = Regexp.last_match(4)
         
     | 
| 
       78 
123 
     | 
    
         | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                       
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
      
 124 
     | 
    
         
            +
                      if parse_context.line_number
         
     | 
| 
      
 125 
     | 
    
         
            +
                        # newlines inside the tag should increase the line number,
         
     | 
| 
      
 126 
     | 
    
         
            +
                        # particularly important for multiline {% liquid %} tags
         
     | 
| 
      
 127 
     | 
    
         
            +
                        parse_context.line_number += Regexp.last_match(1).count("\n") + Regexp.last_match(3).count("\n")
         
     | 
| 
      
 128 
     | 
    
         
            +
                      end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                      if tag_name == 'liquid'
         
     | 
| 
      
 131 
     | 
    
         
            +
                        parse_liquid_tag(markup, parse_context)
         
     | 
| 
      
 132 
     | 
    
         
            +
                        next
         
     | 
| 
      
 133 
     | 
    
         
            +
                      end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                      unless (tag = registered_tags[tag_name])
         
     | 
| 
      
 136 
     | 
    
         
            +
                        # end parsing if we reach an unknown tag and let the caller decide
         
     | 
| 
      
 137 
     | 
    
         
            +
                        # determine how to proceed
         
     | 
| 
      
 138 
     | 
    
         
            +
                        return yield tag_name, markup
         
     | 
| 
      
 139 
     | 
    
         
            +
                      end
         
     | 
| 
      
 140 
     | 
    
         
            +
                      new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
         
     | 
| 
      
 141 
     | 
    
         
            +
                      @blank &&= new_tag.blank?
         
     | 
| 
      
 142 
     | 
    
         
            +
                      @nodelist << new_tag
         
     | 
| 
      
 143 
     | 
    
         
            +
                    when token.start_with?(VARSTART)
         
     | 
| 
      
 144 
     | 
    
         
            +
                      whitespace_handler(token, parse_context)
         
     | 
| 
      
 145 
     | 
    
         
            +
                      @nodelist << create_variable(token, parse_context)
         
     | 
| 
      
 146 
     | 
    
         
            +
                      @blank = false
         
     | 
| 
      
 147 
     | 
    
         
            +
                    else
         
     | 
| 
      
 148 
     | 
    
         
            +
                      if parse_context.trim_whitespace
         
     | 
| 
      
 149 
     | 
    
         
            +
                        token.lstrip!
         
     | 
| 
       86 
150 
     | 
    
         
             
                      end
         
     | 
| 
      
 151 
     | 
    
         
            +
                      parse_context.trim_whitespace = false
         
     | 
| 
      
 152 
     | 
    
         
            +
                      @nodelist << token
         
     | 
| 
      
 153 
     | 
    
         
            +
                      @blank &&= token.match?(WhitespaceOrNothing)
         
     | 
| 
      
 154 
     | 
    
         
            +
                    end
         
     | 
| 
      
 155 
     | 
    
         
            +
                    parse_context.line_number = tokenizer.line_number
         
     | 
| 
      
 156 
     | 
    
         
            +
                  end
         
     | 
| 
       87 
157 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
      
 158 
     | 
    
         
            +
                  yield nil, nil
         
     | 
| 
      
 159 
     | 
    
         
            +
                end
         
     | 
| 
       89 
160 
     | 
    
         | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
      
 161 
     | 
    
         
            +
                def whitespace_handler(token, parse_context)
         
     | 
| 
      
 162 
     | 
    
         
            +
                  if token[2] == WhitespaceControl
         
     | 
| 
      
 163 
     | 
    
         
            +
                    previous_token = @nodelist.last
         
     | 
| 
      
 164 
     | 
    
         
            +
                    if previous_token.is_a?(String)
         
     | 
| 
      
 165 
     | 
    
         
            +
                      first_byte = previous_token.getbyte(0)
         
     | 
| 
      
 166 
     | 
    
         
            +
                      previous_token.rstrip!
         
     | 
| 
      
 167 
     | 
    
         
            +
                      if previous_token.empty? && parse_context[:bug_compatible_whitespace_trimming] && first_byte
         
     | 
| 
      
 168 
     | 
    
         
            +
                        previous_token << first_byte
         
     | 
| 
       92 
169 
     | 
    
         
             
                      end
         
     | 
| 
       93 
     | 
    
         
            -
                    rescue MemoryError => e
         
     | 
| 
       94 
     | 
    
         
            -
                      raise e
         
     | 
| 
       95 
     | 
    
         
            -
                    rescue ::StandardError => e
         
     | 
| 
       96 
     | 
    
         
            -
                      output << context.handle_error(e, token)
         
     | 
| 
       97 
170 
     | 
    
         
             
                    end
         
     | 
| 
       98 
171 
     | 
    
         
             
                  end
         
     | 
| 
      
 172 
     | 
    
         
            +
                  parse_context.trim_whitespace = (token[-3] == WhitespaceControl)
         
     | 
| 
      
 173 
     | 
    
         
            +
                end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                def blank?
         
     | 
| 
      
 176 
     | 
    
         
            +
                  @blank
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
       99 
178 
     | 
    
         | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
      
 179 
     | 
    
         
            +
                # Remove blank strings in the block body for a control flow tag (e.g. `if`, `for`, `case`, `unless`)
         
     | 
| 
      
 180 
     | 
    
         
            +
                # with a blank body.
         
     | 
| 
      
 181 
     | 
    
         
            +
                #
         
     | 
| 
      
 182 
     | 
    
         
            +
                # For example, in a conditional assignment like the following
         
     | 
| 
      
 183 
     | 
    
         
            +
                #
         
     | 
| 
      
 184 
     | 
    
         
            +
                # ```
         
     | 
| 
      
 185 
     | 
    
         
            +
                # {% if size > max_size %}
         
     | 
| 
      
 186 
     | 
    
         
            +
                #   {% assign size = max_size %}
         
     | 
| 
      
 187 
     | 
    
         
            +
                # {% endif %}
         
     | 
| 
      
 188 
     | 
    
         
            +
                # ```
         
     | 
| 
      
 189 
     | 
    
         
            +
                #
         
     | 
| 
      
 190 
     | 
    
         
            +
                # we assume the intention wasn't to output the blank spaces in the `if` tag's block body, so this method
         
     | 
| 
      
 191 
     | 
    
         
            +
                # will remove them to reduce the render output size.
         
     | 
| 
      
 192 
     | 
    
         
            +
                #
         
     | 
| 
      
 193 
     | 
    
         
            +
                # Note that it is now preferred to use the `liquid` tag for this use case.
         
     | 
| 
      
 194 
     | 
    
         
            +
                def remove_blank_strings
         
     | 
| 
      
 195 
     | 
    
         
            +
                  raise "remove_blank_strings only support being called on a blank block body" unless @blank
         
     | 
| 
      
 196 
     | 
    
         
            +
                  @nodelist.reject! { |node| node.instance_of?(String) }
         
     | 
| 
       101 
197 
     | 
    
         
             
                end
         
     | 
| 
       102 
198 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
                 
     | 
| 
      
 199 
     | 
    
         
            +
                def render(context)
         
     | 
| 
      
 200 
     | 
    
         
            +
                  render_to_output_buffer(context, +'')
         
     | 
| 
      
 201 
     | 
    
         
            +
                end
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                def render_to_output_buffer(context, output)
         
     | 
| 
      
 204 
     | 
    
         
            +
                  freeze unless frozen?
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                  context.resource_limits.increment_render_score(@nodelist.length)
         
     | 
| 
       104 
207 
     | 
    
         | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
                   
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
                     
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
      
 208 
     | 
    
         
            +
                  idx = 0
         
     | 
| 
      
 209 
     | 
    
         
            +
                  while (node = @nodelist[idx])
         
     | 
| 
      
 210 
     | 
    
         
            +
                    if node.instance_of?(String)
         
     | 
| 
      
 211 
     | 
    
         
            +
                      output << node
         
     | 
| 
      
 212 
     | 
    
         
            +
                    else
         
     | 
| 
      
 213 
     | 
    
         
            +
                      render_node(context, output, node)
         
     | 
| 
      
 214 
     | 
    
         
            +
                      # If we get an Interrupt that means the block must stop processing. An
         
     | 
| 
      
 215 
     | 
    
         
            +
                      # Interrupt is any command that stops block execution such as {% break %}
         
     | 
| 
      
 216 
     | 
    
         
            +
                      # or {% continue %}. These tags may also occur through Block or Include tags.
         
     | 
| 
      
 217 
     | 
    
         
            +
                      break if context.interrupt? # might have happened in a for-block
         
     | 
| 
      
 218 
     | 
    
         
            +
                    end
         
     | 
| 
      
 219 
     | 
    
         
            +
                    idx += 1
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                    context.resource_limits.increment_write_score(output)
         
     | 
| 
       111 
222 
     | 
    
         
             
                  end
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                  output
         
     | 
| 
       113 
225 
     | 
    
         
             
                end
         
     | 
| 
       114 
226 
     | 
    
         | 
| 
       115 
     | 
    
         
            -
                 
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
      
 227 
     | 
    
         
            +
                private
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
                def render_node(context, output, node)
         
     | 
| 
      
 230 
     | 
    
         
            +
                  BlockBody.render_node(context, output, node)
         
     | 
| 
      
 231 
     | 
    
         
            +
                end
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                def create_variable(token, parse_context)
         
     | 
| 
      
 234 
     | 
    
         
            +
                  if token =~ ContentOfVariable
         
     | 
| 
      
 235 
     | 
    
         
            +
                    markup = Regexp.last_match(1)
         
     | 
| 
      
 236 
     | 
    
         
            +
                    return Variable.new(markup, parse_context)
         
     | 
| 
       119 
237 
     | 
    
         
             
                  end
         
     | 
| 
       120 
     | 
    
         
            -
                   
     | 
| 
      
 238 
     | 
    
         
            +
                  BlockBody.raise_missing_variable_terminator(token, parse_context)
         
     | 
| 
      
 239 
     | 
    
         
            +
                end
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                # @deprecated Use {.raise_missing_tag_terminator} instead
         
     | 
| 
      
 242 
     | 
    
         
            +
                def raise_missing_tag_terminator(token, parse_context)
         
     | 
| 
      
 243 
     | 
    
         
            +
                  BlockBody.raise_missing_tag_terminator(token, parse_context)
         
     | 
| 
      
 244 
     | 
    
         
            +
                end
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
                # @deprecated Use {.raise_missing_variable_terminator} instead
         
     | 
| 
      
 247 
     | 
    
         
            +
                def raise_missing_variable_terminator(token, parse_context)
         
     | 
| 
      
 248 
     | 
    
         
            +
                  BlockBody.raise_missing_variable_terminator(token, parse_context)
         
     | 
| 
      
 249 
     | 
    
         
            +
                end
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                def registered_tags
         
     | 
| 
      
 252 
     | 
    
         
            +
                  Template.tags
         
     | 
| 
       121 
253 
     | 
    
         
             
                end
         
     | 
| 
       122 
254 
     | 
    
         
             
              end
         
     | 
| 
       123 
255 
     | 
    
         
             
            end
         
     |