liquid 3.0.6 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
 - data/History.md +243 -58
 - data/README.md +43 -4
 - data/lib/liquid/block.rb +57 -123
 - data/lib/liquid/block_body.rb +217 -85
 - data/lib/liquid/condition.rb +92 -45
 - data/lib/liquid/context.rb +154 -89
 - data/lib/liquid/document.rb +57 -9
 - data/lib/liquid/drop.rb +20 -17
 - data/lib/liquid/errors.rb +27 -29
 - data/lib/liquid/expression.rb +32 -20
 - data/lib/liquid/extensions.rb +21 -7
 - data/lib/liquid/file_system.rb +17 -15
 - data/lib/liquid/forloop_drop.rb +92 -0
 - data/lib/liquid/i18n.rb +10 -8
 - data/lib/liquid/interrupts.rb +4 -3
 - data/lib/liquid/lexer.rb +37 -26
 - data/lib/liquid/locales/en.yml +13 -6
 - data/lib/liquid/parse_context.rb +54 -0
 - data/lib/liquid/parse_tree_visitor.rb +42 -0
 - data/lib/liquid/parser.rb +30 -18
 - data/lib/liquid/parser_switching.rb +20 -6
 - data/lib/liquid/partial_cache.rb +24 -0
 - data/lib/liquid/profiler/hooks.rb +26 -14
 - data/lib/liquid/profiler.rb +72 -92
 - data/lib/liquid/range_lookup.rb +28 -3
 - data/lib/liquid/registers.rb +51 -0
 - data/lib/liquid/resource_limits.rb +62 -0
 - data/lib/liquid/standardfilters.rb +715 -132
 - data/lib/liquid/strainer_factory.rb +41 -0
 - data/lib/liquid/strainer_template.rb +62 -0
 - data/lib/liquid/tablerowloop_drop.rb +121 -0
 - data/lib/liquid/tag/disableable.rb +22 -0
 - data/lib/liquid/tag/disabler.rb +21 -0
 - data/lib/liquid/tag.rb +35 -12
 - data/lib/liquid/tags/assign.rb +57 -18
 - data/lib/liquid/tags/break.rb +15 -5
 - data/lib/liquid/tags/capture.rb +24 -18
 - data/lib/liquid/tags/case.rb +79 -30
 - data/lib/liquid/tags/comment.rb +19 -4
 - data/lib/liquid/tags/continue.rb +16 -12
 - data/lib/liquid/tags/cycle.rb +47 -27
 - data/lib/liquid/tags/decrement.rb +23 -24
 - data/lib/liquid/tags/echo.rb +41 -0
 - data/lib/liquid/tags/for.rb +155 -124
 - data/lib/liquid/tags/if.rb +97 -63
 - data/lib/liquid/tags/ifchanged.rb +11 -12
 - data/lib/liquid/tags/include.rb +82 -73
 - data/lib/liquid/tags/increment.rb +23 -17
 - data/lib/liquid/tags/inline_comment.rb +43 -0
 - data/lib/liquid/tags/raw.rb +50 -8
 - data/lib/liquid/tags/render.rb +109 -0
 - data/lib/liquid/tags/table_row.rb +57 -41
 - data/lib/liquid/tags/unless.rb +38 -20
 - data/lib/liquid/template.rb +71 -103
 - data/lib/liquid/template_factory.rb +9 -0
 - data/lib/liquid/tokenizer.rb +39 -0
 - data/lib/liquid/usage.rb +8 -0
 - data/lib/liquid/utils.rb +63 -9
 - data/lib/liquid/variable.rb +74 -56
 - data/lib/liquid/variable_lookup.rb +31 -15
 - data/lib/liquid/version.rb +3 -1
 - data/lib/liquid.rb +27 -12
 - metadata +30 -106
 - data/lib/liquid/module_ex.rb +0 -62
 - data/lib/liquid/strainer.rb +0 -59
 - data/lib/liquid/token.rb +0 -18
 - data/test/fixtures/en_locale.yml +0 -9
 - data/test/integration/assign_test.rb +0 -48
 - data/test/integration/blank_test.rb +0 -106
 - data/test/integration/capture_test.rb +0 -50
 - data/test/integration/context_test.rb +0 -32
 - data/test/integration/drop_test.rb +0 -271
 - data/test/integration/error_handling_test.rb +0 -207
 - data/test/integration/filter_test.rb +0 -138
 - data/test/integration/hash_ordering_test.rb +0 -23
 - data/test/integration/output_test.rb +0 -124
 - data/test/integration/parsing_quirks_test.rb +0 -116
 - data/test/integration/render_profiling_test.rb +0 -154
 - data/test/integration/security_test.rb +0 -64
 - data/test/integration/standard_filter_test.rb +0 -396
 - data/test/integration/tags/break_tag_test.rb +0 -16
 - data/test/integration/tags/continue_tag_test.rb +0 -16
 - data/test/integration/tags/for_tag_test.rb +0 -375
 - data/test/integration/tags/if_else_tag_test.rb +0 -190
 - data/test/integration/tags/include_tag_test.rb +0 -234
 - data/test/integration/tags/increment_tag_test.rb +0 -24
 - data/test/integration/tags/raw_tag_test.rb +0 -25
 - data/test/integration/tags/standard_tag_test.rb +0 -297
 - data/test/integration/tags/statements_test.rb +0 -113
 - data/test/integration/tags/table_row_test.rb +0 -63
 - data/test/integration/tags/unless_else_tag_test.rb +0 -26
 - data/test/integration/template_test.rb +0 -182
 - data/test/integration/variable_test.rb +0 -82
 - data/test/test_helper.rb +0 -89
 - data/test/unit/block_unit_test.rb +0 -55
 - data/test/unit/condition_unit_test.rb +0 -149
 - data/test/unit/context_unit_test.rb +0 -492
 - data/test/unit/file_system_unit_test.rb +0 -35
 - data/test/unit/i18n_unit_test.rb +0 -37
 - data/test/unit/lexer_unit_test.rb +0 -48
 - data/test/unit/module_ex_unit_test.rb +0 -87
 - data/test/unit/parser_unit_test.rb +0 -82
 - data/test/unit/regexp_unit_test.rb +0 -44
 - data/test/unit/strainer_unit_test.rb +0 -69
 - data/test/unit/tag_unit_test.rb +0 -16
 - data/test/unit/tags/case_tag_unit_test.rb +0 -10
 - data/test/unit/tags/for_tag_unit_test.rb +0 -13
 - data/test/unit/tags/if_tag_unit_test.rb +0 -8
 - data/test/unit/template_unit_test.rb +0 -69
 - data/test/unit/tokenizer_unit_test.rb +0 -38
 - data/test/unit/variable_unit_test.rb +0 -145
 - /data/{MIT-LICENSE → LICENSE} +0 -0
 
