liquid 4.0.3 → 5.1.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 +54 -0
 - data/README.md +6 -0
 - data/lib/liquid/block.rb +31 -14
 - data/lib/liquid/block_body.rb +166 -54
 - data/lib/liquid/condition.rb +41 -20
 - data/lib/liquid/context.rb +107 -52
 - data/lib/liquid/document.rb +47 -9
 - data/lib/liquid/drop.rb +4 -2
 - data/lib/liquid/errors.rb +20 -18
 - data/lib/liquid/expression.rb +29 -34
 - data/lib/liquid/extensions.rb +2 -0
 - data/lib/liquid/file_system.rb +6 -4
 - data/lib/liquid/forloop_drop.rb +11 -4
 - data/lib/liquid/i18n.rb +5 -3
 - data/lib/liquid/interrupts.rb +3 -1
 - data/lib/liquid/lexer.rb +30 -23
 - data/lib/liquid/locales/en.yml +3 -1
 - data/lib/liquid/parse_context.rb +20 -4
 - data/lib/liquid/parse_tree_visitor.rb +2 -2
 - data/lib/liquid/parser.rb +30 -18
 - data/lib/liquid/parser_switching.rb +17 -3
 - data/lib/liquid/partial_cache.rb +24 -0
 - data/lib/liquid/profiler/hooks.rb +26 -14
 - data/lib/liquid/profiler.rb +67 -86
 - data/lib/liquid/range_lookup.rb +13 -3
 - data/lib/liquid/register.rb +6 -0
 - data/lib/liquid/resource_limits.rb +47 -8
 - data/lib/liquid/standardfilters.rb +95 -46
 - data/lib/liquid/static_registers.rb +44 -0
 - data/lib/liquid/strainer_factory.rb +36 -0
 - data/lib/liquid/strainer_template.rb +53 -0
 - data/lib/liquid/tablerowloop_drop.rb +6 -4
 - data/lib/liquid/tag/disableable.rb +22 -0
 - data/lib/liquid/tag/disabler.rb +21 -0
 - data/lib/liquid/tag.rb +28 -6
 - data/lib/liquid/tags/assign.rb +24 -10
 - data/lib/liquid/tags/break.rb +8 -3
 - data/lib/liquid/tags/capture.rb +11 -8
 - data/lib/liquid/tags/case.rb +40 -27
 - data/lib/liquid/tags/comment.rb +5 -3
 - data/lib/liquid/tags/continue.rb +8 -3
 - data/lib/liquid/tags/cycle.rb +25 -14
 - data/lib/liquid/tags/decrement.rb +6 -3
 - data/lib/liquid/tags/echo.rb +34 -0
 - data/lib/liquid/tags/for.rb +68 -44
 - data/lib/liquid/tags/if.rb +39 -23
 - data/lib/liquid/tags/ifchanged.rb +11 -10
 - data/lib/liquid/tags/include.rb +34 -47
 - data/lib/liquid/tags/increment.rb +7 -3
 - data/lib/liquid/tags/raw.rb +14 -11
 - data/lib/liquid/tags/render.rb +84 -0
 - data/lib/liquid/tags/table_row.rb +23 -19
 - data/lib/liquid/tags/unless.rb +23 -15
 - data/lib/liquid/template.rb +53 -72
 - data/lib/liquid/template_factory.rb +9 -0
 - data/lib/liquid/tokenizer.rb +18 -10
 - data/lib/liquid/usage.rb +8 -0
 - data/lib/liquid/utils.rb +13 -3
 - data/lib/liquid/variable.rb +46 -41
 - data/lib/liquid/variable_lookup.rb +11 -6
 - data/lib/liquid/version.rb +2 -1
 - data/lib/liquid.rb +17 -5
 - data/test/integration/assign_test.rb +74 -5
 - data/test/integration/blank_test.rb +11 -8
 - data/test/integration/block_test.rb +47 -1
 - data/test/integration/capture_test.rb +18 -10
 - data/test/integration/context_test.rb +609 -5
 - data/test/integration/document_test.rb +4 -2
 - data/test/integration/drop_test.rb +67 -83
 - data/test/integration/error_handling_test.rb +73 -61
 - data/test/integration/expression_test.rb +46 -0
 - data/test/integration/filter_test.rb +53 -42
 - data/test/integration/hash_ordering_test.rb +5 -3
 - data/test/integration/output_test.rb +26 -24
 - data/test/integration/parsing_quirks_test.rb +19 -7
 - data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
 - data/test/integration/security_test.rb +30 -21
 - data/test/integration/standard_filter_test.rb +385 -281
 - data/test/integration/tag/disableable_test.rb +59 -0
 - data/test/integration/tag_test.rb +45 -0
 - data/test/integration/tags/break_tag_test.rb +4 -2
 - data/test/integration/tags/continue_tag_test.rb +4 -2
 - data/test/integration/tags/echo_test.rb +13 -0
 - data/test/integration/tags/for_tag_test.rb +107 -51
 - data/test/integration/tags/if_else_tag_test.rb +5 -3
 - data/test/integration/tags/include_tag_test.rb +70 -54
 - data/test/integration/tags/increment_tag_test.rb +4 -2
 - data/test/integration/tags/liquid_tag_test.rb +116 -0
 - data/test/integration/tags/raw_tag_test.rb +14 -11
 - data/test/integration/tags/render_tag_test.rb +213 -0
 - data/test/integration/tags/standard_tag_test.rb +38 -31
 - data/test/integration/tags/statements_test.rb +23 -21
 - data/test/integration/tags/table_row_test.rb +2 -0
 - data/test/integration/tags/unless_else_tag_test.rb +4 -2
 - data/test/integration/template_test.rb +132 -124
 - data/test/integration/trim_mode_test.rb +78 -44
 - data/test/integration/variable_test.rb +74 -32
 - data/test/test_helper.rb +113 -22
 - data/test/unit/block_unit_test.rb +19 -24
 - data/test/unit/condition_unit_test.rb +79 -77
 - data/test/unit/file_system_unit_test.rb +6 -4
 - data/test/unit/i18n_unit_test.rb +7 -5
 - data/test/unit/lexer_unit_test.rb +11 -9
 - data/test/{integration → unit}/parse_tree_visitor_test.rb +16 -2
 - data/test/unit/parser_unit_test.rb +37 -35
 - data/test/unit/partial_cache_unit_test.rb +128 -0
 - data/test/unit/regexp_unit_test.rb +17 -15
 - data/test/unit/static_registers_unit_test.rb +156 -0
 - data/test/unit/strainer_factory_unit_test.rb +100 -0
 - data/test/unit/strainer_template_unit_test.rb +82 -0
 - data/test/unit/tag_unit_test.rb +5 -3
 - data/test/unit/tags/case_tag_unit_test.rb +3 -1
 - data/test/unit/tags/for_tag_unit_test.rb +4 -2
 - data/test/unit/tags/if_tag_unit_test.rb +3 -1
 - data/test/unit/template_factory_unit_test.rb +12 -0
 - data/test/unit/template_unit_test.rb +19 -10
 - data/test/unit/tokenizer_unit_test.rb +26 -19
 - data/test/unit/variable_unit_test.rb +51 -49
 - metadata +76 -50
 - data/lib/liquid/strainer.rb +0 -66
 - data/lib/liquid/truffle.rb +0 -5
 - data/test/truffle/truffle_test.rb +0 -9
 - data/test/unit/context_unit_test.rb +0 -489
 - data/test/unit/strainer_unit_test.rb +0 -164
 
    
        data/lib/liquid/template.rb
    CHANGED
    
    | 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
