liquid 3.0.0 → 4.0.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 +4 -4
 - data/History.md +130 -62
 - data/README.md +31 -0
 - data/lib/liquid/block.rb +31 -124
 - data/lib/liquid/block_body.rb +75 -59
 - data/lib/liquid/condition.rb +23 -22
 - data/lib/liquid/context.rb +51 -60
 - data/lib/liquid/document.rb +19 -9
 - data/lib/liquid/drop.rb +17 -16
 - data/lib/liquid/errors.rb +20 -24
 - data/lib/liquid/expression.rb +15 -3
 - data/lib/liquid/extensions.rb +13 -7
 - data/lib/liquid/file_system.rb +11 -11
 - data/lib/liquid/forloop_drop.rb +42 -0
 - data/lib/liquid/i18n.rb +5 -5
 - data/lib/liquid/interrupts.rb +1 -2
 - data/lib/liquid/lexer.rb +6 -4
 - data/lib/liquid/locales/en.yml +5 -1
 - data/lib/liquid/parse_context.rb +37 -0
 - data/lib/liquid/parser.rb +1 -1
 - data/lib/liquid/parser_switching.rb +4 -4
 - data/lib/liquid/profiler/hooks.rb +7 -7
 - data/lib/liquid/profiler.rb +18 -19
 - data/lib/liquid/range_lookup.rb +16 -1
 - data/lib/liquid/resource_limits.rb +23 -0
 - data/lib/liquid/standardfilters.rb +121 -61
 - data/lib/liquid/strainer.rb +32 -29
 - data/lib/liquid/tablerowloop_drop.rb +62 -0
 - data/lib/liquid/tag.rb +9 -8
 - data/lib/liquid/tags/assign.rb +17 -4
 - data/lib/liquid/tags/break.rb +0 -3
 - data/lib/liquid/tags/capture.rb +2 -2
 - data/lib/liquid/tags/case.rb +19 -12
 - data/lib/liquid/tags/comment.rb +2 -2
 - data/lib/liquid/tags/cycle.rb +6 -6
 - data/lib/liquid/tags/decrement.rb +1 -4
 - data/lib/liquid/tags/for.rb +95 -75
 - data/lib/liquid/tags/if.rb +48 -43
 - data/lib/liquid/tags/ifchanged.rb +0 -2
 - data/lib/liquid/tags/include.rb +61 -52
 - data/lib/liquid/tags/raw.rb +32 -4
 - data/lib/liquid/tags/table_row.rb +12 -31
 - data/lib/liquid/tags/unless.rb +4 -5
 - data/lib/liquid/template.rb +42 -54
 - data/lib/liquid/tokenizer.rb +31 -0
 - data/lib/liquid/utils.rb +52 -8
 - data/lib/liquid/variable.rb +46 -45
 - data/lib/liquid/variable_lookup.rb +9 -5
 - data/lib/liquid/version.rb +1 -1
 - data/lib/liquid.rb +9 -7
 - data/test/integration/assign_test.rb +18 -8
 - data/test/integration/blank_test.rb +14 -14
 - data/test/integration/capture_test.rb +10 -0
 - data/test/integration/context_test.rb +2 -2
 - data/test/integration/document_test.rb +19 -0
 - data/test/integration/drop_test.rb +42 -40
 - data/test/integration/error_handling_test.rb +99 -46
 - data/test/integration/filter_test.rb +72 -19
 - data/test/integration/hash_ordering_test.rb +9 -9
 - data/test/integration/output_test.rb +34 -27
 - data/test/integration/parsing_quirks_test.rb +15 -13
 - data/test/integration/render_profiling_test.rb +20 -20
 - data/test/integration/security_test.rb +9 -7
 - data/test/integration/standard_filter_test.rb +198 -42
 - data/test/integration/tags/break_tag_test.rb +1 -2
 - data/test/integration/tags/continue_tag_test.rb +0 -1
 - data/test/integration/tags/for_tag_test.rb +133 -98
 - data/test/integration/tags/if_else_tag_test.rb +96 -77
 - data/test/integration/tags/include_tag_test.rb +34 -30
 - data/test/integration/tags/increment_tag_test.rb +10 -11
 - data/test/integration/tags/raw_tag_test.rb +7 -1
 - data/test/integration/tags/standard_tag_test.rb +121 -122
 - data/test/integration/tags/statements_test.rb +3 -5
 - data/test/integration/tags/table_row_test.rb +20 -19
 - data/test/integration/tags/unless_else_tag_test.rb +6 -6
 - data/test/integration/template_test.rb +190 -49
 - data/test/integration/trim_mode_test.rb +525 -0
 - data/test/integration/variable_test.rb +23 -13
 - data/test/test_helper.rb +44 -9
 - data/test/unit/block_unit_test.rb +8 -5
 - data/test/unit/condition_unit_test.rb +86 -77
 - data/test/unit/context_unit_test.rb +48 -57
 - data/test/unit/file_system_unit_test.rb +3 -3
 - data/test/unit/i18n_unit_test.rb +2 -2
 - data/test/unit/lexer_unit_test.rb +11 -8
 - data/test/unit/parser_unit_test.rb +2 -2
 - data/test/unit/regexp_unit_test.rb +1 -1
 - data/test/unit/strainer_unit_test.rb +85 -8
 - data/test/unit/tag_unit_test.rb +7 -2
 - data/test/unit/tags/case_tag_unit_test.rb +1 -1
 - data/test/unit/tags/for_tag_unit_test.rb +2 -2
 - data/test/unit/tags/if_tag_unit_test.rb +1 -1
 - data/test/unit/template_unit_test.rb +14 -5
 - data/test/unit/tokenizer_unit_test.rb +24 -7
 - data/test/unit/variable_unit_test.rb +66 -43
 - metadata +55 -50
 - data/lib/liquid/module_ex.rb +0 -62
 - data/lib/liquid/token.rb +0 -18
 - data/test/unit/module_ex_unit_test.rb +0 -87
 - /data/{MIT-LICENSE → LICENSE} +0 -0
 
| 
         @@ -6,10 +6,10 @@ module Liquid 
     | 
|
| 
       6 
6 
     | 
    
         
             
                  super
         
     | 
| 
       7 
7 
     | 
    
         
             
                  if markup =~ Syntax
         
     | 
| 
       8 
8 
     | 
    
         
             
                    @variable_name = $1
         
     | 
| 
       9 
     | 
    
         
            -
                    @collection_name = $2
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @collection_name = Expression.parse($2)
         
     | 
| 
       10 