| 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Liquid
         
     | 
| 
      
 4 
     | 
    
         
            +
              # StrainerFactory is the factory for the filters system.
         
     | 
| 
      
 5 
     | 
    
         
            +
              module StrainerFactory
         
     | 
| 
      
 6 
     | 
    
         
            +
                extend self
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def add_global_filter(filter)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  strainer_class_cache.clear
         
     | 
| 
      
 10 
     | 
    
         
            +
                  GlobalCache.add_filter(filter)
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def create(context, filters = [])
         
     | 
| 
      
 14 
     | 
    
         
            +
                  strainer_from_cache(filters).new(context)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def global_filter_names
         
     | 
| 
      
 18 
     | 
    
         
            +
                  GlobalCache.filter_method_names
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                GlobalCache = Class.new(StrainerTemplate)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                private
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def strainer_from_cache(filters)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  if filters.empty?
         
     | 
| 
      
 27 
     | 
    
         
            +
                    GlobalCache
         
     | 
| 
      
 28 
     | 
    
         
            +
                  else
         
     | 
| 
      
 29 
     | 
    
         
            +
                    strainer_class_cache[filters] ||= begin
         
     | 
| 
      
 30 
     | 
    
         
            +
                      klass = Class.new(GlobalCache)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      filters.each { |f| klass.add_filter(f) }
         
     | 
| 
      
 32 
     | 
    
         
            +
                      klass
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def strainer_class_cache
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @strainer_class_cache ||= {}
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,62 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'set'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Liquid
         
     | 
| 
      
 6 
     | 
    
         
            +
              # StrainerTemplate is the computed class for the filters system.
         
     | 
| 
      
 7 
     | 
    
         
            +
              # New filters are mixed into the strainer class which is then instantiated for each liquid template render run.
         
     | 
| 
      
 8 
     | 
    
         
            +
              #
         
     | 
| 
      
 9 
     | 
    
         
            +
              # The Strainer only allows method calls defined in filters given to it via StrainerFactory.add_global_filter,
         
     | 
| 
      
 10 
     | 
    
         
            +
              # Context#add_filters or Template.register_filter
         
     | 
| 
      
 11 
     | 
    
         
            +
              class StrainerTemplate
         
     | 
| 
      
 12 
     | 
    
         
            +
                def initialize(context)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @context = context
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def add_filter(filter)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    return if include?(filter)
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    invokable_non_public_methods = (filter.private_instance_methods + filter.protected_instance_methods).select { |m| invokable?(m) }
         
     | 
| 
      
 21 
     | 
    
         
            +
                    if invokable_non_public_methods.any?
         
     | 
| 
      
 22 
     | 
    
         
            +
                      raise MethodOverrideError, "Filter overrides registered public methods as non public: #{invokable_non_public_methods.join(', ')}"
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    include(filter)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    filter_methods.merge(filter.public_instance_methods.map(&:to_s))
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def invokable?(method)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    filter_methods.include?(method.to_s)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  def inherited(subclass)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    super
         
     | 
| 
      
 36 
     | 
    
         
            +
                    subclass.instance_variable_set(:@filter_methods, @filter_methods.dup)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def filter_method_names
         
     | 
| 
      
 40 
     | 
    
         
            +
                    filter_methods.map(&:to_s).to_a
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  private
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def filter_methods
         
     | 
| 
      
 46 
     | 
    
         
            +
                    @filter_methods ||= Set.new
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def invoke(method, *args)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  if self.class.invokable?(method)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    send(method, *args)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  elsif @context.strict_filters
         
     | 
| 
      
 54 
     | 
    
         
            +
                    raise Liquid::UndefinedFilter, "undefined filter #{method}"
         
     | 
| 
      
 55 
     | 
    
         
            +
                  else
         
     | 
| 
      
 56 
     | 
    
         
            +
                    args.first
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                rescue ::ArgumentError => e
         
     | 
| 
      
 59 
     | 
    
         
            +
                  raise Liquid::ArgumentError, e.message, e.backtrace
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,121 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Liquid
         
     | 
| 
      
 4 
     | 
    
         
            +
              # @liquid_public_docs
         
     | 
| 
      
 5 
     | 
    
         
            +
              # @liquid_type object
         
     | 
| 
      
 6 
     | 
    
         
            +
              # @liquid_name tablerowloop
         
     | 
| 
      
 7 
     | 
    
         
            +
              # @liquid_summary
         
     | 
| 
      
 8 
     | 
    
         
            +
              #   Information about a parent [`tablerow` loop](/api/liquid/tags#tablerow).
         
     | 