4 
     | 
    
         
             
              # Templates are central to liquid.
         
     | 
| 
       3 
5 
     | 
    
         
             
              # Interpretating templates is a two step process. First you compile the
         
     | 
| 
         @@ -16,13 +18,11 @@ module Liquid 
     | 
|
| 
       16 
18 
     | 
    
         
             
                attr_accessor :root
         
     | 
| 
       17 
19 
     | 
    
         
             
                attr_reader :resource_limits, :warnings
         
     | 
| 
       18 
20 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
                @@file_system = BlankFileSystem.new
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
21 
     | 
    
         
             
                class TagRegistry
         
     | 
| 
       22 
22 
     | 
    
         
             
                  include Enumerable
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
24 
     | 
    
         
             
                  def initialize
         
     | 
| 
       25 
     | 
    
         
            -
                    @tags 
     | 
| 
      
 25 
     | 
    
         
            +
                    @tags  = {}
         
     | 
| 
       26 
26 
     | 
    
         
             
                    @cache = {}
         
     | 
| 
       27 
27 
     | 
    
         
             
                  end
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
         @@ -50,7 +50,7 @@ module Liquid 
     | 
|
| 
       50 
50 
     | 
    
         
             
                  private
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
52 
     | 
    
         
             
                  def lookup_class(name)
         
     | 
| 
       53 
     | 
    
         
            -
                     
     | 
| 
      
 53 
     | 
    
         
            +
                    Object.const_get(name)
         
     | 
| 
       54 
54 
     | 
    
         
             
                  end
         
     | 
| 
       55 
55 
     | 
    
         
             
                end
         
     | 
| 
       56 
56 
     | 
    
         | 
| 
         @@ -61,76 +61,54 @@ module Liquid 
     | 
|
| 
       61 
61 
     | 
    
         
             
                  # :lax acts like liquid 2.5 and silently ignores malformed tags in most cases.
         
     | 
| 
       62 
62 
     | 
    
         
             
                  # :warn is the default and will give deprecation warnings when invalid syntax is used.
         
     | 
| 
       63 
63 
     | 
    
         
             
                  # :strict will enforce correct syntax.
         
     | 
| 
       64 
     | 
    
         
            -
                   
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
                  # Sets how strict the taint checker should be.
         
     | 
| 
       67 
     | 
    
         
            -
                  # :lax is the default, and ignores the taint flag completely
         
     | 
| 
       68 
     | 
    
         
            -
                  # :warn adds a warning, but does not interrupt the rendering
         
     | 
| 
       69 
     | 
    
         
            -
                  # :error raises an error when tainted output is used
         
     | 
| 
       70 
     | 
    
         
            -
                  attr_writer :taint_mode
         
     | 
| 
      
 64 
     | 
    
         
            +
                  attr_accessor :error_mode
         
     | 
| 
      
 65 
     | 
    
         
            +
                  Template.error_mode = :lax
         
     | 
| 
       71 
66 
     | 
    
         | 
| 
       72 
67 
     | 
    
         
             
                  attr_accessor :default_exception_renderer
         
     | 
| 
       73 
68 
     | 
    
         
             
                  Template.default_exception_renderer = lambda do |exception|
         
     | 
| 
       74 
69 
     | 
    
         
             
                    exception
         
     | 
| 
       75 
70 
     | 
    
         
             
                  end
         
     | 
| 
       76 
71 
     | 
    
         | 
| 
       77 
     | 
    
         
            -
                   
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
                  attr_accessor :file_system
         
     | 
| 
      
 73 
     | 
    
         
            +
                  Template.file_system = BlankFileSystem.new
         
     | 
| 
       80 
74 
     | 
    
         | 
| 
       81 
     | 
    
         
            -
                   
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                   
     | 
| 
      
 75 
     | 
    
         
            +
                  attr_accessor :tags
         
     | 
| 
      
 76 
     | 
    
         
            +
                  Template.tags = TagRegistry.new
         
     | 
| 
      
 77 
     | 
    
         
            +
                  private :tags=
         
     | 
| 
       84 
78 
     | 
    
         | 
| 
       85 
79 
     | 
    
         
             
                  def register_tag(name, klass)
         
     | 
| 
       86 
80 
     | 
    
         
             
                    tags[name.to_s] = klass
         
     | 
| 
       87 
81 
     | 
    
         
             
                  end
         
     | 
| 
       88 
82 
     | 
    
         | 
| 
       89 
     | 
    
         
            -
                  def tags
         
     | 
| 
       90 
     | 
    
         
            -
                    @tags ||= TagRegistry.new
         
     | 
| 
       91 
     | 
    
         
            -
                  end
         
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
                  def error_mode
         
     | 
| 
       94 
     | 
    
         
            -
                    @error_mode ||= :lax
         
     | 
| 
       95 
     | 
    
         
            -
                  end
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
                  def taint_mode
         
     | 
| 
       98 
     | 
    
         
            -
                    @taint_mode ||= :lax
         
     | 
| 
       99 
     | 
    
         
            -
                  end
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
83 
     | 
    
         
             
                  # Pass a module with filter methods which should be available
         
     | 
| 
       102 
84 
     | 
    
         
             
                  # to all liquid views. Good for registering the standard library
         
     | 
| 
       103 
85 
     | 
    
         
             
                  def register_filter(mod)
         
     | 
| 
       104 
     | 
    
         
            -
                     
     | 
| 
      
 86 
     | 
    
         
            +
                    StrainerFactory.add_global_filter(mod)
         
     | 
| 
       105 
87 
     | 
    
         
             
                  end
         
     | 
| 
       106 
88 
     | 
    
         | 
| 
       107 
     | 
    
         
            -
                   
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
                   
     | 
| 
      
 89 
     | 
    
         
            +
                  attr_accessor :default_resource_limits
         
     | 