10 
     | 
    
         
             
                    @attributes = {}
         
     | 
| 
       11 
11 
     | 
    
         
             
                    markup.scan(TagAttributes) do |key, value|
         
     | 
| 
       12 
     | 
    
         
            -
                      @attributes[key] = value
         
     | 
| 
      
 12 
     | 
    
         
            +
                      @attributes[key] = Expression.parse(value)
         
     | 
| 
       13 
13 
     | 
    
         
             
                    end
         
     | 
| 
       14 
14 
     | 
    
         
             
                  else
         
     | 
| 
       15 
15 
     | 
    
         
             
                    raise SyntaxError.new(options[:locale].t("errors.syntax.table_row".freeze))
         
     | 
| 
         @@ -17,51 +17,32 @@ module Liquid 
     | 
|
| 
       17 
17 
     | 
    
         
             
                end
         
     | 
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
                def render(context)
         
     | 
| 
       20 
     | 
    
         
            -
                  collection = context 
     | 
| 
      
 20 
     | 
    
         
            +
                  collection = context.evaluate(@collection_name) or return ''.freeze
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
                  from = @attributes 
     | 
| 
       23 
     | 
    
         
            -
                  to = @attributes 
     | 
| 
      
 22 
     | 
    
         
            +
                  from = @attributes.key?('offset'.freeze) ? context.evaluate(@attributes['offset'.freeze]).to_i : 0
         
     | 
| 
      
 23 
     | 
    
         
            +
                  to = @attributes.key?('limit'.freeze) ? from + context.evaluate(@attributes['limit'.freeze]).to_i : nil
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                  collection = Utils.slice_collection(collection, from, to)
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                  length = collection.length
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                  cols = context 
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                  row = 1
         
     | 
| 
       32 
     | 
    
         
            -
                  col = 0
         
     | 
| 
      
 29 
     | 
    
         
            +
                  cols = context.evaluate(@attributes['cols'.freeze]).to_i
         
     | 
| 
       33 
30 
     | 
    
         | 
| 
       34 
31 
     | 
    
         
             
                  result = "<tr class=\"row1\">\n"
         
     | 
| 
       35 
32 
     | 
    
         
             
                  context.stack do
         
     | 
| 
      
 33 
     | 
    
         
            +
                    tablerowloop = Liquid::TablerowloopDrop.new(length, cols)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    context['tablerowloop'.freeze] = tablerowloop
         
     | 
| 
       36 
35 
     | 
    
         | 
| 
       37 
36 
     | 
    
         
             
                    collection.each_with_index do |item, index|
         
     | 
| 
       38 
37 
     | 
    
         
             
                      context[@variable_name] = item
         
     | 
| 
       39 
     | 
    
         
            -
                      context['tablerowloop'.freeze] = {
         
     | 
| 
       40 
     | 
    
         
            -
                        'length'.freeze    => length,
         
     | 
| 
       41 
     | 
    
         
            -
                        'index'.freeze     => index + 1,
         
     | 
| 
       42 
     | 
    
         
            -
                        'index0'.freeze    => index,
         
     | 
| 
       43 
     | 
    
         
            -
                        'col'.freeze       => col + 1,
         
     | 
| 
       44 
     | 
    
         
            -
                        'col0'.freeze      => col,
         
     | 
| 
       45 
     | 
    
         
            -
                        'index0'.freeze    => index,
         
     | 
| 
       46 
     | 
    
         
            -
                        'rindex'.freeze    => length - index,
         
     | 
| 
       47 
     | 
    
         
            -
                        'rindex0'.freeze   => length - index - 1,
         
     | 
| 
       48 
     | 
    
         
            -
                        'first'.freeze     => (index == 0),
         
     | 
| 
       49 
     | 
    
         
            -
                        'last'.freeze      => (index == length - 1),
         
     | 
| 
       50 
     | 
    
         
            -
                        'col_first'.freeze => (col == 0),
         
     | 
| 
       51 
     | 
    
         
            -
                        'col_last'.freeze  => (col == cols - 1)
         
     | 
| 
       52 
     | 
    
         
            -
                      }
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                      col += 1
         
     | 
| 
       56 
38 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
                      result << "<td class=\"col#{col}\">" << super << '</td>'
         
     | 
| 
      
 39 
     | 
    
         
            +
                      result << "<td class=\"col#{tablerowloop.col}\">" << super << '</td>'
         
     | 
| 
       58 
40 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
                      if  
     | 
| 
       60 
     | 
    
         
            -
                         
     | 
| 
       61 
     | 
    
         
            -
                        row += 1
         
     | 
| 
       62 
     | 
    
         
            -
                        result << "</tr>\n<tr class=\"row#{row}\">"
         
     | 
| 
      
 41 
     | 
    
         
            +
                      if tablerowloop.col_last && !tablerowloop.last
         
     | 
| 
      
 42 
     | 
    
         
            +
                        result << "</tr>\n<tr class=\"row#{tablerowloop.row + 1}\">"
         
     | 
| 
       63 
43 
     | 
    
         
             
                      end
         
     | 
| 
       64 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
                      tablerowloop.send(:increment!)
         
     | 
| 
       65 
46 
     | 
    
         
             
                    end
         
     | 
| 
       66 
47 
     | 
    
         
             
                  end
         
     | 
| 
       67 
48 
     | 
    
         
             
                  result << "</tr>\n"
         
     | 
    
        data/lib/liquid/tags/unless.rb
    CHANGED
    
    | 
         @@ -1,24 +1,23 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            require_relative 'if'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
       4 
4 
     | 
    
         
             
              # Unless is a conditional just like 'if' but works on the inverse logic.
         
     | 
| 
       5 
5 
     | 
    
         
             
              #
         
     | 
| 
       6 
     | 
    
         
            -
              #   {% unless x < 0 %} x is greater than zero {%  
     | 
| 
      
 6 
     | 
    
         
            +
              #   {% unless x < 0 %} x is greater than zero {% endunless %}
         
     | 
| 
       7 
7 
     | 
    
         
             
              #
         
     | 
| 
       8 
8 
     | 
    
         
             
              class Unless < If
         
     | 
| 
       9 
9 
     | 
    
         
             
                def render(context)
         
     | 
| 
       10 
10 
     | 
    
         
             
                  context.stack do
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
11 
     | 
    
         
             
                    # First condition is interpreted backwards ( if not )
         
     | 
| 
       13 
12 
     | 
    
         
             
                    first_block = @blocks.first
         
     | 
| 
       14 
13 
     | 
    
         
             
                    unless first_block.evaluate(context)
         
     | 