| 
      
 9 
     | 
    
         
            +
              class TablerowloopDrop < Drop
         
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize(length, cols)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @length = length
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @row    = 1
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @col    = 1
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @cols   = cols
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @index  = 0
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 20 
     | 
    
         
            +
                #   The total number of iterations in the loop.
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @liquid_return [number]
         
     | 
| 
      
 22 
     | 
    
         
            +
                attr_reader :length
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 25 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 26 
     | 
    
         
            +
                #   The 1-based index of the current column.
         
     | 
| 
      
 27 
     | 
    
         
            +
                # @liquid_return [number]
         
     | 
| 
      
 28 
     | 
    
         
            +
                attr_reader :col
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 31 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 32 
     | 
    
         
            +
                #   The 1-based index of current row.
         
     | 
| 
      
 33 
     | 
    
         
            +
                # @liquid_return [number]
         
     | 
| 
      
 34 
     | 
    
         
            +
                attr_reader :row
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 37 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 38 
     | 
    
         
            +
                #   The 1-based index of the current iteration.
         
     | 
| 
      
 39 
     | 
    
         
            +
                # @liquid_return [number]
         
     | 
| 
      
 40 
     | 
    
         
            +
                def index
         
     | 
| 
      
 41 
     | 
    
         
            +
                  @index + 1
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 45 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 46 
     | 
    
         
            +
                #   The 0-based index of the current iteration.
         
     | 
| 
      
 47 
     | 
    
         
            +
                # @liquid_return [number]
         
     | 
| 
      
 48 
     | 
    
         
            +
                def index0
         
     | 
| 
      
 49 
     | 
    
         
            +
                  @index
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 53 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 54 
     | 
    
         
            +
                #   The 0-based index of the current column.
         
     | 
| 
      
 55 
     | 
    
         
            +
                # @liquid_return [number]
         
     | 
| 
      
 56 
     | 
    
         
            +
                def col0
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @col - 1
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 61 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 62 
     | 
    
         
            +
                #   The 1-based index of the current iteration, in reverse order.
         
     | 
| 
      
 63 
     | 
    
         
            +
                # @liquid_return [number]
         
     | 
| 
      
 64 
     | 
    
         
            +
                def rindex
         
     | 
| 
      
 65 
     | 
    
         
            +
                  @length - @index
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 69 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 70 
     | 
    
         
            +
                #   The 0-based index of the current iteration, in reverse order.
         
     | 
| 
      
 71 
     | 
    
         
            +
                # @liquid_return [number]
         
     | 
| 
      
 72 
     | 
    
         
            +
                def rindex0
         
     | 
| 
      
 73 
     | 
    
         
            +
                  @length - @index - 1
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 77 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 78 
     | 
    
         
            +
                #   Returns `true` if the current iteration is the first. Returns `false` if not.
         
     | 
| 
      
 79 
     | 
    
         
            +
                # @liquid_return [boolean]
         
     | 
| 
      
 80 
     | 
    
         
            +
                def first
         
     | 
| 
      
 81 
     | 
    
         
            +
                  @index == 0
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 85 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 86 
     | 
    
         
            +
                #   Returns `true` if the current iteration is the last. Returns `false` if not.
         
     | 
| 
      
 87 
     | 
    
         
            +
                # @liquid_return [boolean]
         
     | 
| 
      
 88 
     | 
    
         
            +
                def last
         
     | 
| 
      
 89 
     | 
    
         
            +
                  @index == @length - 1
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 93 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 94 
     | 
    
         
            +
                #   Returns `true` if the current column is the first in the row. Returns `false` if not.
         
     | 
| 
      
 95 
     | 
    
         
            +
                # @liquid_return [boolean]
         
     | 
| 
      
 96 
     | 
    
         
            +
                def col_first
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @col == 1
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                # @liquid_public_docs
         
     | 
| 
      
 101 
     | 
    
         
            +
                # @liquid_summary
         
     | 
| 
      
 102 
     | 
    
         
            +
                #   Returns `true` if the current column is the last in the row. Returns `false` if not.
         
     | 
| 
      
 103 
     | 
    
         
            +
                # @liquid_return [boolean]
         
     | 
| 
      
 104 
     | 
    
         
            +
                def col_last
         
     | 
| 
      
 105 
     | 
    
         
            +
                  @col == @cols
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                protected
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                def increment!
         
     | 
| 
      
 111 
     | 
    
         
            +
                  @index += 1
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  if @col == @cols
         
     | 
| 
      
 114 
     | 
    
         
            +
                    @col = 1
         
     | 
| 
      
 115 
     | 
    
         
            +
                    @row += 1
         
     | 
| 
      
 116 
     | 
    
         
            +
                  else
         
     | 
| 
      
 117 
     | 
    
         
            +
                    @col += 1
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Liquid
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Tag
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Disableable
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def render_to_output_buffer(context, output)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    if context.tag_disabled?(tag_name)
         
     | 
| 
      
 8 
     | 
    
         
            +
                      output << disabled_error(context)
         
     | 
| 
      
 9 
     | 
    
         
            +
                      return
         
     | 
| 
      
 10 
     | 
    
         
            +
                    end
         
     | 
| 
      
 11 
     | 
    
         
            +
                    super
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def disabled_error(context)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    # raise then rescue the exception so that the Context#exception_renderer can re-raise it
         
     | 
| 
      
 16 
     | 
    
         
            +
                    raise DisabledError, "#{tag_name} #{parse_context[:locale].t('errors.disabled.tag')}"
         
     | 
| 
      
 17 
     | 
    
         
            +
                  rescue DisabledError => exc
         
     | 