| 
      
 90 
     | 
    
         
            +
                  Template.default_resource_limits = {}
         
     | 
| 
      
 91 
     | 
    
         
            +
                  private :default_resource_limits=
         
     | 
| 
       110 
92 
     | 
    
         | 
| 
       111 
93 
     | 
    
         
             
                  # creates a new <tt>Template</tt> object from liquid source code
         
     | 
| 
       112 
94 
     | 
    
         
             
                  # To enable profiling, pass in <tt>profile: true</tt> as an option.
         
     | 
| 
       113 
95 
     | 
    
         
             
                  # See Liquid::Profiler for more information
         
     | 
| 
       114 
96 
     | 
    
         
             
                  def parse(source, options = {})
         
     | 
| 
       115 
     | 
    
         
            -
                     
     | 
| 
       116 
     | 
    
         
            -
                    template.parse(source, options)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    new.parse(source, options)
         
     | 
| 
       117 
98 
     | 
    
         
             
                  end
         
     | 
| 
       118 
99 
     | 
    
         
             
                end
         
     | 
| 
       119 
100 
     | 
    
         | 
| 
       120 
101 
     | 
    
         
             
                def initialize
         
     | 
| 
       121 
     | 
    
         
            -
                  @rethrow_errors 
     | 
| 
       122 
     | 
    
         
            -
                  @resource_limits = ResourceLimits.new( 
     | 
| 
      
 102 
     | 
    
         
            +
                  @rethrow_errors  = false
         
     | 
| 
      
 103 
     | 
    
         
            +
                  @resource_limits = ResourceLimits.new(Template.default_resource_limits)
         
     | 
| 
       123 
104 
     | 
    
         
             
                end
         
     | 
| 
       124 
105 
     | 
    
         | 
| 
       125 
106 
     | 
    
         
             
                # Parse source code.
         
     | 
| 
       126 
107 
     | 
    
         
             
                # Returns self for easy chaining
         
     | 
| 
       127 
108 
     | 
    
         
             
                def parse(source, options = {})
         
     | 
| 
       128 
     | 
    
         
            -
                   
     | 
| 
       129 
     | 
    
         
            -
                  @ 
     | 
| 
       130 
     | 
    
         
            -
                  @ 
     | 
| 
       131 
     | 
    
         
            -
                  parse_context = options.is_a?(ParseContext) ? options : ParseContext.new(options)
         
     | 
| 
       132 
     | 
    
         
            -
                  @root = Document.parse(tokenize(source), parse_context)
         
     | 
| 
       133 
     | 
    
         
            -
                  @warnings = parse_context.warnings
         
     | 
| 
      
 109 
     | 
    
         
            +
                  parse_context = configure_options(options)
         
     | 
| 
      
 110 
     | 
    
         
            +
                  tokenizer     = parse_context.new_tokenizer(source, start_line_number: @line_numbers && 1)
         
     | 
| 
      
 111 
     | 
    
         
            +
                  @root         = Document.parse(tokenizer, parse_context)
         
     | 
| 
       134 
112 
     | 
    
         
             
                  self
         
     | 
| 
       135 
113 
     | 
    
         
             
                end
         
     | 
| 
       136 
114 
     | 
    
         | 
| 
         @@ -165,19 +143,19 @@ module Liquid 
     | 
|
| 
       165 
143 
     | 
    
         
             
                #    filters and tags and might be useful to integrate liquid more with its host application
         
     | 
| 
       166 
144 
     | 
    
         
             
                #
         
     | 
| 
       167 
145 
     | 
    
         
             
                def render(*args)
         
     | 
| 
       168 
     | 
    
         
            -
                  return '' 
     | 
| 
      
 146 
     | 
    
         
            +
                  return '' if @root.nil?
         
     | 
| 
       169 
147 
     | 
    
         | 
| 
       170 
148 
     | 
    
         
             
                  context = case args.first
         
     | 
| 
       171 
149 
     | 
    
         
             
                  when Liquid::Context
         
     | 
| 
       172 
150 
     | 
    
         
             
                    c = args.shift
         
     | 
| 
       173 
151 
     | 
    
         | 
| 
       174 
152 
     | 
    
         
             
                    if @rethrow_errors
         
     | 
| 
       175 
     | 
    
         
            -
                      c.exception_renderer =  
     | 
| 
      
 153 
     | 
    
         
            +
                      c.exception_renderer = Liquid::RAISE_EXCEPTION_LAMBDA
         
     | 
| 
       176 
154 
     | 
    
         
             
                    end
         
     | 
| 
       177 
155 
     | 
    
         | 
| 
       178 
156 
     | 
    
         
             
                    c
         
     | 
| 
       179 
157 
     | 
    
         
             
                  when Liquid::Drop
         
     | 
| 
       180 
     | 
    
         
            -
                    drop 
     | 
| 
      
 158 
     | 
    
         
            +
                    drop         = args.shift
         
     | 
| 
       181 
159 
     | 
    
         
             
                    drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
         
     | 
| 
       182 
160 
     | 
    
         
             
                  when Hash
         
     | 
| 
       183 
161 
     | 
    
         
             
                    Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
         
     | 
| 
         @@ -187,11 +165,18 @@ module Liquid 
     | 
|
| 
       187 
165 
     | 
    
         
             
                    raise ArgumentError, "Expected Hash or Liquid::Context as parameter"
         
     | 
| 
       188 
166 
     | 
    
         
             
                  end
         
     | 
| 
       189 
167 
     | 
    
         | 
| 
      
 168 
     | 
    
         
            +
                  output = nil
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                  context_register = context.registers.is_a?(StaticRegisters) ? context.registers.static : context.registers
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
       190 
172 
     | 
    
         
             
                  case args.last
         
     | 
| 
       191 
173 
     | 
    
         
             
                  when Hash
         
     | 
| 
       192 
174 
     | 
    
         
             
                    options = args.pop
         
     | 
| 
      
 175 
     | 
    
         
            +
                    output  = options[:output] if options[:output]
         
     | 
| 
       193 
176 
     | 
    
         | 
| 
       194 
     | 
    
         
            -
                     
     | 
| 
      
 177 
     | 
    
         
            +
                    options[:registers]&.each do |key, register|
         
     | 
| 
      
 178 
     | 
    
         
            +
                      context_register[key] = register
         
     | 
| 
      
 179 
     | 
    
         
            +
                    end
         
     | 
| 
       195 
180 
     | 
    
         | 
| 
       196 
181 
     | 
    
         
             
                    apply_options_to_context(context, options)
         
     | 
| 
       197 
182 
     | 
    
         
             
                  when Module, Array
         
     | 
| 
         @@ -201,13 +186,13 @@ module Liquid 
     | 
|
| 
       201 
186 
     | 
    
         
             
                  # Retrying a render resets resource usage
         
     | 
| 
       202 
187 
     | 
    
         
             
                  context.resource_limits.reset
         
     | 
| 
       203 
188 
     | 
    
         | 
| 
      
 189 
     | 
    
         
            +
                  if @profiling && context.profiler.nil?
         
     | 
| 
      
 190 
     | 
    
         
            +
                    @profiler = context.profiler = Liquid::Profiler.new
         
     | 
| 
      
 191 
     | 
    
         
            +
                  end
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
       204 
193 
     | 
    
         
             
                  begin
         
     | 
| 
       205 
194 
     | 
    
         
             
                    # render the nodelist.
         
     | 
| 
       206 
     | 
    
         
            -
                     
     | 
| 
       207 
     | 
    
         
            -
                    result = with_profiling(context) do
         
     | 
| 
       208 
     | 
    
         
            -
                      @root.render(context)
         
     | 
| 
       209 
     | 
    
         
            -
                    end
         
     | 
| 
       210 
     | 
    
         
            -
                    result.respond_to?(:join) ? result.join : result
         
     | 
| 
      
 195 
     | 
    
         
            +
                    @root.render_to_output_buffer(context, output || +'')
         
     | 
| 
       211 
196 
     | 
    
         
             
                  rescue Liquid::MemoryError => e
         
     | 
| 
       212 
197 
     | 
    
         
             
                    context.handle_error(e)
         
     | 
| 
       213 
198 
     | 
    
         
             
                  ensure
         
     | 
| 
         @@ -220,35 +205,31 @@ module Liquid 
     | 
|
| 
       220 
205 
     | 
    
         
             
                  render(*args)
         
     | 
| 
       221 
206 
     | 
    
         
             
                end
         
     | 
| 
       222 
207 
     | 
    
         | 
| 
       223 
     | 
    
         
            -
                 
     | 
| 
       224 
     | 
    
         
            -
             
     | 
| 
       225 
     | 
    
         
            -
                def tokenize(source)
         
     | 
| 
       226 
     | 
    
         
            -
                  Tokenizer.new(source, @line_numbers)
         
     | 
| 
      
 208 
     | 
    
         
            +
                def render_to_output_buffer(context, output)
         
     | 
| 
      
 209 
     | 
    
         
            +
                  render(context, output: output)
         
     | 
| 
       227 
210 
     | 
    
         
             
                end
         
     | 
| 
       228 
211 
     | 
    
         | 
| 
       229 
     | 
    
         
            -
                 
     | 
| 
       230 
     | 
    
         
            -
                  if @profiling && !context.partial
         
     | 
| 
       231 
     | 
    
         
            -
                    raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler)
         
     | 