| 
       15 
     | 
    
         
            -
                      return  
     | 
| 
      
 14 
     | 
    
         
            +
                      return first_block.attachment.render(context)
         
     | 
| 
       16 
15 
     | 
    
         
             
                    end
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
       18 
17 
     | 
    
         
             
                    # After the first condition unless works just like if
         
     | 
| 
       19 
18 
     | 
    
         
             
                    @blocks[1..-1].each do |block|
         
     | 
| 
       20 
19 
     | 
    
         
             
                      if block.evaluate(context)
         
     | 
| 
       21 
     | 
    
         
            -
                        return  
     | 
| 
      
 20 
     | 
    
         
            +
                        return block.attachment.render(context)
         
     | 
| 
       22 
21 
     | 
    
         
             
                      end
         
     | 
| 
       23 
22 
     | 
    
         
             
                    end
         
     | 
| 
       24 
23 
     | 
    
         | 
    
        data/lib/liquid/template.rb
    CHANGED
    
    | 
         @@ -1,5 +1,4 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
2 
     | 
    
         
             
              # Templates are central to liquid.
         
     | 
| 
       4 
3 
     | 
    
         
             
              # Interpretating templates is a two step process. First you compile the
         
     | 
| 
       5 
4 
     | 
    
         
             
              # source code you got. During compile time some extensive error checking is performed.
         
     | 
| 
         @@ -14,21 +13,21 @@ module Liquid 
     | 
|
| 
       14 
13 
     | 
    
         
             
              #   template.render('user_name' => 'bob')
         
     | 
| 
       15 
14 
     | 
    
         
             
              #
         
     | 
| 
       16 
15 
     | 
    
         
             
              class Template
         
     | 
| 
       17 
     | 
    
         
            -
                 
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
                }
         
     | 
| 
      
 16 
     | 
    
         
            +
                attr_accessor :root
         
     | 
| 
      
 17 
     | 
    
         
            +
                attr_reader :resource_limits, :warnings
         
     | 
| 
       20 
18 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                attr_accessor :root, :resource_limits
         
     | 
| 
       22 
19 
     | 
    
         
             
                @@file_system = BlankFileSystem.new
         
     | 
| 
       23 
20 
     | 
    
         | 
| 
       24 
21 
     | 
    
         
             
                class TagRegistry
         
     | 
| 
      
 22 
     | 
    
         
            +
                  include Enumerable
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
       25 
24 
     | 
    
         
             
                  def initialize
         
     | 
| 
       26 
     | 
    
         
            -
                    @tags 
     | 
| 
      
 25 
     | 
    
         
            +
                    @tags = {}
         
     | 
| 
       27 
26 
     | 
    
         
             
                    @cache = {}
         
     | 
| 
       28 
27 
     | 
    
         
             
                  end
         
     | 
| 
       29 
28 
     | 
    
         | 
| 
       30 
29 
     | 
    
         
             
                  def [](tag_name)
         
     | 
| 
       31 
     | 
    
         
            -
                    return nil unless @tags. 
     | 
| 
      
 30 
     | 
    
         
            +
                    return nil unless @tags.key?(tag_name)
         
     | 
| 
       32 
31 
     | 
    
         
             
                    return @cache[tag_name] if Liquid.cache_classes
         
     | 
| 
       33 
32 
     | 
    
         | 
| 
       34 
33 
     | 
    
         
             
                    lookup_class(@tags[tag_name]).tap { |o| @cache[tag_name] = o }
         
     | 
| 
         @@ -44,6 +43,10 @@ module Liquid 
     | 
|
| 
       44 
43 
     | 
    
         
             
                    @cache.delete(tag_name)
         
     | 
| 
       45 
44 
     | 
    
         
             
                  end
         
     | 
| 
       46 
45 
     | 
    
         | 
| 
      
 46 
     | 
    
         
            +
                  def each(&block)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @tags.each(&block)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
       47 
50 
     | 
    
         
             
                  private
         
     | 
| 
       48 
51 
     | 
    
         | 
| 
       49 
52 
     | 
    
         
             
                  def lookup_class(name)
         
     | 
| 
         @@ -66,6 +69,11 @@ module Liquid 
     | 
|
| 
       66 
69 
     | 
    
         
             
                  # :error raises an error when tainted output is used
         
     | 
| 
       67 
70 
     | 
    
         
             
                  attr_writer :taint_mode
         
     | 
| 
       68 
71 
     | 
    
         | 
| 
      
 72 
     | 
    
         
            +
                  attr_accessor :default_exception_renderer
         
     | 
| 
      
 73 
     | 
    
         
            +
                  Template.default_exception_renderer = lambda do |exception|
         
     | 
| 
      
 74 
     | 
    
         
            +
                    exception
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
       69 
77 
     | 
    
         
             
                  def file_system
         
     | 
| 
       70 
78 
     | 
    
         
             
                    @@file_system
         
     | 
| 
       71 
79 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -83,11 +91,11 @@ module Liquid 
     | 
|
| 
       83 
91 
     | 
    
         
             
                  end
         
     | 
| 
       84 
92 
     | 
    
         | 
| 
       85 
93 
     | 
    
         
             
                  def error_mode
         
     | 
| 
       86 
     | 
    
         
            -
                    @error_mode  
     | 
| 
      
 94 
     | 
    
         
            +
                    @error_mode ||= :lax
         
     | 
| 
       87 
95 
     | 
    
         
             
                  end
         
     | 
| 
       88 
96 
     | 
    
         | 
| 
       89 
97 
     | 
    
         
             
                  def taint_mode
         
     | 
| 
       90 
     | 
    
         
            -
                    @taint_mode  
     | 
| 
      
 98 
     | 
    
         
            +
                    @taint_mode ||= :lax
         
     | 
| 
       91 
99 
     | 
    
         
             
                  end
         
     | 
| 
       92 
100 
     | 
    
         | 
| 
       93 
101 
     | 
    
         
             
                  # Pass a module with filter methods which should be available
         
     | 
| 
         @@ -110,7 +118,8 @@ module Liquid 
     | 
|
| 
       110 
118 
     | 
    
         
             
                end
         
     | 
| 
       111 
119 
     | 
    
         | 
| 
       112 
120 
     | 
    
         
             
                def initialize
         
     | 
| 
       113 
     | 
    
         
            -
                  @ 
     | 
| 
      
 121 
     | 
    
         
            +
                  @rethrow_errors = false
         
     | 
| 
      
 122 
     | 
    
         
            +
                  @resource_limits = ResourceLimits.new(self.class.default_resource_limits)
         
     | 