| 
      
 18 
     | 
    
         
            +
                    context.handle_error(exc, line_number)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Liquid
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Tag
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Disabler
         
     | 
| 
      
 6 
     | 
    
         
            +
                  module ClassMethods
         
     | 
| 
      
 7 
     | 
    
         
            +
                    attr_reader :disabled_tags
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def self.prepended(base)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    base.extend(ClassMethods)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def render_to_output_buffer(context, output)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    context.with_disabled_tags(self.class.disabled_tags) do
         
     | 
| 
      
 16 
     | 
    
         
            +
                      super
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/liquid/tag.rb
    CHANGED
    
    | 
         @@ -1,26 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
4 
     | 
    
         
             
              class Tag
         
     | 
| 
       3 
     | 
    
         
            -
                 
     | 
| 
       4 
     | 
    
         
            -
                 
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :nodelist, :tag_name, :line_number, :parse_context
         
     | 
| 
      
 6 
     | 
    
         
            +
                alias_method :options, :parse_context
         
     | 
| 
       5 
7 
     | 
    
         
             
                include ParserSwitching
         
     | 
| 
       6 
8 
     | 
    
         | 
| 
       7 
9 
     | 
    
         
             
                class << self
         
     | 
| 
       8 
     | 
    
         
            -
                  def parse(tag_name, markup,  
     | 
| 
       9 
     | 
    
         
            -
                    tag = new(tag_name, markup,  
     | 
| 
       10 
     | 
    
         
            -
                    tag.parse( 
     | 
| 
      
 10 
     | 
    
         
            +
                  def parse(tag_name, markup, tokenizer, parse_context)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    tag = new(tag_name, markup, parse_context)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    tag.parse(tokenizer)
         
     | 
| 
       11 
13 
     | 
    
         
             
                    tag
         
     | 
| 
       12 
14 
     | 
    
         
             
                  end
         
     | 
| 
       13 
15 
     | 
    
         | 
| 
      
 16 
     | 
    
         
            +
                  def disable_tags(*tag_names)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @disabled_tags ||= []
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @disabled_tags.concat(tag_names)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    prepend(Disabler)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
       14 
22 
     | 
    
         
             
                  private :new
         
     | 
| 
       15 
23 
     | 
    
         
             
                end
         
     | 
| 
       16 
24 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
                def initialize(tag_name, markup,  
     | 
| 
       18 
     | 
    
         
            -
                  @tag_name 
     | 
| 
       19 
     | 
    
         
            -
                  @markup 
     | 
| 
       20 
     | 
    
         
            -
                  @ 
     | 
| 
      
 25 
     | 
    
         
            +
                def initialize(tag_name, markup, parse_context)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @tag_name      = tag_name
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @markup        = markup
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @parse_context = parse_context
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @line_number   = parse_context.line_number
         
     | 
| 
       21 
30 
     | 
    
         
             
                end
         
     | 
| 
       22 
31 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
                def parse( 
     | 
| 
      
 32 
     | 
    
         
            +
                def parse(_tokens)
         
     | 
| 
       24 
33 
     | 
    
         
             
                end
         
     | 
| 
       25 
34 
     | 
    
         | 
| 
       26 
35 
     | 
    
         
             
                def raw
         
     | 
| 
         @@ -31,12 +40,26 @@ module Liquid 
     | 
|
| 
       31 
40 
     | 
    
         
             
                  self.class.name.downcase
         
     | 
| 
       32 
41 
     | 
    
         
             
                end
         
     | 
| 
       33 
42 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                def render( 
     | 
| 
       35 
     | 
    
         
            -
                  '' 
     | 
| 
      
 43 
     | 
    
         
            +
                def render(_context)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  ''
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                # For backwards compatibility with custom tags. In a future release, the semantics
         
     | 
| 
      
 48 
     | 
    
         
            +
                # of the `render_to_output_buffer` method will become the default and the `render`
         
     | 
| 
      
 49 
     | 
    
         
            +
                # method will be removed.
         
     | 
| 
      
 50 
     | 
    
         
            +
                def render_to_output_buffer(context, output)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  output << render(context)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  output
         
     | 
| 
       36 
53 
     | 
    
         
             
                end
         
     | 
| 
       37 
54 
     | 
    
         | 
| 
       38 
55 
     | 
    
         
             
                def blank?
         
     | 
| 
       39 
56 
     | 
    
         
             
                  false
         
     | 
| 
       40 
57 
     | 
    
         
             
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                private
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def parse_expression(markup)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  parse_context.parse_expression(markup)
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
       41 
64 
     | 
    
         
             
              end
         
     | 
| 
       42 
65 
     | 
    
         
             
            end
         
     | 
    
        data/lib/liquid/tags/assign.rb
    CHANGED
    
    | 
         @@ -1,38 +1,77 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
              #
         
     | 
| 
       5 
     | 
    
         
            -
              # 
     | 
| 
       6 
     | 
    
         
            -
              #
         
     | 
| 
       7 
     | 
    
         
            -
              #  
     | 
| 
       8 
     | 
    
         
            -
              #
         
     | 
| 
       9 
     | 
    
         
            -
              # 
     | 
| 
       10 
     | 
    
         
            -
              #
         
     | 
| 
      
 3 
     | 
    
         
            +
            module Liquid
         
     | 
| 
      
 4 
     | 
    
         
            +
              # @liquid_public_docs
         
     | 
| 
      
 5 
     | 
    
         
            +
              # @liquid_type tag
         
     | 
| 
      
 6 
     | 
    
         
            +
              # @liquid_category variable
         
     | 
| 
      
 7 
     | 
    
         
            +
              # @liquid_name assign
         
     | 
| 
      
 8 
     | 
    
         
            +
              # @liquid_summary
         
     | 
| 
      
 9 
     | 
    
         
            +
              #   Creates a new variable.
         
     | 
| 
      
 10 
     | 
    
         
            +
              # @liquid_description
         
     | 
| 
      
 11 
     | 
    
         
            +
              #   You can create variables of any [basic type](/api/liquid/basics#types), [object](/api/liquid/objects), or object property.
         
     | 
| 
      
 12 
     | 
    
         
            +
              # @liquid_syntax
         
     | 
| 
      
 13 
     | 
    
         
            +
              #   {% assign variable_name = value %}
         
     | 
| 
      
 14 
     | 
    
         
            +
              # @liquid_syntax_keyword variable_name The name of the variable being created.
         
     | 
| 
      
 15 
     | 
    
         
            +
              # @liquid_syntax_keyword value The value you want to assign to the variable.
         
     | 
| 
       11 
16 
     | 
    
         
             
              class Assign < Tag
         
     | 
| 
       12 
17 
     | 
    
         
             
                Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om
         
     | 
| 
       13 
18 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
                 
     | 
| 
      
 19 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 20 
     | 
    
         
            +
                def self.raise_syntax_error(parse_context)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  raise Liquid::SyntaxError, parse_context.locale.t('errors.syntax.assign')
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                attr_reader :to, :from
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def initialize(tag_name, markup, parse_context)
         
     | 
| 
       15 
27 
     | 
    
         
             
                  super
         
     | 
| 
       16 
28 
     | 
    
         
             
                  if markup =~ Syntax
         
     | 
| 
       17 
     | 
    
         
            -
                    @to 
     | 
| 
       18 
     | 
    
         
            -
                    @from = Variable.new( 
     | 
| 
       19 
     | 
    
         
            -
                    @from.line_number = line_number
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @to   = Regexp.last_match(1)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @from = Variable.new(Regexp.last_match(2), parse_context)
         
     | 
| 
       20 
31 
     | 
    
         
             
                  else
         
     | 
| 
       21 
     | 
    
         
            -
                     
     | 
| 
      
 32 
     | 
    
         
            +
                    self.class.raise_syntax_error(parse_context)
         
     | 
| 
       22 
33 
     | 
    
         
             
                  end
         
     | 
| 
       23 
34 
     | 
    
         
             
                end
         
     | 
| 
       24 
35 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                def  
     | 
| 
      
 36 
     | 
    
         
            +
                def render_to_output_buffer(context, output)
         
     | 
| 
       26 
37 
     | 
    
         
             
                  val = @from.render(context)
         
     | 
| 
       27 
38 
     | 
    
         
             
                  context.scopes.last[@to] = val
         
     | 
| 
       28 
     | 
    
         
            -
                  context. 
     | 
| 
       29 
     | 
    
         
            -
                   
     | 
| 
      
 39 
     | 
    
         
            +
                  context.resource_limits.increment_assign_score(assign_score_of(val))
         
     | 
| 
      
 40 
     | 
    
         
            +
                  output
         
     | 
| 
       30 
41 
     | 
    
         
             
                end
         
     | 
| 
       31 
42 
     | 
    
         | 
| 
       32 
43 
     | 
    
         
             
                def blank?
         
     | 
| 
       33 
44 
     | 
    
         
             
                  true
         
     | 
| 
       34 
45 
     | 
    
         
             
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                private
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                def assign_score_of(val)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  if val.instance_of?(String)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    val.bytesize
         
     | 
| 
      
 52 
     | 
    
         
            +
                  elsif val.instance_of?(Array)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    sum = 1
         
     | 
| 
      
 54 
     | 
    
         
            +
                    # Uses #each to avoid extra allocations.
         
     | 
| 
      
 55 
     | 
    
         
            +
                    val.each { |child| sum += assign_score_of(child) }
         
     | 
| 
      
 56 
     | 
    
         
            +
                    sum
         
     | 
| 
      
 57 
     | 
    
         
            +
                  elsif val.instance_of?(Hash)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    sum = 1
         
     | 
| 
      
 59 
     | 
    
         
            +
                    val.each do |key, entry_value|
         
     | 
| 
      
 60 
     | 
    
         
            +
                      sum += assign_score_of(key)
         
     | 
| 
      
 61 
     | 
    
         
            +
                      sum += assign_score_of(entry_value)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
                    sum
         
     | 
| 
      
 64 
     | 
    
         
            +
                  else
         
     | 
| 
      
 65 
     | 
    
         
            +
                    1
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                class ParseTreeVisitor < Liquid::ParseTreeVisitor
         
     | 
| 
      
 70 
     | 
    
         
            +
                  def children
         
     | 
| 
      
 71 
     | 
    
         
            +
                    [@node.from]
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
       35 
74 
     | 
    
         
             
              end
         
     | 
| 
       36 
75 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
              Template.register_tag('assign' 
     | 
| 
      
 76 
     | 
    
         
            +
              Template.register_tag('assign', Assign)
         
     | 
| 
       38 
77 
     | 
    
         
             
            end
         
     | 
    
        data/lib/liquid/tags/break.rb
    CHANGED
    
    | 
         @@ -1,5 +1,6 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            module Liquid
         
     | 
| 
       3 
4 
     | 
    
         
             
              # Break tag to be used to break out of a for loop.
         
     | 
| 
       4 
5 
     | 
    
         
             
              #
         
     | 
| 
       5 
6 
     | 
    
         
             
              # == Basic Usage:
         
     | 
| 
         @@ -9,13 +10,22 @@ module Liquid 
     | 
|
| 
       9 
10 
     | 
    
         
             
              #      {% endif %}
         
     | 
| 
       10 
11 
     | 
    
         
             
              #    {% endfor %}
         
     | 
| 
       11 
12 
     | 
    
         
             
              #
         
     | 
| 
      
 13 
     | 
    
         
            +
              # @liquid_public_docs
         
     | 
| 
      
 14 
     | 
    
         
            +
              # @liquid_type tag
         
     | 
| 
      
 15 
     | 
    
         
            +
              # @liquid_category iteration
         
     | 
| 
      
 16 
     | 
    
         
            +
              # @liquid_name break
         
     | 
| 
      
 17 
     | 
    
         
            +
              # @liquid_summary
         
     | 
| 
      
 18 
     | 
    
         
            +
              #   Stops a [`for` loop](/api/liquid/tags#for) from iterating.
         
     | 
| 
      
 19 
     | 
    
         
            +
              # @liquid_syntax
         
     | 
| 
      
 20 
     | 
    
         
            +
              #   {% break %}
         
     | 
| 
       12 
21 
     | 
    
         
             
              class Break < Tag
         
     | 
| 
      
 22 
     | 
    
         
            +
                INTERRUPT = BreakInterrupt.new.freeze
         
     | 
| 
       13 
23 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
                def  
     | 
| 
       15 
     | 
    
         
            -
                   
     | 
| 
      
 24 
     | 
    
         
            +
                def render_to_output_buffer(context, output)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  context.push_interrupt(INTERRUPT)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  output
         
     | 
| 
       16 
27 
     | 
    
         
             
                end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
28 
     | 
    
         
             
              end
         
     | 
| 
       19 
29 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
              Template.register_tag('break' 
     | 
| 
      
 30 
     | 
    
         
            +
              Template.register_tag('break', Break)
         
     | 
| 
       21 
31 
     | 
    
         
             
            end
         
     | 
    
        data/lib/liquid/tags/capture.rb
    CHANGED
    
    | 
         @@ -1,32 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
       2 
     | 
    
         
            -
              #  
     | 
| 
       3 
     | 
    
         
            -
              #
         
     | 
| 
       4 
     | 
    
         
            -
              # 
     | 
| 
       5 
     | 
    
         
            -
              # 
     | 
| 
      
 4 
     | 
    
         
            +
              # @liquid_public_docs
         
     | 
| 
      
 5 
     | 
    
         
            +
              # @liquid_type tag
         
     | 
| 
      
 6 
     | 
    
         
            +
              # @liquid_category variable
         
     | 
| 
      
 7 
     | 
    
         
            +
              # @liquid_name capture
         
     | 
| 
      
 8 
     | 
    
         
            +
              # @liquid_summary
         
     | 
| 
      
 9 
     | 
    
         
            +
              #   Creates a new variable with a string value.
         
     | 
| 
      
 10 
     | 
    
         
            +
              # @liquid_description
         
     | 
| 
      
 11 
     | 
    
         
            +
              #   You can create complex strings with Liquid logic and variables.
         
     | 
| 
      
 12 
     | 
    
         
            +
              # @liquid_syntax
         
     | 
| 
      
 13 
     | 
    
         
            +
              #   {% capture variable %}
         
     | 
| 
      
 14 
     | 
    
         
            +
              #     value
         
     | 
| 
       6 
15 
     | 
    
         
             
              #   {% endcapture %}
         
     | 
| 
       7 
     | 
    
         
            -
              # 
     | 
| 
       8 
     | 
    
         
            -
              # 
     | 
| 
       9 
     | 
    
         
            -
              #
         
     | 
| 
       10 
     | 
    
         
            -
              # Capture is useful for saving content for use later in your template, such as
         
     | 
| 
       11 
     | 
    
         
            -
              # in a sidebar or footer.
         
     | 
| 
       12 
     | 
    
         
            -
              #
         
     | 
| 
      
 16 
     | 
    
         
            +
              # @liquid_syntax_keyword variable The name of the variable being created.
         
     | 
| 
      
 17 
     | 
    
         
            +
              # @liquid_syntax_keyword value The value you want to assign to the variable.
         
     | 
| 
       13 
18 
     | 
    
         
             
              class Capture < Block
         
     | 
| 
       14 
19 
     | 
    
         
             
                Syntax = /(#{VariableSignature}+)/o
         
     | 
| 
       15 
20 
     | 
    
         | 
| 
       16 
21 
     | 
    
         
             
                def initialize(tag_name, markup, options)
         
     | 
| 
       17 
22 
     | 
    
         
             
                  super
         
     | 
| 
       18 
23 
     | 
    
         
             
                  if markup =~ Syntax
         
     | 
| 
       19 
     | 
    
         
            -
                    @to =  
     | 
| 
      
 24 
     | 
    
         
            +
                    @to = Regexp.last_match(1)
         
     | 
| 
       20 
25 
     | 
    
         
             
                  else
         
     | 
| 
       21 
     | 
    
         
            -
                    raise SyntaxError 
     | 
| 
      
 26 
     | 
    
         
            +
                    raise SyntaxError, options[:locale].t("errors.syntax.capture")
         
     | 
| 
       22 
27 
     | 
    
         
             
                  end
         
     | 
| 
       23 
28 
     | 
    
         
             
                end
         
     | 
| 
       24 
29 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                def  
     | 
| 
       26 
     | 
    
         
            -
                   
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                   
     | 
| 
      
 30 
     | 
    
         
            +
                def render_to_output_buffer(context, output)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  context.resource_limits.with_capture do
         
     | 
| 
      
 32 
     | 
    
         
            +
                    capture_output = render(context)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    context.scopes.last[@to] = capture_output
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  output
         
     | 
| 
       30 
36 
     | 
    
         
             
                end
         
     | 
| 
       31 
37 
     | 
    
         | 
| 
       32 
38 
     | 
    
         
             
                def blank?
         
     | 
| 
         @@ -34,5 +40,5 @@ module Liquid 
     | 
|
| 
       34 
40 
     | 
    
         
             
                end
         
     | 
| 
       35 
41 
     | 
    
         
             
              end
         
     | 
| 
       36 
42 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
              Template.register_tag('capture' 
     | 
| 
      
 43 
     | 
    
         
            +
              Template.register_tag('capture', Capture)
         
     | 
| 
       38 
44 
     | 
    
         
             
            end
         
     | 
    
        data/lib/liquid/tags/case.rb
    CHANGED
    
    | 
         @@ -1,79 +1,128 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Liquid
         
     | 
| 
      
 4 
     | 
    
         
            +
              # @liquid_public_docs
         
     | 
| 
      
 5 
     | 
    
         
            +
              # @liquid_type tag
         
     | 
| 
      
 6 
     | 
    
         
            +
              # @liquid_category conditional
         
     | 
| 
      
 7 
     | 
    
         
            +
              # @liquid_name case
         
     | 
| 
      
 8 
     | 
    
         
            +
              # @liquid_summary
         
     | 
| 
      
 9 
     | 
    
         
            +
              #   Renders a specific expression depending on the value of a specific variable.
         
     | 
| 
      
 10 
     | 
    
         
            +
              # @liquid_syntax
         
     | 
| 
      
 11 
     | 
    
         
            +
              #   {% case variable %}
         
     | 
| 
      
 12 
     | 
    
         
            +
              #     {% when first_value %}
         
     | 
| 
      
 13 
     | 
    
         
            +
              #       first_expression
         
     | 
| 
      
 14 
     | 
    
         
            +
              #     {% when second_value %}
         
     | 
| 
      
 15 
     | 
    
         
            +
              #       second_expression
         
     | 
| 
      
 16 
     | 
    
         
            +
              #     {% else %}
         
     | 
| 
      
 17 
     | 
    
         
            +
              #       third_expression
         
     | 
| 
      
 18 
     | 
    
         
            +
              #   {% endcase %}
         
     | 
| 
      
 19 
     | 
    
         
            +
              # @liquid_syntax_keyword variable The name of the variable you want to base your case statement on.
         
     | 
| 
      
 20 
     | 
    
         
            +
              # @liquid_syntax_keyword first_value A specific value to check for.
         
     | 
| 
      
 21 
     | 
    
         
            +
              # @liquid_syntax_keyword second_value A specific value to check for.
         
     | 
| 
      
 22 
     | 
    
         
            +
              # @liquid_syntax_keyword first_expression An expression to be rendered when the variable's value matches `first_value`.
         
     | 
| 
      
 23 
     | 
    
         
            +
              # @liquid_syntax_keyword second_expression An expression to be rendered when the variable's value matches `second_value`.
         
     | 
| 
      
 24 
     | 
    
         
            +
              # @liquid_syntax_keyword third_expression An expression to be rendered when the variable's value has no match.
         
     | 
| 
       2 
25 
     | 
    
         
             
              class Case < Block
         
     | 
| 
       3 
26 
     | 
    
         
             
                Syntax     = /(#{QuotedFragment})/o
         
     | 
| 
       4 
27 
     | 
    
         
             
                WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/om
         
     | 
| 
       5 
28 
     | 
    
         | 
| 
      
 29 
     | 
    
         
            +
                attr_reader :blocks, :left
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
       6 
31 
     | 
    
         
             
                def initialize(tag_name, markup, options)
         
     | 
| 
       7 
32 
     | 
    
         
             
                  super
         
     | 
| 
       8 
33 
     | 
    
         
             
                  @blocks = []
         
     | 
| 
       9 
34 
     | 
    
         | 
| 
       10 
35 
     | 
    
         
             
                  if markup =~ Syntax
         
     | 
| 
       11 
     | 
    
         
            -
                    @left =  
     | 
| 
      
 36 
     | 
    
         
            +
                    @left = parse_expression(Regexp.last_match(1))
         
     | 
| 
       12 
37 
     | 
    
         
             
                  else
         
     | 
| 
       13 
     | 
    
         
            -
                    raise SyntaxError 
     | 
| 
      
 38 
     | 
    
         
            +
                    raise SyntaxError, options[:locale].t("errors.syntax.case")
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def parse(tokens)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  body = case_body = new_body
         
     | 
| 
      
 44 
     | 
    
         
            +
                  body = @blocks.last.attachment while parse_body(body, tokens)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @blocks.reverse_each do |condition|
         
     | 
| 
      
 46 
     | 
    
         
            +
                    body = condition.attachment
         
     | 
| 
      
 47 
     | 
    
         
            +
                    unless body.frozen?
         
     | 
| 
      
 48 
     | 
    
         
            +
                      body.remove_blank_strings if blank?
         
     | 
| 
      
 49 
     | 
    
         
            +
                      body.freeze
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
       14 
51 
     | 
    
         
             
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                  case_body.freeze
         
     | 
| 
       15 
53 
     | 
    
         
             
                end
         
     | 
| 
       16 
54 
     | 
    
         | 
| 
       17 
55 
     | 
    
         
             
                def nodelist
         
     | 
| 
       18 
     | 
    
         
            -
                  @blocks. 
     | 
| 
      
 56 
     | 
    
         
            +
                  @blocks.map(&:attachment)
         
     | 
| 
       19 
57 
     | 
    
         
             
                end
         
     | 
| 
       20 
58 
     | 
    
         | 
| 
       21 
59 
     | 
    
         
             
                def unknown_tag(tag, markup, tokens)
         
     | 
| 
       22 
     | 
    
         
            -
                  @nodelist = []
         
     | 
| 
       23 
60 
     | 
    
         
             
                  case tag
         
     | 
| 
       24 
     | 
    
         
            -
                  when 'when' 
     | 
| 
      
 61 
     | 
    
         
            +
                  when 'when'
         
     | 
| 
       25 
62 
     | 
    
         
             
                    record_when_condition(markup)
         
     | 
| 
       26 
     | 
    
         
            -
                  when 'else' 
     | 
| 
      
 63 
     | 
    
         
            +
                  when 'else'
         
     | 
| 
       27 
64 
     | 
    
         
             
                    record_else_condition(markup)
         
     | 
| 
       28 
65 
     | 
    
         
             
                  else
         
     | 
| 
       29 
66 
     | 
    
         
             
                    super
         
     | 
| 
       30 
67 
     | 
    
         
             
                  end
         
     | 
| 
       31 
68 
     | 
    
         
             
                end
         
     | 
| 
       32 
69 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                def  
     | 
| 
       34 
     | 
    
         
            -
                   
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                     
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                       
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
      
 70 
     | 
    
         
            +
                def render_to_output_buffer(context, output)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  execute_else_block = true
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  @blocks.each do |block|
         
     | 
| 
      
 74 
     | 
    
         
            +
                    if block.else?
         
     | 
| 
      
 75 
     | 
    
         
            +
                      block.attachment.render_to_output_buffer(context, output) if execute_else_block
         
     | 
| 
      
 76 
     | 
    
         
            +
                      next
         
     | 
| 
      
 77 
     | 
    
         
            +
                    end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    result = Liquid::Utils.to_liquid_value(
         
     | 
| 
      
 80 
     | 
    
         
            +
                      block.evaluate(context)
         
     | 
| 
      
 81 
     | 
    
         
            +
                    )
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                    if result
         
     | 
| 
      
 84 
     | 
    
         
            +
                      execute_else_block = false
         
     | 
| 
      
 85 
     | 
    
         
            +
                      block.attachment.render_to_output_buffer(context, output)
         
     | 
| 
       45 
86 
     | 
    
         
             
                    end
         
     | 
| 
       46 
     | 
    
         
            -
                    output
         
     | 
| 
       47 
87 
     | 
    
         
             
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  output
         
     | 
| 
       48 
90 
     | 
    
         
             
                end
         
     | 
| 
       49 
91 
     | 
    
         | 
| 
       50 
92 
     | 
    
         
             
                private
         
     | 
| 
       51 
93 
     | 
    
         | 
| 
       52 
94 
     | 
    
         
             
                def record_when_condition(markup)
         
     | 
| 
      
 95 
     | 
    
         
            +
                  body = new_body
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
       53 
97 
     | 
    
         
             
                  while markup
         
     | 
| 
       54 
     | 
    
         
            -
                     
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
                      raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_when".freeze))
         
     | 
| 
      
 98 
     | 
    
         
            +
                    unless markup =~ WhenSyntax
         
     | 
| 
      
 99 
     | 
    
         
            +
                      raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_when")
         
     | 
| 
       57 
100 
     | 
    
         
             
                    end
         
     | 
| 
       58 
101 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
                    markup =  
     | 
| 
      
 102 
     | 
    
         
            +
                    markup = Regexp.last_match(2)
         
     | 
| 
       60 
103 
     | 
    
         | 
| 
       61 
     | 
    
         
            -
                    block = Condition.new(@left, '=='. 
     | 
| 
       62 
     | 
    
         
            -
                    block.attach( 
     | 
| 
       63 
     | 
    
         
            -
                    @blocks 
     | 
| 
      
 104 
     | 
    
         
            +
                    block = Condition.new(@left, '==', Condition.parse_expression(parse_context, Regexp.last_match(1)))
         
     | 
| 
      
 105 
     | 
    
         
            +
                    block.attach(body)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    @blocks << block
         
     | 
| 
       64 
107 
     | 
    
         
             
                  end
         
     | 
| 
       65 
108 
     | 
    
         
             
                end
         
     | 
| 
       66 
109 
     | 
    
         | 
| 
       67 
110 
     | 
    
         
             
                def record_else_condition(markup)
         
     | 
| 
       68 
     | 
    
         
            -
                   
     | 
| 
       69 
     | 
    
         
            -
                    raise SyntaxError 
     | 
| 
      
 111 
     | 
    
         
            +
                  unless markup.strip.empty?
         
     | 
| 
      
 112 
     | 
    
         
            +
                    raise SyntaxError, options[:locale].t("errors.syntax.case_invalid_else")
         
     | 
| 
       70 
113 
     | 
    
         
             
                  end
         
     | 
| 
       71 
114 
     | 
    
         | 
| 
       72 
115 
     | 
    
         
             
                  block = ElseCondition.new
         
     | 
| 
       73 
     | 
    
         
            -
                  block.attach( 
     | 
| 
      
 116 
     | 
    
         
            +
                  block.attach(new_body)
         
     | 
| 
       74 
117 
     | 
    
         
             
                  @blocks << block
         
     | 
| 
       75 
118 
     | 
    
         
             
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                class ParseTreeVisitor < Liquid::ParseTreeVisitor
         
     | 
| 
      
 121 
     | 
    
         
            +
                  def children
         
     | 
| 
      
 122 
     | 
    
         
            +
                    [@node.left] + @node.blocks
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
       76 
125 
     | 
    
         
             
              end
         
     | 
| 
       77 
126 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
              Template.register_tag('case' 
     | 
| 
      
 127 
     | 
    
         
            +
              Template.register_tag('case', Case)
         
     | 
| 
       79 
128 
     | 
    
         
             
            end
         
     |