| 
       232 
     | 
    
         
            -
             
     | 
| 
       233 
     | 
    
         
            -
                    @profiler = Profiler.new
         
     | 
| 
       234 
     | 
    
         
            -
                    @profiler.start
         
     | 
| 
      
 212 
     | 
    
         
            +
                private
         
     | 
| 
       235 
213 
     | 
    
         | 
| 
       236 
     | 
    
         
            -
             
     | 
| 
       237 
     | 
    
         
            -
             
     | 
| 
       238 
     | 
    
         
            -
                     
     | 
| 
       239 
     | 
    
         
            -
                      @profiler.stop
         
     | 
| 
       240 
     | 
    
         
            -
                    end
         
     | 
| 
       241 
     | 
    
         
            -
                  else
         
     | 
| 
       242 
     | 
    
         
            -
                    yield
         
     | 
| 
      
 214 
     | 
    
         
            +
                def configure_options(options)
         
     | 
| 
      
 215 
     | 
    
         
            +
                  if (profiling = options[:profile])
         
     | 
| 
      
 216 
     | 
    
         
            +
                    raise "Profiler not loaded, require 'liquid/profiler' first" unless defined?(Liquid::Profiler)
         
     | 
| 
       243 
217 
     | 
    
         
             
                  end
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
                  @options      = options
         
     | 
| 
      
 220 
     | 
    
         
            +
                  @profiling    = profiling
         
     | 
| 
      
 221 
     | 
    
         
            +
                  @line_numbers = options[:line_numbers] || @profiling
         
     | 
| 
      
 222 
     | 
    
         
            +
                  parse_context = options.is_a?(ParseContext) ? options : ParseContext.new(options)
         
     | 
| 
      
 223 
     | 
    
         
            +
                  @warnings     = parse_context.warnings
         
     | 
| 
      
 224 
     | 
    
         
            +
                  parse_context
         
     | 
| 
       244 
225 
     | 
    
         
             
                end
         
     | 
| 
       245 
226 
     | 
    
         | 
| 
       246 
227 
     | 
    
         
             
                def apply_options_to_context(context, options)
         
     | 
| 
       247 
228 
     | 
    
         
             
                  context.add_filters(options[:filters]) if options[:filters]
         
     | 
| 
       248 
     | 
    
         
            -
                  context.global_filter 
     | 
| 
      
 229 
     | 
    
         
            +
                  context.global_filter      = options[:global_filter] if options[:global_filter]
         
     | 
| 
       249 
230 
     | 
    
         
             
                  context.exception_renderer = options[:exception_renderer] if options[:exception_renderer]
         
     | 
| 
       250 
     | 
    
         
            -
                  context.strict_variables 
     | 
| 
       251 
     | 
    
         
            -
                  context.strict_filters 
     | 
| 
      
 231 
     | 
    
         
            +
                  context.strict_variables   = options[:strict_variables] if options[:strict_variables]
         
     | 
| 
      
 232 
     | 
    
         
            +
                  context.strict_filters     = options[:strict_filters] if options[:strict_filters]
         
     | 
| 
       252 
233 
     | 
    
         
             
                end
         
     | 
| 
       253 
234 
     | 
    
         
             
              end
         
     | 
| 
       254 
235 
     | 
    
         
             
            end
         
     | 
    
        data/lib/liquid/tokenizer.rb
    CHANGED
    
    | 
         @@ -1,29 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
4 
     | 
    
         
             
              class Tokenizer
         
     | 
| 
       3 
     | 
    
         
            -
                attr_reader :line_number
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :line_number, :for_liquid_tag
         
     | 
| 
       4 
6 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
                def initialize(source, line_numbers = false)
         
     | 
| 
       6 
     | 
    
         
            -
                  @source 
     | 
| 
       7 
     | 
    
         
            -
                  @line_number 
     | 
| 
       8 
     | 
    
         
            -
                  @ 
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @source         = source.to_s.to_str
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @line_number    = line_number || (line_numbers ? 1 : nil)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @for_liquid_tag = for_liquid_tag
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @tokens         = tokenize
         
     | 