| 
       114 
123 
     | 
    
         
             
                end
         
     | 
| 
       115 
124 
     | 
    
         | 
| 
       116 
125 
     | 
    
         
             
                # Parse source code.
         
     | 
| 
         @@ -119,16 +128,12 @@ module Liquid 
     | 
|
| 
       119 
128 
     | 
    
         
             
                  @options = options
         
     | 
| 
       120 
129 
     | 
    
         
             
                  @profiling = options[:profile]
         
     | 
| 
       121 
130 
     | 
    
         
             
                  @line_numbers = options[:line_numbers] || @profiling
         
     | 
| 
       122 
     | 
    
         
            -
                   
     | 
| 
       123 
     | 
    
         
            -
                  @ 
     | 
| 
      
 131 
     | 
    
         
            +
                  parse_context = options.is_a?(ParseContext) ? options : ParseContext.new(options)
         
     | 
| 
      
 132 
     | 
    
         
            +
                  @root = Document.parse(tokenize(source), parse_context)
         
     | 
| 
      
 133 
     | 
    
         
            +
                  @warnings = parse_context.warnings
         
     | 
| 
       124 
134 
     | 
    
         
             
                  self
         
     | 
| 
       125 
135 
     | 
    
         
             
                end
         
     | 
| 
       126 
136 
     | 
    
         | 
| 
       127 
     | 
    
         
            -
                def warnings
         
     | 
| 
       128 
     | 
    
         
            -
                  return [] unless @root
         
     | 
| 
       129 
     | 
    
         
            -
                  @warnings ||= @root.warnings
         
     | 
| 
       130 
     | 
    
         
            -
                end
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
137 
     | 
    
         
             
                def registers
         
     | 
| 
       133 
138 
     | 
    
         
             
                  @registers ||= {}
         
     | 
| 
       134 
139 
     | 
    
         
             
                end
         
     | 
| 
         @@ -167,7 +172,7 @@ module Liquid 
     | 
|
| 
       167 
172 
     | 
    
         
             
                    c = args.shift
         
     | 
| 
       168 
173 
     | 
    
         | 
| 
       169 
174 
     | 
    
         
             
                    if @rethrow_errors
         
     | 
| 
       170 
     | 
    
         
            -
                      c. 
     | 
| 
      
 175 
     | 
    
         
            +
                      c.exception_renderer = ->(e) { raise }
         
     | 
| 
       171 
176 
     | 
    
         
             
                    end
         
     | 
| 
       172 
177 
     | 
    
         | 
| 
       173 
178 
     | 
    
         
             
                    c
         
     | 
| 
         @@ -186,27 +191,20 @@ module Liquid 
     | 
|
| 
       186 
191 
     | 
    
         
             
                  when Hash
         
     | 
| 
       187 
192 
     | 
    
         
             
                    options = args.pop
         
     | 
| 
       188 
193 
     | 
    
         | 
| 
       189 
     | 
    
         
            -
                    if options[:registers].is_a?(Hash)
         
     | 
| 
       190 
     | 
    
         
            -
                      self.registers.merge!(options[:registers])
         
     | 
| 
       191 
     | 
    
         
            -
                    end
         
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
                    if options[:filters]
         
     | 
| 
       194 
     | 
    
         
            -
                      context.add_filters(options[:filters])
         
     | 
| 
       195 
     | 
    
         
            -
                    end
         
     | 
| 
      
 194 
     | 
    
         
            +
                    registers.merge!(options[:registers]) if options[:registers].is_a?(Hash)
         
     | 
| 
       196 
195 
     | 
    
         | 
| 
       197 
     | 
    
         
            -
                     
     | 
| 
       198 
     | 
    
         
            -
             
     | 
| 
       199 
     | 
    
         
            -
                    end
         
     | 
| 
       200 
     | 
    
         
            -
                  when Module
         
     | 
| 
       201 
     | 
    
         
            -
                    context.add_filters(args.pop)
         
     | 
| 
       202 
     | 
    
         
            -
                  when Array
         
     | 
| 
      
 196 
     | 
    
         
            +
                    apply_options_to_context(context, options)
         
     | 
| 
      
 197 
     | 
    
         
            +
                  when Module, Array
         
     | 
| 
       203 
198 
     | 
    
         
             
                    context.add_filters(args.pop)
         
     | 
| 
       204 
199 
     | 
    
         
             
                  end
         
     | 
| 
       205 
200 
     | 
    
         | 
| 
      
 201 
     | 
    
         
            +
                  # Retrying a render resets resource usage
         
     | 
| 
      
 202 
     | 
    
         
            +
                  context.resource_limits.reset
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
       206 
204 
     | 
    
         
             
                  begin
         
     | 
| 
       207 
205 
     | 
    
         
             
                    # render the nodelist.
         
     | 
| 
       208 
206 
     | 
    
         
             
                    # for performance reasons we get an array back here. join will make a string out of it.
         
     | 
| 
       209 
     | 
    
         
            -
                    result = with_profiling do
         
     | 
| 
      
 207 
     | 
    
         
            +
                    result = with_profiling(context) do
         
     | 
| 
       210 
208 
     | 
    
         
             
                      @root.render(context)
         
     | 
| 
       211 
209 
     | 
    
         
             
                    end
         
     | 
| 
       212 
210 
     | 
    
         
             
                    result.respond_to?(:join) ? result.join : result
         
     | 
| 
         @@ -224,32 +222,14 @@ module Liquid 
     | 
|
| 
       224 
222 
     | 
    
         | 
| 
       225 
223 
     | 
    
         
             
                private
         
     | 
| 
       226 
224 
     | 
    
         | 
| 
       227 
     | 
    
         
            -
                # Uses the <tt>Liquid::TemplateParser</tt> regexp to tokenize the passed source
         
     | 
| 
       228 
225 
     | 
    
         
             
                def tokenize(source)
         
     | 
| 
       229 
     | 
    
         
            -
                   
     | 
| 
       230 
     | 
    
         
            -
                  return [] if source.to_s.empty?
         
     | 
| 
       231 
     | 
    
         
            -
             
     | 
| 
       232 
     | 
    
         
            -
                  tokens = calculate_line_numbers(source.split(TemplateParser))
         
     | 
| 
       233 
     | 
    
         
            -
             
     | 
| 
       234 
     | 
    
         
            -
                  # removes the rogue empty element at the beginning of the array
         
     | 
| 
       235 
     | 
    
         
            -
                  tokens.shift if tokens[0] and tokens[0].empty?
         
     | 