| 
       9 
12 
     | 
    
         
             
                end
         
     | 
| 
       10 
13 
     | 
    
         | 
| 
       11 
14 
     | 
    
         
             
                def shift
         
     | 
| 
       12 
     | 
    
         
            -
                  token = @tokens.shift
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
      
 15 
     | 
    
         
            +
                  (token = @tokens.shift) || return
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  if @line_number
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @line_number += @for_liquid_tag ? 1 : token.count("\n")
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
       14 
21 
     | 
    
         
             
                  token
         
     | 
| 
       15 
22 
     | 
    
         
             
                end
         
     | 
| 
       16 
23 
     | 
    
         | 
| 
       17 
24 
     | 
    
         
             
                private
         
     | 
| 
       18 
25 
     | 
    
         | 
| 
       19 
26 
     | 
    
         
             
                def tokenize
         
     | 
| 
       20 
     | 
    
         
            -
                   
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
                  return [] if @source.empty?
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  return @source.split("\n") if @for_liquid_tag
         
     | 
| 
       22 
30 
     | 
    
         | 
| 
       23 
31 
     | 
    
         
             
                  tokens = @source.split(TemplateParser)
         
     | 
| 
       24 
32 
     | 
    
         | 
| 
       25 
33 
     | 
    
         
             
                  # removes the rogue empty element at the beginning of the array
         
     | 
| 
       26 
     | 
    
         
            -
                  tokens.shift if tokens[0] 
     | 
| 
      
 34 
     | 
    
         
            +
                  tokens.shift if tokens[0]&.empty?
         
     | 
| 
       27 
35 
     | 
    
         | 
| 
       28 
36 
     | 
    
         
             
                  tokens
         
     | 
| 
       29 
37 
     | 
    
         
             
                end
         
     | 
    
        data/lib/liquid/usage.rb
    ADDED
    
    
    
        data/lib/liquid/utils.rb
    CHANGED
    
    | 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
4 
     | 
    
         
             
              module Utils
         
     | 
| 
       3 
5 
     | 
    
         
             
                def self.slice_collection(collection, from, to)
         
     | 
| 
         @@ -10,7 +12,7 @@ module Liquid 
     | 
|
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
                def self.slice_collection_using_each(collection, from, to)
         
     | 
| 
       12 
14 
     | 
    
         
             
                  segments = []
         
     | 
| 
       13 
     | 
    
         
            -
                  index 
     | 
| 
      
 15 
     | 
    
         
            +
                  index    = 0
         
     | 
| 
       14 
16 
     | 
    
         | 
| 
       15 
17 
     | 
    
         
             
                  # Maintains Ruby 1.8.7 String#each behaviour on 1.9
         
     | 
| 
       16 
18 
     | 
    
         
             
                  if collection.is_a?(String)
         
     | 
| 
         @@ -50,7 +52,7 @@ module Liquid 
     | 
|
| 
       50 
52 
     | 
    
         
             
                  when Numeric
         
     | 
| 
       51 
53 
     | 
    
         
             
                    obj
         
     | 
| 
       52 
54 
     | 
    
         
             
                  when String
         
     | 
| 
       53 
     | 
    
         
            -
                     
     | 
| 
      
 55 
     | 
    
         
            +
                    /\A-?\d+\.\d+\z/.match?(obj.strip) ? BigDecimal(obj) : obj.to_i
         
     | 
| 
       54 
56 
     | 
    
         
             
                  else
         
     | 
| 
       55 
57 
     | 
    
         
             
                    if obj.respond_to?(:to_number)
         
     | 
| 
       56 
58 
     | 
    
         
             
                      obj.to_number
         
     | 
| 
         @@ -69,7 +71,7 @@ module Liquid 
     | 
|
| 
       69 
71 
     | 
    
         
             
                  end
         
     | 
| 
       70 
72 
     | 
    
         | 
| 
       71 
73 
     | 
    
         
             
                  case obj
         
     | 
| 
       72 
     | 
    
         
            -
                  when 'now' 
     | 
| 
      
 74 
     | 
    
         
            +
                  when 'now', 'today'
         
     | 
| 
       73 
75 
     | 
    
         
             
                    Time.now
         
     | 
| 
       74 
76 
     | 
    
         
             
                  when /\A\d+\z/, Integer
         
     | 
| 
       75 
77 
     | 
    
         
             
                    Time.at(obj.to_i)
         
     | 
| 
         @@ -79,5 +81,13 @@ module Liquid 
     | 
|
| 
       79 
81 
     | 
    
         
             
                rescue ::ArgumentError
         
     | 
| 
       80 
82 
     | 
    
         
             
                  nil
         
     | 
| 
       81 
83 
     | 
    
         
             
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def self.to_liquid_value(obj)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  # Enable "obj" to represent itself as a primitive value like integer, string, or boolean
         
     | 
| 
      
 87 
     | 
    
         
            +
                  return obj.to_liquid_value if obj.respond_to?(:to_liquid_value)
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  # Otherwise return the object itself
         
     | 
| 
      
 90 
     | 
    
         
            +
                  obj
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
       82 
92 
     | 
    
         
             
              end
         
     | 
| 
       83 
93 
     | 
    
         
             
            end
         
     | 
    
        data/lib/liquid/variable.rb
    CHANGED
    
    | 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
4 
     | 
    
         
             
              # Holds variables. Variables are only loaded "just in time"
         
     | 
| 
       3 
5 
     | 
    
         
             
              # and are not evaluated as part of the render stage
         
     | 
| 
         @@ -10,10 +12,10 @@ module Liquid 
     | 
|
| 
       10 
12 
     | 
    
         
             
              #   {{ user | link }}
         
     | 
| 
       11 
13 
     | 
    
         
             
              #
         
     | 
| 
       12 
14 
     | 
    
         
             
              class Variable
         
     | 
| 
       13 
     | 
    
         
            -
                FilterMarkupRegex 
     | 
| 
       14 
     | 
    
         
            -
                FilterParser 
     | 
| 
       15 
     | 
    
         
            -
                FilterArgsRegex 
     | 
| 
       16 
     | 
    
         
            -
                JustTagAttributes 
     | 
| 
      
 15 
     | 
    
         
            +
                FilterMarkupRegex        = /#{FilterSeparator}\s*(.*)/om
         
     | 
| 
      
 16 
     | 
    
         
            +
                FilterParser             = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o
         
     | 