| 
       236 
     | 
    
         
            -
             
     | 
| 
       237 
     | 
    
         
            -
                  tokens
         
     | 
| 
      
 226 
     | 
    
         
            +
                  Tokenizer.new(source, @line_numbers)
         
     | 
| 
       238 
227 
     | 
    
         
             
                end
         
     | 
| 
       239 
228 
     | 
    
         | 
| 
       240 
     | 
    
         
            -
                def  
     | 
| 
       241 
     | 
    
         
            -
                   
     | 
| 
      
 229 
     | 
    
         
            +
                def with_profiling(context)
         
     | 
| 
      
 230 
     | 
    
         
            +
                  if @profiling && !context.partial
         
     | 
| 
      
 231 
     | 
    
         
            +
                    raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler)
         
     | 
| 
       242 
232 
     | 
    
         | 
| 
       243 
     | 
    
         
            -
                  current_line = 1
         
     | 
| 
       244 
     | 
    
         
            -
                  raw_tokens.map do |token|
         
     | 
| 
       245 
     | 
    
         
            -
                    Token.new(token, current_line).tap do
         
     | 
| 
       246 
     | 
    
         
            -
                      current_line += token.count("\n")
         
     | 
| 
       247 
     | 
    
         
            -
                    end
         
     | 
| 
       248 
     | 
    
         
            -
                  end
         
     | 
| 
       249 
     | 
    
         
            -
                end
         
     | 
| 
       250 
     | 
    
         
            -
             
     | 
| 
       251 
     | 
    
         
            -
                def with_profiling
         
     | 
| 
       252 
     | 
    
         
            -
                  if @profiling && !@options[:included]
         
     | 
| 
       253 
233 
     | 
    
         
             
                    @profiler = Profiler.new
         
     | 
| 
       254 
234 
     | 
    
         
             
                    @profiler.start
         
     | 
| 
       255 
235 
     | 
    
         | 
| 
         @@ -262,5 +242,13 @@ module Liquid 
     | 
|
| 
       262 
242 
     | 
    
         
             
                    yield
         
     | 
| 
       263 
243 
     | 
    
         
             
                  end
         
     | 
| 
       264 
244 
     | 
    
         
             
                end
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
                def apply_options_to_context(context, options)
         
     | 
| 
      
 247 
     | 
    
         
            +
                  context.add_filters(options[:filters]) if options[:filters]
         
     | 
| 
      
 248 
     | 
    
         
            +
                  context.global_filter = options[:global_filter] if options[:global_filter]
         
     | 
| 
      
 249 
     | 
    
         
            +
                  context.exception_renderer = options[:exception_renderer] if options[:exception_renderer]
         
     | 
| 
      
 250 
     | 
    
         
            +
                  context.strict_variables = options[:strict_variables] if options[:strict_variables]
         
     | 
| 
      
 251 
     | 
    
         
            +
                  context.strict_filters = options[:strict_filters] if options[:strict_filters]
         
     | 
| 
      
 252 
     | 
    
         
            +
                end
         
     | 
| 
       265 
253 
     | 
    
         
             
              end
         
     | 
| 
       266 
254 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Liquid
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Tokenizer
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :line_number
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(source, line_numbers = false)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @source = source
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @line_number = line_numbers ? 1 : nil
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @tokens = tokenize
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def shift
         
     | 
| 
      
 12 
     | 
    
         
            +
                  token = @tokens.shift
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @line_number += token.count("\n") if @line_number && token
         
     | 
| 
      
 14 
     | 
    
         
            +
                  token
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                private
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def tokenize
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @source = @source.source if @source.respond_to?(:source)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  return [] if @source.to_s.empty?
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  tokens = @source.split(TemplateParser)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  # removes the rogue empty element at the beginning of the array
         
     | 
| 
      
 26 
     | 
    
         
            +
                  tokens.shift if tokens[0] && tokens[0].empty?
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  tokens
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/liquid/utils.rb
    CHANGED
    
    | 
         @@ -1,27 +1,24 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
2 
     | 
    
         
             
              module Utils
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
3 
     | 
    
         
             
                def self.slice_collection(collection, from, to)
         
     | 
| 
       5 
     | 
    
         
            -
                  if (from != 0 || to 
     | 
| 
      
 4 
     | 
    
         
            +
                  if (from != 0 || !to.nil?) && collection.respond_to?(:load_slice)
         
     | 
| 
       6 
5 
     | 
    
         
             
                    collection.load_slice(from, to)
         
     | 
| 
       7 
6 
     | 
    
         
             
                  else
         
     | 
| 
       8 
7 
     | 
    
         
             
                    slice_collection_using_each(collection, from, to)
         
     | 
| 
       9 
8 
     | 
    
         
             
                  end
         
     | 
| 
       10 
9 
     | 
    
         
             
                end
         
     | 
| 
       11 
10 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
                def self.non_blank_string?(collection)
         
     | 
| 
       13 
     | 
    
         
            -
                  collection.is_a?(String) && collection != ''.freeze
         
     | 
| 
       14 
     | 
    
         
            -
                end
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
11 
     | 
    
         
             
                def self.slice_collection_using_each(collection, from, to)
         
     | 
| 
       17 
12 
     | 
    
         
             
                  segments = []
         
     | 
| 
       18 
13 
     | 
    
         
             
                  index = 0
         
     | 
| 
       19 
14 
     | 
    
         | 
| 
       20 
15 
     | 
    
         
             
                  # Maintains Ruby 1.8.7 String#each behaviour on 1.9
         
     | 
| 
       21 
     | 
    
         
            -
                   
     | 
| 
      
 16 
     | 
    
         
            +
                  if collection.is_a?(String)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return collection.empty? ? [] : [collection]
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  return [] unless collection.respond_to?(:each)
         
     | 
| 
       22 
20 
     | 
    
         | 
| 
       23 
21 
     | 
    
         
             
                  collection.each do |item|
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
22 
     | 
    
         
             
                    if to && to <= index
         
     | 
| 
       26 
23 
     | 
    
         
             
                      break
         
     | 
| 
       27 
24 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -35,5 +32,52 @@ module Liquid 
     | 
|
| 
       35 
32 
     | 
    
         | 
| 
       36 
33 
     | 
    
         
             
                  segments
         
     | 
| 
       37 
34 
     | 
    
         
             
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def self.to_integer(num)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  return num if num.is_a?(Integer)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  num = num.to_s
         
     | 
| 
      
 39 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 40 
     | 
    
         
            +
                    Integer(num)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  rescue ::ArgumentError
         
     | 
| 
      
 42 
     | 
    
         
            +
                    raise Liquid::ArgumentError, "invalid integer"
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def self.to_number(obj)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  case obj
         
     | 
| 
      
 48 
     | 
    
         
            +
                  when Float
         
     | 
| 
      
 49 
     | 
    
         
            +
                    BigDecimal.new(obj.to_s)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  when Numeric
         
     | 
| 
      
 51 
     | 
    
         
            +
                    obj
         
     | 
| 
      
 52 
     | 
    
         
            +
                  when String
         
     | 
| 
      
 53 
     | 
    
         
            +
                    (obj.strip =~ /\A-?\d+\.\d+\z/) ? BigDecimal.new(obj) : obj.to_i
         
     | 
| 
      
 54 
     | 
    
         
            +
                  else
         
     | 
| 
      
 55 
     | 
    
         
            +
                    if obj.respond_to?(:to_number)
         
     | 
| 
      
 56 
     | 
    
         
            +
                      obj.to_number
         
     | 
| 
      
 57 
     | 
    
         
            +
                    else
         
     | 
| 
      
 58 
     | 
    
         
            +
                      0
         
     | 
| 
      
 59 
     | 
    
         
            +
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def self.to_date(obj)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  return obj if obj.respond_to?(:strftime)
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  if obj.is_a?(String)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    return nil if obj.empty?
         
     | 
| 
      
 68 
     | 
    
         
            +
                    obj = obj.downcase
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  case obj
         
     | 
| 
      
 72 
     | 
    
         
            +
                  when 'now'.freeze, 'today'.freeze
         
     | 
| 
      
 73 
     | 
    
         
            +
                    Time.now
         
     | 
| 
      
 74 
     | 
    
         
            +
                  when /\A\d+\z/, Integer
         
     | 
| 
      
 75 
     | 
    
         
            +
                    Time.at(obj.to_i)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  when String
         
     | 
| 
      
 77 
     | 
    
         
            +
                    Time.parse(obj)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
                rescue ::ArgumentError
         
     | 
| 
      
 80 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
       38 
82 
     | 
    
         
             
              end
         
     | 
| 
       39 
83 
     | 
    
         
             
            end
         
     | 
    
        data/lib/liquid/variable.rb
    CHANGED
    
    | 
         @@ -1,5 +1,4 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
2 
     | 
    
         
             
              # Holds variables. Variables are only loaded "just in time"
         
     | 
| 
       4 
3 
     | 
    
         
             
              # and are not evaluated as part of the render stage
         
     | 
| 
       5 
4 
     | 
    
         
             
              #
         
     | 
| 
         @@ -12,15 +11,16 @@ module Liquid 
     | 
|
| 
       12 
11 
     | 
    
         
             
              #
         
     | 
| 
       13 
12 
     | 
    
         
             
              class Variable
         
     | 
| 
       14 
13 
     | 
    
         
             
                FilterParser = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o
         
     | 
| 
       15 
     | 
    
         
            -
                 
     | 
| 
       16 
     | 
    
         
            -
                 
     | 
| 
       17 
     | 
    
         
            -
                 
     | 
| 
      
 14 
     | 
    
         
            +
                attr_accessor :filters, :name, :line_number
         
     | 
| 
      
 15 
     | 
    
         
            +
                attr_reader :parse_context
         
     | 
| 
      
 16 
     | 
    
         
            +
                alias_method :options, :parse_context
         
     | 
| 
       18 
17 
     | 
    
         
             
                include ParserSwitching
         
     | 
| 
       19 
18 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
                def initialize(markup,  
     | 
| 
      
 19 
     | 
    
         
            +
                def initialize(markup, parse_context)
         
     | 
| 
       21 
20 
     | 
    
         
             
                  @markup  = markup
         
     | 
| 
       22 
21 
     | 
    
         
             
                  @name    = nil
         
     | 
| 
       23 
     | 
    
         
            -
                  @ 
     | 
| 
      
 22 
     | 
    
         
            +
                  @parse_context = parse_context
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @line_number = parse_context.line_number
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                  parse_with_selected_parser(markup)
         
     | 
| 
       26 
26 
     | 
    
         
             
                end
         
     | 
| 
         @@ -35,35 +35,27 @@ module Liquid 
     | 
|
| 
       35 
35 
     | 
    
         | 
| 
       36 
36 
     | 
    
         
             
                def lax_parse(markup)
         
     | 
| 
       37 
37 
     | 
    
         
             
                  @filters = []
         
     | 
| 
       38 
     | 
    
         
            -
                   
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
                      end
         
     | 
| 
      
 38 
     | 
    
         
            +
                  return unless markup =~ /(#{QuotedFragment})(.*)/om
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  name_markup = $1
         
     | 
| 
      
 41 
     | 
    
         
            +
                  filter_markup = $2
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @name = Expression.parse(name_markup)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  if filter_markup =~ /#{FilterSeparator}\s*(.*)/om
         
     | 
| 
      
 44 
     | 
    
         
            +
                    filters = $1.scan(FilterParser)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    filters.each do |f|
         
     | 
| 
      
 46 
     | 
    
         
            +
                      next unless f =~ /\w+/
         
     | 
| 
      
 47 
     | 
    
         
            +
                      filtername = Regexp.last_match(0)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten
         
     | 
| 
      
 49 
     | 
    
         
            +
                      @filters << parse_filter_expressions(filtername, filterargs)
         
     | 
| 
       51 
50 
     | 
    
         
             
                    end
         
     | 
| 
       52 
51 
     | 
    
         
             
                  end
         
     | 
| 
       53 
52 
     | 
    
         
             
                end
         
     | 
| 
       54 
53 
     | 
    
         | 
| 
       55 
54 
     | 
    
         
             
                def strict_parse(markup)
         
     | 
| 
       56 
     | 
    
         
            -
                  # Very simple valid cases
         
     | 
| 
       57 
     | 
    
         
            -
                  if markup =~ EasyParse
         
     | 
| 
       58 
     | 
    
         
            -
                    @name = Expression.parse($1)
         
     | 
| 
       59 
     | 
    
         
            -
                    @filters = []
         
     | 
| 
       60 
     | 
    
         
            -
                    return
         
     | 
| 
       61 
     | 
    
         
            -
                  end
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
55 
     | 
    
         
             
                  @filters = []
         
     | 
| 
       64 
56 
     | 
    
         
             
                  p = Parser.new(markup)
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
                  @name =  
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  @name = Expression.parse(p.expression)
         
     | 
| 
       67 
59 
     | 
    
         
             
                  while p.consume?(:pipe)
         
     | 
| 
       68 
60 
     | 
    
         
             
                    filtername = p.consume(:id)
         
     | 
| 
       69 
61 
     | 
    
         
             
                    filterargs = p.consume?(:colon) ? parse_filterargs(p) : []
         
     | 
| 
         @@ -76,17 +68,21 @@ module Liquid 
     | 
|
| 
       76 
68 
     | 
    
         
             
                  # first argument
         
     | 
| 
       77 
69 
     | 
    
         
             
                  filterargs = [p.argument]
         
     | 
| 
       78 
70 
     | 
    
         
             
                  # followed by comma separated others
         
     | 
| 
       79 
     | 
    
         
            -
                  while p.consume?(:comma)
         
     | 
| 
       80 
     | 
    
         
            -
                    filterargs << p.argument
         
     | 
| 
       81 
     | 
    
         
            -
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  filterargs << p.argument while p.consume?(:comma)
         
     | 
| 
       82 
72 
     | 
    
         
             
                  filterargs
         
     | 
| 
       83 
73 
     | 
    
         
             
                end
         
     | 
| 
       84 
74 
     | 
    
         | 
| 
       85 
75 
     | 
    
         
             
                def render(context)
         
     | 
| 
       86 
     | 
    
         
            -
                  @filters.inject(context.evaluate(@name)) do |output, (filter_name, filter_args, filter_kwargs)|
         
     | 
| 
      
 76 
     | 
    
         
            +
                  obj = @filters.inject(context.evaluate(@name)) do |output, (filter_name, filter_args, filter_kwargs)|
         
     | 
| 
       87 
77 
     | 
    
         
             
                    filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs)
         
     | 
| 
       88 
     | 
    
         
            -
                     
     | 
| 
       89 
     | 
    
         
            -
                  end 
     | 
| 
      
 78 
     | 
    
         
            +
                    context.invoke(filter_name, output, *filter_args)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  obj = context.apply_global_filter(obj)
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  taint_check(context, obj)
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                  obj
         
     | 
| 
       90 
86 
     | 
    
         
             
                end
         
     | 
| 
       91 
87 
     | 
    
         | 
| 
       92 
88 
     | 
    
         
             
                private
         
     | 
| 
         @@ -118,17 +114,22 @@ module Liquid 
     | 
|
| 
       118 
114 
     | 
    
         
             
                  parsed_args
         
     | 
| 
       119 
115 
     | 
    
         
             
                end
         
     | 
| 
       120 
116 
     | 
    
         | 
| 
       121 
     | 
    
         
            -
                def taint_check(obj)
         
     | 
| 
       122 
     | 
    
         
            -
                   
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
      
 117 
     | 
    
         
            +
                def taint_check(context, obj)
         
     | 
| 
      
 118 
     | 
    
         
            +
                  return unless obj.tainted?
         
     | 
| 
      
 119 
     | 
    
         
            +
                  return if Template.taint_mode == :lax
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                  @markup =~ QuotedFragment
         
     | 
| 
      
 122 
     | 
    
         
            +
                  name = Regexp.last_match(0)
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                  error = TaintedError.new("variable '#{name}' is tainted and was not escaped")
         
     | 
| 
      
 125 
     | 
    
         
            +
                  error.line_number = line_number
         
     | 
| 
      
 126 
     | 
    
         
            +
                  error.template_name = context.template_name
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                  case Template.taint_mode
         
     | 
| 
      
 129 
     | 
    
         
            +
                  when :warn
         
     | 
| 
      
 130 
     | 
    
         
            +
                    context.warnings << error
         
     | 
| 
      
 131 
     | 
    
         
            +
                  when :error
         
     | 
| 
      
 132 
     | 
    
         
            +
                    raise error
         
     | 
| 
       132 
133 
     | 
    
         
             
                  end
         
     | 
| 
       133 
134 
     | 
    
         
             
                end
         
     | 
| 
       134 
135 
     | 
    
         
             
              end
         
     | 
| 
         @@ -3,6 +3,8 @@ module Liquid 
     | 
|
| 
       3 
3 
     | 
    
         
             
                SQUARE_BRACKETED = /\A\[(.*)\]\z/m
         
     | 
| 
       4 
4 
     | 
    
         
             
                COMMAND_METHODS = ['size'.freeze, 'first'.freeze, 'last'.freeze]
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :name, :lookups
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
       6 
8 
     | 
    
         
             
                def self.parse(markup)
         
     | 
| 
       7 
9 
     | 
    
         
             
                  new(markup)
         
     | 
| 
       8 
10 
     | 
    
         
             
                end
         
     | 
| 
         @@ -39,8 +41,8 @@ module Liquid 
     | 
|
| 
       39 
41 
     | 
    
         
             
                    # If object is a hash- or array-like object we look for the
         
     | 
| 
       40 
42 
     | 
    
         
             
                    # presence of the key and if its available we return it
         
     | 
| 
       41 
43 
     | 
    
         
             
                    if object.respond_to?(:[]) &&
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 44 
     | 
    
         
            +
                        ((object.respond_to?(:key?) && object.key?(key)) ||
         
     | 
| 
      
 45 
     | 
    
         
            +
                         (object.respond_to?(:fetch) && key.is_a?(Integer)))
         
     | 
| 
       44 
46 
     | 
    
         | 
| 
       45 
47 
     | 
    
         
             
                      # if its a proc we will replace the entry with the proc
         
     | 
| 
       46 
48 
     | 
    
         
             
                      res = context.lookup_and_evaluate(object, key)
         
     | 
| 
         @@ -53,9 +55,11 @@ module Liquid 
     | 
|
| 
       53 
55 
     | 
    
         
             
                      object = object.send(key).to_liquid
         
     | 
| 
       54 
56 
     | 
    
         | 
| 
       55 
57 
     | 
    
         
             
                      # No key was present with the desired value and it wasn't one of the directly supported
         
     | 
| 
       56 
     | 
    
         
            -
                      # keywords either. The only thing we got left is to return nil
         
     | 
| 
      
 58 
     | 
    
         
            +
                      # keywords either. The only thing we got left is to return nil or
         
     | 
| 
      
 59 
     | 
    
         
            +
                      # raise an exception if `strict_variables` option is set to true
         
     | 
| 
       57 
60 
     | 
    
         
             
                    else
         
     | 
| 
       58 
     | 
    
         
            -
                      return nil
         
     | 
| 
      
 61 
     | 
    
         
            +
                      return nil unless context.strict_variables
         
     | 
| 
      
 62 
     | 
    
         
            +
                      raise Liquid::UndefinedVariable, "undefined variable #{key}"
         
     | 
| 
       59 
63 
     | 
    
         
             
                    end
         
     | 
| 
       60 
64 
     | 
    
         | 
| 
       61 
65 
     | 
    
         
             
                    # If we are dealing with a drop here we have to
         
     | 
| 
         @@ -66,7 +70,7 @@ module Liquid 
     | 
|
| 
       66 
70 
     | 
    
         
             
                end
         
     | 
| 
       67 
71 
     | 
    
         | 
| 
       68 
72 
     | 
    
         
             
                def ==(other)
         
     | 
| 
       69 
     | 
    
         
            -
                  self.class == other.class &&  
     | 
| 
      
 73 
     | 
    
         
            +
                  self.class == other.class && state == other.state
         
     | 
| 
       70 
74 
     | 
    
         
             
                end
         
     | 
| 
       71 
75 
     | 
    
         | 
| 
       72 
76 
     | 
    
         
             
                protected
         
     | 
    
        data/lib/liquid/version.rb
    CHANGED
    
    
    
        data/lib/liquid.rb
    CHANGED
    
    | 
         @@ -24,6 +24,7 @@ module Liquid 
     | 
|
| 
       24 
24 
     | 
    
         
             
              ArgumentSeparator           = ','.freeze
         
     | 
| 
       25 
25 
     | 
    
         
             
              FilterArgumentSeparator     = ':'.freeze
         
     | 
| 
       26 
26 
     | 
    
         
             
              VariableAttributeSeparator  = '.'.freeze
         
     | 
| 
      
 27 
     | 
    
         
            +
              WhitespaceControl           = '-'.freeze
         
     | 
| 
       27 
28 
     | 
    
         
             
              TagStart                    = /\{\%/
         
     | 
| 
       28 
29 
     | 
    
         
             
              TagEnd                      = /\%\}/
         
     | 
| 
       29 
30 
     | 
    
         
             
              VariableSignature           = /\(?[\w\-\.\[\]]\)?/
         
     | 
| 
         @@ -34,7 +35,7 @@ module Liquid 
     | 
|
| 
       34 
35 
     | 
    
         
             
              QuotedString                = /"[^"]*"|'[^']*'/
         
     | 
| 
       35 
36 
     | 
    
         
             
              QuotedFragment              = /#{QuotedString}|(?:[^\s,\|'"]|#{QuotedString})+/o
         
     | 
| 
       36 
37 
     | 
    
         
             
              TagAttributes               = /(\w+)\s*\:\s*(#{QuotedFragment})/o
         
     | 
| 
       37 
     | 
    
         
            -
              AnyStartingTag              =  
     | 
| 
      
 38 
     | 
    
         
            +
              AnyStartingTag              = /#{TagStart}|#{VariableStart}/o
         
     | 
| 
       38 
39 
     | 
    
         
             
              PartialTemplateParser       = /#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd}/om
         
     | 
| 
       39 
40 
     | 
    
         
             
              TemplateParser              = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
         
     | 
| 
       40 
41 
     | 
    
         
             
              VariableParser              = /\[[^\]]+\]|#{VariableSegment}+\??/o
         
     | 
| 
         @@ -48,6 +49,8 @@ require 'liquid/lexer' 
     | 
|
| 
       48 
49 
     | 
    
         
             
            require 'liquid/parser'
         
     | 
| 
       49 
50 
     | 
    
         
             
            require 'liquid/i18n'
         
     | 
| 
       50 
51 
     | 
    
         
             
            require 'liquid/drop'
         
     | 
| 
      
 52 
     | 
    
         
            +
            require 'liquid/tablerowloop_drop'
         
     | 
| 
      
 53 
     | 
    
         
            +
            require 'liquid/forloop_drop'
         
     | 
| 
       51 
54 
     | 
    
         
             
            require 'liquid/extensions'
         
     | 
| 
       52 
55 
     | 
    
         
             
            require 'liquid/errors'
         
     | 
| 
       53 
56 
     | 
    
         
             
            require 'liquid/interrupts'
         
     | 
| 
         @@ -57,21 +60,20 @@ require 'liquid/context' 
     | 
|
| 
       57 
60 
     | 
    
         
             
            require 'liquid/parser_switching'
         
     | 
| 
       58 
61 
     | 
    
         
             
            require 'liquid/tag'
         
     | 
| 
       59 
62 
     | 
    
         
             
            require 'liquid/block'
         
     | 
| 
      
 63 
     | 
    
         
            +
            require 'liquid/block_body'
         
     | 
| 
       60 
64 
     | 
    
         
             
            require 'liquid/document'
         
     | 
| 
       61 
65 
     | 
    
         
             
            require 'liquid/variable'
         
     | 
| 
       62 
66 
     | 
    
         
             
            require 'liquid/variable_lookup'
         
     | 
| 
       63 
67 
     | 
    
         
             
            require 'liquid/range_lookup'
         
     | 
| 
       64 
68 
     | 
    
         
             
            require 'liquid/file_system'
         
     | 
| 
      
 69 
     | 
    
         
            +
            require 'liquid/resource_limits'
         
     | 
| 
       65 
70 
     | 
    
         
             
            require 'liquid/template'
         
     | 
| 
       66 
71 
     | 
    
         
             
            require 'liquid/standardfilters'
         
     | 
| 
       67 
72 
     | 
    
         
             
            require 'liquid/condition'
         
     | 
| 
       68 
     | 
    
         
            -
            require 'liquid/module_ex'
         
     | 
| 
       69 
73 
     | 
    
         
             
            require 'liquid/utils'
         
     | 
| 
       70 
     | 
    
         
            -
            require 'liquid/ 
     | 
| 
      
 74 
     | 
    
         
            +
            require 'liquid/tokenizer'
         
     | 
| 
      
 75 
     | 
    
         
            +
            require 'liquid/parse_context'
         
     | 
| 
       71 
76 
     | 
    
         | 
| 
       72 
77 
     | 
    
         
             
            # Load all the tags of the standard library
         
     | 
| 
       73 
78 
     | 
    
         
             
            #
         
     | 
| 
       74 
     | 
    
         
            -
            Dir[ 
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
            require 'liquid/profiler'
         
     | 
| 
       77 
     | 
    
         
            -
            require 'liquid/profiler/hooks'
         
     | 
| 
      
 79 
     | 
    
         
            +
            Dir["#{__dir__}/liquid/tags/*.rb"].each { |f| require f }
         
     |