| 
      
 17 
     | 
    
         
            +
                FilterArgsRegex          = /(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o
         
     | 
| 
      
 18 
     | 
    
         
            +
                JustTagAttributes        = /\A#{TagAttributes}\z/o
         
     | 
| 
       17 
19 
     | 
    
         
             
                MarkupWithQuotedFragment = /(#{QuotedFragment})(.*)/om
         
     | 
| 
       18 
20 
     | 
    
         | 
| 
       19 
21 
     | 
    
         
             
                attr_accessor :filters, :name, :line_number
         
     | 
| 
         @@ -23,12 +25,12 @@ module Liquid 
     | 
|
| 
       23 
25 
     | 
    
         
             
                include ParserSwitching
         
     | 
| 
       24 
26 
     | 
    
         | 
| 
       25 
27 
     | 
    
         
             
                def initialize(markup, parse_context)
         
     | 
| 
       26 
     | 
    
         
            -
                  @markup 
     | 
| 
       27 
     | 
    
         
            -
                  @name 
     | 
| 
      
 28 
     | 
    
         
            +
                  @markup        = markup
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @name          = nil
         
     | 
| 
       28 
30 
     | 
    
         
             
                  @parse_context = parse_context
         
     | 
| 
       29 
     | 
    
         
            -
                  @line_number 
     | 
| 
      
 31 
     | 
    
         
            +
                  @line_number   = parse_context.line_number
         
     | 
| 
       30 
32 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
                   
     | 
| 
      
 33 
     | 
    
         
            +
                  strict_parse_with_error_mode_fallback(markup)
         
     | 
| 
       32 
34 
     | 
    
         
             
                end
         
     | 
| 
       33 
35 
     | 
    
         | 
| 
       34 
36 
     | 
    
         
             
                def raw
         
     | 
| 
         @@ -43,11 +45,11 @@ module Liquid 
     | 
|
| 
       43 
45 
     | 
    
         
             
                  @filters = []
         
     | 
| 
       44 
46 
     | 
    
         
             
                  return unless markup =~ MarkupWithQuotedFragment
         
     | 
| 
       45 
47 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
                  name_markup 
     | 
| 
       47 
     | 
    
         
            -
                  filter_markup =  
     | 
| 
       48 
     | 
    
         
            -
                  @name 
     | 
| 
      
 48 
     | 
    
         
            +
                  name_markup   = Regexp.last_match(1)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  filter_markup = Regexp.last_match(2)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  @name         = Expression.parse(name_markup)
         
     | 
| 
       49 
51 
     | 
    
         
             
                  if filter_markup =~ FilterMarkupRegex
         
     | 
| 
       50 
     | 
    
         
            -
                    filters =  
     | 
| 
      
 52 
     | 
    
         
            +
                    filters = Regexp.last_match(1).scan(FilterParser)
         
     | 
| 
       51 
53 
     | 
    
         
             
                    filters.each do |f|
         
     | 
| 
       52 
54 
     | 
    
         
             
                      next unless f =~ /\w+/
         
     | 
| 
       53 
55 
     | 
    
         
             
                      filtername = Regexp.last_match(0)
         
     | 
| 
         @@ -61,6 +63,8 @@ module Liquid 
     | 
|
| 
       61 
63 
     | 
    
         
             
                  @filters = []
         
     | 
| 
       62 
64 
     | 
    
         
             
                  p = Parser.new(markup)
         
     | 
| 
       63 
65 
     | 
    
         | 
| 
      
 66 
     | 
    
         
            +
                  return if p.look(:end_of_string)
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
       64 
68 
     | 
    
         
             
                  @name = Expression.parse(p.expression)
         
     | 
| 
       65 
69 
     | 
    
         
             
                  while p.consume?(:pipe)
         
     | 
| 
       66 
70 
     | 
    
         
             
                    filtername = p.consume(:id)
         
     | 
| 
         @@ -79,37 +83,57 @@ module Liquid 
     | 
|
| 
       79 
83 
     | 
    
         
             
                end
         
     | 
| 
       80 
84 
     | 
    
         | 
| 
       81 
85 
     | 
    
         
             
                def render(context)
         
     | 
| 
       82 
     | 
    
         
            -
                  obj =  
     | 
| 
      
 86 
     | 
    
         
            +
                  obj = context.evaluate(@name)
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  @filters.each do |filter_name, filter_args, filter_kwargs|
         
     | 
| 
       83 
89 
     | 
    
         
             
                    filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs)
         
     | 
| 
       84 
     | 
    
         
            -
                    context.invoke(filter_name,  
     | 
| 
      
 90 
     | 
    
         
            +
                    obj = context.invoke(filter_name, obj, *filter_args)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                  context.apply_global_filter(obj)
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                def render_to_output_buffer(context, output)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  obj = render(context)
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  if obj.is_a?(Array)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    output << obj.join
         
     | 
| 
      
 101 
     | 
    
         
            +
                  elsif obj.nil?
         
     | 
| 
      
 102 
     | 
    
         
            +
                  else
         
     | 
| 
      
 103 
     | 
    
         
            +
                    output << obj.to_s
         
     | 
| 
       85 
104 
     | 
    
         
             
                  end
         
     | 
| 
       86 
105 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
                   
     | 
| 
      
 106 
     | 
    
         
            +
                  output
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
       88 
108 
     | 
    
         | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
      
 109 
     | 
    
         
            +
                def disabled?(_context)
         
     | 
| 
      
 110 
     | 
    
         
            +
                  false
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
       90 
112 
     | 
    
         | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
      
 113 
     | 
    
         
            +
                def disabled_tags
         
     | 
| 
      
 114 
     | 
    
         
            +
                  []
         
     | 
| 
       92 
115 
     | 
    
         
             
                end
         
     | 
| 
       93 
116 
     | 
    
         | 
| 
       94 
117 
     | 
    
         
             
                private
         
     | 
| 
       95 
118 
     | 
    
         | 
| 
       96 
119 
     | 
    
         
             
                def parse_filter_expressions(filter_name, unparsed_args)
         
     | 
| 
       97 
     | 
    
         
            -
                  filter_args 
     | 
| 
       98 
     | 
    
         
            -
                  keyword_args =  
     | 
| 
      
 120 
     | 
    
         
            +
                  filter_args  = []
         
     | 
| 
      
 121 
     | 
    
         
            +
                  keyword_args = nil
         
     | 
| 
       99 
122 
     | 
    
         
             
                  unparsed_args.each do |a|
         
     | 
| 
       100 
     | 
    
         
            -
                    if matches = a.match(JustTagAttributes)
         
     | 
| 
      
 123 
     | 
    
         
            +
                    if (matches = a.match(JustTagAttributes))
         
     | 
| 
      
 124 
     | 
    
         
            +
                      keyword_args           ||= {}
         
     | 
| 
       101 
125 
     | 
    
         
             
                      keyword_args[matches[1]] = Expression.parse(matches[2])
         
     | 
| 
       102 
126 
     | 
    
         
             
                    else
         
     | 
| 
       103 
127 
     | 
    
         
             
                      filter_args << Expression.parse(a)
         
     | 
| 
       104 
128 
     | 
    
         
             
                    end
         
     | 
| 
       105 
129 
     | 
    
         
             
                  end
         
     | 
| 
       106 
130 
     | 
    
         
             
                  result = [filter_name, filter_args]
         
     | 
| 
       107 
     | 
    
         
            -
                  result << keyword_args  
     | 
| 
      
 131 
     | 
    
         
            +
                  result << keyword_args if keyword_args
         
     | 
| 
       108 
132 
     | 
    
         
             
                  result
         
     | 
| 
       109 
133 
     | 
    
         
             
                end
         
     | 
| 
       110 
134 
     | 
    
         | 
| 
       111 
135 
     | 
    
         
             
                def evaluate_filter_expressions(context, filter_args, filter_kwargs)
         
     | 
| 
       112 
     | 
    
         
            -
                  parsed_args = filter_args.map{ |expr| context.evaluate(expr) }
         
     | 
| 
      
 136 
     | 
    
         
            +
                  parsed_args = filter_args.map { |expr| context.evaluate(expr) }
         
     | 
| 
       113 
137 
     | 
    
         
             
                  if filter_kwargs
         
     | 
| 
       114 
138 
     | 
    
         
             
                    parsed_kwargs = {}
         
     | 
| 
       115 
139 
     | 
    
         
             
                    filter_kwargs.each do |key, expr|
         
     | 
| 
         @@ -120,25 +144,6 @@ module Liquid 
     | 
|
| 
       120 
144 
     | 
    
         
             
                  parsed_args
         
     | 
| 
       121 
145 
     | 
    
         
             
                end
         
     | 
| 
       122 
146 
     | 
    
         | 
| 
       123 
     | 
    
         
            -
                def taint_check(context, obj)
         
     | 
| 
       124 
     | 
    
         
            -
                  return unless obj.tainted?
         
     | 
| 
       125 
     | 
    
         
            -
                  return if Template.taint_mode == :lax
         
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
                  @markup =~ QuotedFragment
         
     | 
| 
       128 
     | 
    
         
            -
                  name = Regexp.last_match(0)
         
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
                  error = TaintedError.new("variable '#{name}' is tainted and was not escaped")
         
     | 
| 
       131 
     | 
    
         
            -
                  error.line_number = line_number
         
     | 
| 
       132 
     | 
    
         
            -
                  error.template_name = context.template_name
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
     | 
    
         
            -
                  case Template.taint_mode
         
     | 
| 
       135 
     | 
    
         
            -
                  when :warn
         
     | 
| 
       136 
     | 
    
         
            -
                    context.warnings << error
         
     | 
| 
       137 
     | 
    
         
            -
                  when :error
         
     | 
| 
       138 
     | 
    
         
            -
                    raise error
         
     | 
| 
       139 
     | 
    
         
            -
                  end
         
     | 
| 
       140 
     | 
    
         
            -
                end
         
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
147 
     | 
    
         
             
                class ParseTreeVisitor < Liquid::ParseTreeVisitor
         
     | 
| 
       143 
148 
     | 
    
         
             
                  def children
         
     | 
| 
       144 
149 
     | 
    
         
             
                    [@node.name] + @node.filters.flatten
         
     | 
| 
         @@ -1,7 +1,9 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
4 
     | 
    
         
             
              class VariableLookup
         
     | 
| 
       3 
5 
     | 
    
         
             
                SQUARE_BRACKETED = /\A\[(.*)\]\z/m
         
     | 
| 
       4 
     | 
    
         
            -
                COMMAND_METHODS 
     | 
| 
      
 6 
     | 
    
         
            +
                COMMAND_METHODS  = ['size', 'first', 'last'].freeze
         
     | 
| 
       5 
7 
     | 
    
         | 
| 
       6 
8 
     | 
    
         
             
                attr_reader :name, :lookups
         
     | 
| 
       7 
9 
     | 
    
         | 
| 
         @@ -14,17 +16,17 @@ module Liquid 
     | 
|
| 
       14 
16 
     | 
    
         | 
| 
       15 
17 
     | 
    
         
             
                  name = lookups.shift
         
     | 
| 
       16 
18 
     | 
    
         
             
                  if name =~ SQUARE_BRACKETED
         
     | 
| 
       17 
     | 
    
         
            -
                    name = Expression.parse( 
     | 
| 
      
 19 
     | 
    
         
            +
                    name = Expression.parse(Regexp.last_match(1))
         
     | 
| 
       18 
20 
     | 
    
         
             
                  end
         
     | 
| 
       19 
21 
     | 
    
         
             
                  @name = name
         
     | 
| 
       20 
22 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                  @lookups 
     | 
| 
      
 23 
     | 
    
         
            +
                  @lookups       = lookups
         
     | 
| 
       22 
24 
     | 
    
         
             
                  @command_flags = 0
         
     | 
| 
       23 
25 
     | 
    
         | 
| 
       24 
26 
     | 
    
         
             
                  @lookups.each_index do |i|
         
     | 
| 
       25 
27 
     | 
    
         
             
                    lookup = lookups[i]
         
     | 
| 
       26 
28 
     | 
    
         
             
                    if lookup =~ SQUARE_BRACKETED
         
     | 
| 
       27 
     | 
    
         
            -
                      lookups[i] = Expression.parse( 
     | 
| 
      
 29 
     | 
    
         
            +
                      lookups[i] = Expression.parse(Regexp.last_match(1))
         
     | 
| 
       28 
30 
     | 
    
         
             
                    elsif COMMAND_METHODS.include?(lookup)
         
     | 
| 
       29 
31 
     | 
    
         
             
                      @command_flags |= 1 << i
         
     | 
| 
       30 
32 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -32,12 +34,15 @@ module Liquid 
     | 
|
| 
       32 
34 
     | 
    
         
             
                end
         
     | 
| 
       33 
35 
     | 
    
         | 
| 
       34 
36 
     | 
    
         
             
                def evaluate(context)
         
     | 
| 
       35 
     | 
    
         
            -
                  name 
     | 
| 
      
 37 
     | 
    
         
            +
                  name   = context.evaluate(@name)
         
     | 
| 
       36 
38 
     | 
    
         
             
                  object = context.find_variable(name)
         
     | 
| 
       37 
39 
     | 
    
         | 
| 
       38 
40 
     | 
    
         
             
                  @lookups.each_index do |i|
         
     | 
| 
       39 
41 
     | 
    
         
             
                    key = context.evaluate(@lookups[i])
         
     | 
| 
       40 
42 
     | 
    
         | 
| 
      
 43 
     | 
    
         
            +
                    # Cast "key" to its liquid value to enable it to act as a primitive value
         
     | 
| 
      
 44 
     | 
    
         
            +
                    key = Liquid::Utils.to_liquid_value(key)
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
       41 
46 
     | 
    
         
             
                    # If object is a hash- or array-like object we look for the
         
     | 
| 
       42 
47 
     | 
    
         
             
                    # presence of the key and if its available we return it
         
     | 
| 
       43 
48 
     | 
    
         
             
                    if object.respond_to?(:[]) &&
         
     | 
| 
         @@ -45,7 +50,7 @@ module Liquid 
     | 
|
| 
       45 
50 
     | 
    
         
             
                         (object.respond_to?(:fetch) && key.is_a?(Integer)))
         
     | 
| 
       46 
51 
     | 
    
         | 
| 
       47 
52 
     | 
    
         
             
                      # if its a proc we will replace the entry with the proc
         
     | 
| 
       48 
     | 
    
         
            -
                      res 
     | 
| 
      
 53 
     | 
    
         
            +
                      res    = context.lookup_and_evaluate(object, key)
         
     | 
| 
       49 
54 
     | 
    
         
             
                      object = res.to_liquid
         
     | 
| 
       50 
55 
     | 
    
         | 
| 
       51 
56 
     | 
    
         
             
                      # Some special cases. If the part wasn't in square brackets and
         
     | 
    
        data/lib/liquid/version.rb
    CHANGED
    
    
    
        data/lib/liquid.rb
    CHANGED
    
    | 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            # Copyright (c) 2005 Tobias Luetke
         
     | 
| 
       2 
4 
     | 
    
         
             
            #
         
     | 
| 
       3 
5 
     | 
    
         
             
            # Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
         @@ -21,10 +23,10 @@ 
     | 
|
| 
       21 
23 
     | 
    
         | 
| 
       22 
24 
     | 
    
         
             
            module Liquid
         
     | 
| 
       23 
25 
     | 
    
         
             
              FilterSeparator             = /\|/
         
     | 
| 
       24 
     | 
    
         
            -
              ArgumentSeparator           = ',' 
     | 
| 
       25 
     | 
    
         
            -
              FilterArgumentSeparator     = ':' 
     | 
| 
       26 
     | 
    
         
            -
              VariableAttributeSeparator  = '.' 
     | 
| 
       27 
     | 
    
         
            -
              WhitespaceControl           = '-' 
     | 
| 
      
 26 
     | 
    
         
            +
              ArgumentSeparator           = ','
         
     | 
| 
      
 27 
     | 
    
         
            +
              FilterArgumentSeparator     = ':'
         
     | 
| 
      
 28 
     | 
    
         
            +
              VariableAttributeSeparator  = '.'
         
     | 
| 
      
 29 
     | 
    
         
            +
              WhitespaceControl           = '-'
         
     | 
| 
       28 
30 
     | 
    
         
             
              TagStart                    = /\{\%/
         
     | 
| 
       29 
31 
     | 
    
         
             
              TagEnd                      = /\%\}/
         
     | 
| 
       30 
32 
     | 
    
         
             
              VariableSignature           = /\(?[\w\-\.\[\]]\)?/
         
     | 
| 
         @@ -40,6 +42,8 @@ module Liquid 
     | 
|
| 
       40 
42 
     | 
    
         
             
              TemplateParser              = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
         
     | 
| 
       41 
43 
     | 
    
         
             
              VariableParser              = /\[[^\]]+\]|#{VariableSegment}+\??/o
         
     | 
| 
       42 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
              RAISE_EXCEPTION_LAMBDA = ->(_e) { raise }
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       43 
47 
     | 
    
         
             
              singleton_class.send(:attr_accessor, :cache_classes)
         
     | 
| 
       44 
48 
     | 
    
         
             
              self.cache_classes = true
         
     | 
| 
       45 
49 
     | 
    
         
             
            end
         
     | 
| 
         @@ -55,11 +59,14 @@ require 'liquid/forloop_drop' 
     | 
|
| 
       55 
59 
     | 
    
         
             
            require 'liquid/extensions'
         
     | 
| 
       56 
60 
     | 
    
         
             
            require 'liquid/errors'
         
     | 
| 
       57 
61 
     | 
    
         
             
            require 'liquid/interrupts'
         
     | 
| 
       58 
     | 
    
         
            -
            require 'liquid/ 
     | 
| 
      
 62 
     | 
    
         
            +
            require 'liquid/strainer_factory'
         
     | 
| 
      
 63 
     | 
    
         
            +
            require 'liquid/strainer_template'
         
     | 
| 
       59 
64 
     | 
    
         
             
            require 'liquid/expression'
         
     | 
| 
       60 
65 
     | 
    
         
             
            require 'liquid/context'
         
     | 
| 
       61 
66 
     | 
    
         
             
            require 'liquid/parser_switching'
         
     | 
| 
       62 
67 
     | 
    
         
             
            require 'liquid/tag'
         
     | 
| 
      
 68 
     | 
    
         
            +
            require 'liquid/tag/disabler'
         
     | 
| 
      
 69 
     | 
    
         
            +
            require 'liquid/tag/disableable'
         
     | 
| 
       63 
70 
     | 
    
         
             
            require 'liquid/block'
         
     | 
| 
       64 
71 
     | 
    
         
             
            require 'liquid/block_body'
         
     | 
| 
       65 
72 
     | 
    
         
             
            require 'liquid/document'
         
     | 
| 
         @@ -74,6 +81,11 @@ require 'liquid/condition' 
     | 
|
| 
       74 
81 
     | 
    
         
             
            require 'liquid/utils'
         
     | 
| 
       75 
82 
     | 
    
         
             
            require 'liquid/tokenizer'
         
     | 
| 
       76 
83 
     | 
    
         
             
            require 'liquid/parse_context'
         
     | 
| 
      
 84 
     | 
    
         
            +
            require 'liquid/partial_cache'
         
     | 
| 
      
 85 
     | 
    
         
            +
            require 'liquid/usage'
         
     | 
| 
      
 86 
     | 
    
         
            +
            require 'liquid/register'
         
     | 
| 
      
 87 
     | 
    
         
            +
            require 'liquid/static_registers'
         
     | 
| 
      
 88 
     | 
    
         
            +
            require 'liquid/template_factory'
         
     | 
| 
       77 
89 
     | 
    
         | 
| 
       78 
90 
     | 
    
         
             
            # Load all the tags of the standard library
         
     | 
| 
       79 
91 
     | 
    
         
             
            #
         
     |