From e4276bdf6b6406b2615b90960200d370f3145c5f Mon Sep 17 00:00:00 2001 From: Guilherme Carreiro Date: Wed, 19 Nov 2025 12:32:18 +0100 Subject: [PATCH] This commit reverts the Inline Snippets tag (#2001) and bumps Liquid to 5.11. For now, the inclusion of Inline Snippets in the latest Liquid release is being treated as a bug. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While #2001 does implement the scope contained in RFC#1916, we need to take a step back to make sure we’re setting our sights high enough with this feature, and that we’re truly supporting theme developers in the ways they need. If you have any feedback, please leave a comment on RFC#1916. - Liquid Developer Tools --- lib/liquid.rb | 1 - lib/liquid/locales/en.yml | 3 - lib/liquid/snippet_drop.rb | 22 - lib/liquid/tags.rb | 2 - lib/liquid/tags/render.rb | 34 +- lib/liquid/tags/snippet.rb | 45 - test/integration/tags/render_tag_test.rb | 11 +- test/integration/tags/snippet_test.rb | 1087 ---------------------- 8 files changed, 18 insertions(+), 1187 deletions(-) delete mode 100644 lib/liquid/snippet_drop.rb delete mode 100644 lib/liquid/tags/snippet.rb delete mode 100644 test/integration/tags/snippet_test.rb diff --git a/lib/liquid.rb b/lib/liquid.rb index 09cafe94..4d0a71a6 100644 --- a/lib/liquid.rb +++ b/lib/liquid.rb @@ -67,7 +67,6 @@ require 'liquid/i18n' require 'liquid/drop' require 'liquid/tablerowloop_drop' require 'liquid/forloop_drop' -require 'liquid/snippet_drop' require 'liquid/extensions' require 'liquid/errors' require 'liquid/interrupts' diff --git a/lib/liquid/locales/en.yml b/lib/liquid/locales/en.yml index 7a9fb71e..b99d490c 100644 --- a/lib/liquid/locales/en.yml +++ b/lib/liquid/locales/en.yml @@ -5,7 +5,6 @@ block_tag_unexpected_args: "Syntax Error in '%{tag}' - Valid syntax: {% %{tag} %}{% end%{tag} %}" assign: "Syntax Error in 'assign' - Valid syntax: assign [var] = [source]" capture: "Syntax Error in 'capture' - Valid syntax: capture [var]" - snippet: "Syntax Error in 'snippet' - Valid syntax: snippet [var]" case: "Syntax Error in 'case' - Valid syntax: case [condition]" case_invalid_when: "Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %}" case_invalid_else: "Syntax Error in tag 'case' - Valid else condition: {% else %} (no parameters) " @@ -20,7 +19,6 @@ invalid_delimiter: "'%{tag}' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}" invalid_template_encoding: "Invalid template encoding" render: "Syntax error in tag 'render' - Template name must be a quoted string" - render_invalid_template_name: "Syntax error in tag 'render' - Expected a string or identifier, found %{found}" table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3" table_row_invalid_attribute: "Invalid attribute '%{attribute}' in tablerow loop. Valid attributes are cols, limit, offset, and range" tag_never_closed: "'%{block_name}' tag was never closed" @@ -31,6 +29,5 @@ variable_termination: "Variable '%{token}' was not properly terminated with regexp: %{tag_end}" argument: include: "Argument error in tag 'include' - Illegal template name" - render: "Argument error in tag 'render' - Dynamically chosen templates are not allowed" disabled: tag: "usage is not allowed in this context" diff --git a/lib/liquid/snippet_drop.rb b/lib/liquid/snippet_drop.rb deleted file mode 100644 index 98686999..00000000 --- a/lib/liquid/snippet_drop.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -module Liquid - class SnippetDrop < Drop - attr_reader :body, :name, :filename - - def initialize(body, name, filename) - super() - @body = body - @name = name - @filename = filename - end - - def to_partial - @body - end - - def to_s - 'SnippetDrop' - end - end -end diff --git a/lib/liquid/tags.rb b/lib/liquid/tags.rb index 3ec5e7cf..dff7553f 100644 --- a/lib/liquid/tags.rb +++ b/lib/liquid/tags.rb @@ -20,7 +20,6 @@ require_relative "tags/raw" require_relative "tags/render" require_relative "tags/cycle" require_relative "tags/doc" -require_relative "tags/snippet" module Liquid module Tags @@ -45,7 +44,6 @@ module Liquid 'echo' => Echo, 'tablerow' => TableRow, 'doc' => Doc, - 'snippet' => Snippet, }.freeze end end diff --git a/lib/liquid/tags/render.rb b/lib/liquid/tags/render.rb index dec725ed..4d29e420 100644 --- a/lib/liquid/tags/render.rb +++ b/lib/liquid/tags/render.rb @@ -27,7 +27,7 @@ module Liquid # @liquid_syntax_keyword filename The name of the snippet to render, without the `.liquid` extension. class Render < Tag FOR = 'for' - SYNTAX = /(#{QuotedString}+|#{VariableSegment}+)(\s+(with|#{FOR})\s+(#{QuotedFragment}+))?(\s+(?:as)\s+(#{VariableSegment}+))?/o + SYNTAX = /(#{QuotedString}+)(\s+(with|#{FOR})\s+(#{QuotedFragment}+))?(\s+(?:as)\s+(#{VariableSegment}+))?/o disable_tags "include" @@ -47,23 +47,21 @@ module Liquid end def render_tag(context, output) - template = context.evaluate(@template_name_expr) + # The expression should be a String literal, which parses to a String object + template_name = @template_name_expr + raise ::ArgumentError unless template_name.is_a?(String) - if template.respond_to?(:to_partial) - partial = template.to_partial - template_name = template.filename - context_variable_name = @alias_name || template.name - elsif @template_name_expr.is_a?(String) - partial = PartialCache.load(template, context: context, parse_context: parse_context) - template_name = partial.name - context_variable_name = @alias_name || template_name.split('/').last - else - raise ::ArgumentError - end + partial = PartialCache.load( + template_name, + context: context, + parse_context: parse_context, + ) + + context_variable_name = @alias_name || template_name.split('/').last render_partial_func = ->(var, forloop) { inner_context = context.new_isolated_subcontext - inner_context.template_name = template_name + inner_context.template_name = partial.name inner_context.partial = true inner_context['forloop'] = forloop if forloop @@ -103,18 +101,14 @@ module Liquid key = p.consume p.consume(:colon) @attributes[key] = safe_parse_expression(p) - p.consume?(:comma) # optional comma + p.consume?(:comma) end p.consume(:end_of_string) end def rigid_template_name(p) - return p.consume(:string) if p.look(:string) - return p.consume(:id) if p.look(:id) - - found = p.consume || "nothing" - raise SyntaxError, options[:locale].t("errors.syntax.render_invalid_template_name", found: found) + p.consume(:string) end def strict_parse(markup) diff --git a/lib/liquid/tags/snippet.rb b/lib/liquid/tags/snippet.rb deleted file mode 100644 index 87e2a0de..00000000 --- a/lib/liquid/tags/snippet.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -module Liquid - # @liquid_public_docs - # @liquid_type tag - # @liquid_category variable - # @liquid_name snippet - # @liquid_summary - # Creates a new inline snippet. - # @liquid_description - # You can create inline snippets to make your Liquid code more modular. - # @liquid_syntax - # {% snippet snippet_name %} - # value - # {% endsnippet %} - class Snippet < Block - def initialize(tag_name, markup, options) - super - p = @parse_context.new_parser(markup) - if p.look(:id) - @to = p.consume(:id) - p.consume(:end_of_string) - else - raise SyntaxError, options[:locale].t("errors.syntax.snippet") - end - end - - def render_to_output_buffer(context, output) - snippet_drop = SnippetDrop.new(@body, @to, context.template_name) - context.scopes.last[@to] = snippet_drop - context.resource_limits.increment_assign_score(assign_score_of(snippet_drop)) - output - end - - def blank? - true - end - - private - - def assign_score_of(snippet_drop) - snippet_drop.body.nodelist.sum { |node| node.to_s.bytesize } - end - end -end diff --git a/test/integration/tags/render_tag_test.rb b/test/integration/tags/render_tag_test.rb index 6fe19abb..d6453fb5 100644 --- a/test/integration/tags/render_tag_test.rb +++ b/test/integration/tags/render_tag_test.rb @@ -101,6 +101,10 @@ class RenderTagTest < Minitest::Test end end + def test_dynamically_choosen_templates_are_not_allowed + assert_syntax_error("{% assign name = 'snippet' %}{% render name %}") + end + def test_rigid_parsing_errors with_error_modes(:lax, :strict) do assert_template_result( @@ -290,13 +294,6 @@ class RenderTagTest < Minitest::Test ) end - def test_render_tag_with_snippet_drop - assert_template_result( - "Hello from snippet", - "{% snippet my_snippet %}Hello from snippet{% endsnippet %}{% render my_snippet %}", - ) - end - def test_render_tag_renders_error_with_template_name assert_template_result( 'Liquid error (foo line 1): standard error', diff --git a/test/integration/tags/snippet_test.rb b/test/integration/tags/snippet_test.rb deleted file mode 100644 index 6d1cb35d..00000000 --- a/test/integration/tags/snippet_test.rb +++ /dev/null @@ -1,1087 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class SnippetTest < Minitest::Test - include Liquid - - class LaxMode < SnippetTest - def test_valid_inline_snippet - template = <<~LIQUID.strip - {% snippet input %} - Hey - {% endsnippet %} - LIQUID - expected = '' - - assert_template_result(expected, template) - end - - def test_render_inline_snippet - template = <<~LIQUID.strip - {% snippet hey %} - Hey - {% endsnippet %} - - {%- render hey -%} - LIQUID - expected = <<~OUTPUT - - Hey - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_with_variable - template = <<~LIQUID.strip - {% snippet hey %} -

Today is {{ "hello" | capitalize }}

- {% endsnippet %} - - {%- render hey -%} - LIQUID - expected = <<~OUTPUT - -

Today is Hello

- OUTPUT - - assert_template_result(expected, template) - end - - def test_render_multiple_inline_snippets - template = <<~LIQUID.strip - {% snippet input %} - - {% endsnippet %} - - {% snippet banner %} - - Welcome to my store! - - {% endsnippet %} - - {%- render input -%} - {%- render banner -%} - LIQUID - expected = <<~OUTPUT - - - - - - - Welcome to my store! - - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_with_argument - template = <<~LIQUID.strip - {% snippet input %} - - {% endsnippet %} - - {%- render input, type: "text" -%} - LIQUID - expected = <<~OUTPUT - - - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_with_doc_tag - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - {% enddoc %} - - - {% endsnippet %} - - {%- render input, type: "text" -%} - LIQUID - expected = <<~OUTPUT - - - - - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_with_evaluated_assign - template = <<~LIQUID.strip - {% snippet input %} -

{{ greeting }}

- {% endsnippet %} - - {%- assign greeting = "hello" | upcase -%} - {%- render input, greeting: greeting -%} - LIQUID - expected = <<~OUTPUT - -

HELLO

- OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_with_multiple_arguments - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - @param {string} value - Input value. - {% enddoc %} - - - {% endsnippet %} - - {%- render input, type: "text", value: "Hello" -%} - LIQUID - expected = <<~OUTPUT - - - - - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippets_using_same_argument_name - template = <<~LIQUID.strip - {% snippet input %} - - {% endsnippet %} - - {% snippet inputs %} - - {% endsnippet %} - - {%- render input, type: "text" -%} - {%- render inputs, type: "password", value: "pass" -%} - LIQUID - - expected = <<~OUTPUT - - - - - - - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_empty_string_when_missing_argument - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - @param {string} value - Input value. - {% enddoc %} - - - {% endsnippet %} - - {%- render input, type: "text" -%} - LIQUID - expected = <<~OUTPUT - - - - - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_snippets_as_arguments - template = <<~LIQUID.strip - {% assign color_scheme = 'dark' %} - - {% snippet header %} -
- {{ message }} -
- {% endsnippet %} - - {% snippet main %} - {% assign color_scheme = 'auto' %} - -
- {% render header, message: 'Welcome!' %} -
- {% endsnippet %} - - {% render main, header: header %} - LIQUID - - expected = <<~OUTPUT - - - - - - - - - -
- -
- Welcome! -
- -
- OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_shouldnt_leak_context - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - @param {string} value - Input value. - {% enddoc %} - - - {% endsnippet %} - - {%- render input, type: "text", value: "Hello" -%} - - {{ type }} - {{ value }} - LIQUID - expected = <<~OUTPUT - - - - - - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_multiple_inline_snippets_without_leaking_context - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - {% enddoc %} - - - {% endsnippet %} - - {% snippet no_leak %} - - {% endsnippet %} - - {%- render input, type: "text" -%} - {%- render no_leak -%} - LIQUID - expected = <<~OUTPUT - - - - - - - - - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_ignores_outside_context - template = <<~LIQUID.strip - {% assign color_scheme = 'dark' %} - - {% snippet header %} -
- {{ message }} -
- {% endsnippet %} - - - {% render header, message: 'Welcome!' %} - LIQUID - expected = <<~OUTPUT - - - - - - -
- Welcome! -
- OUTPUT - - assert_template_result(expected, template) - end - - def test_render_captured_snippet - template = <<~LIQUID - {% snippet header %} -
- {{ message }} -
- {% endsnippet %} - - {% capture up_header %} - {%- render header, message: 'Welcome!' -%} - {% endcapture %} - - {{ up_header | upcase }} - - {{ header | upcase }} - - {{ header }} - LIQUID - expected = <<~OUTPUT - - - - - -
- WELCOME! -
- - - SNIPPETDROP - - SnippetDrop - OUTPUT - - assert_template_result(expected, template) - end - - def test_inline_snippet_local_scope_takes_precedence - template = <<~LIQUID - {% assign color_scheme = 'dark' %} - - {% snippet header %} - {% assign color_scheme = 'light' %} -
- {{ message }} -
- {% endsnippet %} - - {{ color_scheme }} - - {% render header, message: 'Welcome!', color_scheme: color_scheme %} - - {{ color_scheme }} - LIQUID - expected = <<~OUTPUT - - - - - dark - - - -
- Welcome! -
- - - dark - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_forloop - template = <<~LIQUID.strip - {% snippet item %} -
  • {{ forloop.index }}: {{ item }}
  • - {% endsnippet %} - - {% assign items = "A,B,C" | split: "," %} - {%- render item for items -%} - LIQUID - expected = <<~OUTPUT - - - -
  • 1: A
  • - -
  • 2: B
  • - -
  • 3: C
  • - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_with - template = <<~LIQUID.strip - {% snippet header %} -
    {{ header }}
    - {% endsnippet %} - - {% assign product = "Apple" %} - {%- render header with product -%} - LIQUID - expected = <<~OUTPUT - - - -
    Apple
    - OUTPUT - - assert_template_result(expected, template) - end - - def test_render_inline_snippet_alias - template = <<~LIQUID.strip - {% snippet product_card %} -
    {{ item }}
    - {% endsnippet %} - - {% assign featured = "Apple" %} - {%- render product_card with featured as item -%} - LIQUID - expected = <<~OUTPUT - - - -
    Apple
    - OUTPUT - - assert_template_result(expected, template) - end - - def test_snippet_with_invalid_identifier - template = <<~LIQUID - {% snippet header foo bar %} - Invalid - {% endsnippet %} - LIQUID - - exception = assert_raises(SyntaxError) { Liquid::Template.parse(template) } - - assert_match("Expected end_of_string but found id", exception.message) - end - - def test_render_with_non_existent_tag - template = Liquid::Template.parse(<<~LIQUID.chomp, line_numbers: true) - {% snippet foo %} - {% render non_existent %} - {% endsnippet %} - - {% render foo %} - LIQUID - - expected = <<~TEXT - - - - Liquid error (index line 2): internal - TEXT - template.name = "index" - - assert_equal(expected, template.render('errors' => ErrorDrop.new)) - end - - def test_render_handles_errors - template = Liquid::Template.parse(<<~LIQUID.chomp, line_numbers: true) - {% snippet foo %} - {% render non_existent %} will raise an error. - - Bla bla test. - - This is an argument error: {{ 'test' | slice: 'not a number' }} - {% endsnippet %} - - {% render foo %} - LIQUID - - expected = <<~TEXT - - - - Liquid error (index line 2): internal will raise an error. - - Bla bla test. - - This is an argument error: Liquid error (index line 6): invalid integer - TEXT - template.name = "index" - - assert_equal(expected, template.render('errors' => ErrorDrop.new)) - end - end - - class RigidMode < SnippetTest - def test_valid_inline_snippet - template = <<~LIQUID.strip - {% snippet input %} - Hey - {% endsnippet %} - LIQUID - expected = '' - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet - template = <<~LIQUID.strip - {% snippet hey %} - Hey - {% endsnippet %} - - {%- render hey -%} - LIQUID - expected = <<~OUTPUT - - Hey - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_with_variable - template = <<~LIQUID.strip - {% snippet hey %} -

    Today is {{ "hello" | capitalize }}

    - {% endsnippet %} - - {%- render hey -%} - LIQUID - expected = <<~OUTPUT - -

    Today is Hello

    - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_multiple_inline_snippets - template = <<~LIQUID.strip - {% snippet input %} - - {% endsnippet %} - - {% snippet banner %} - - Welcome to my store! - - {% endsnippet %} - - {%- render input -%} - {%- render banner -%} - LIQUID - expected = <<~OUTPUT - - - - - - - Welcome to my store! - - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_with_argument - template = <<~LIQUID.strip - {% snippet input %} - - {% endsnippet %} - - {%- render input, type: "text" -%} - LIQUID - expected = <<~OUTPUT - - - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_with_doc_tag - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - {% enddoc %} - - - {% endsnippet %} - - {%- render input, type: "text" -%} - LIQUID - expected = <<~OUTPUT - - - - - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_with_evaluated_assign - template = <<~LIQUID.strip - {% snippet input %} -

    {{ greeting }}

    - {% endsnippet %} - - {%- assign greeting = "hello" | upcase -%} - {%- render input, greeting: greeting -%} - LIQUID - expected = <<~OUTPUT - -

    HELLO

    - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_with_multiple_arguments - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - @param {string} value - Input value. - {% enddoc %} - - - {% endsnippet %} - - {%- render input, type: "text", value: "Hello" -%} - LIQUID - expected = <<~OUTPUT - - - - - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippets_using_same_argument_name - template = <<~LIQUID.strip - {% snippet input %} - - {% endsnippet %} - - {% snippet inputs %} - - {% endsnippet %} - - {%- render input, type: "text" -%} - {%- render inputs, type: "password", value: "pass" -%} - LIQUID - - expected = <<~OUTPUT - - - - - - - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_empty_string_when_missing_argument - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - @param {string} value - Input value. - {% enddoc %} - - - {% endsnippet %} - - {%- render input, type: "text" -%} - LIQUID - expected = <<~OUTPUT - - - - - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_snippets_as_arguments - template = <<~LIQUID.strip - {% assign color_scheme = 'dark' %} - - {% snippet header %} -
    - {{ message }} -
    - {% endsnippet %} - - {% snippet main %} - {% assign color_scheme = 'auto' %} - -
    - {% render header, message: 'Welcome!' %} -
    - {% endsnippet %} - - {% render main, header: header %} - LIQUID - - expected = <<~OUTPUT - - - - - - - - - -
    - -
    - Welcome! -
    - -
    - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_shouldnt_leak_context - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - @param {string} value - Input value. - {% enddoc %} - - - {% endsnippet %} - - {%- render input, type: "text", value: "Hello" -%} - - {{ type }} - {{ value }} - LIQUID - expected = <<~OUTPUT - - - - - - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_multiple_inline_snippets_without_leaking_context - template = <<~LIQUID.strip - {% snippet input %} - {% doc %} - @param {string} type - Input type. - {% enddoc %} - - - {% endsnippet %} - - {% snippet no_leak %} - - {% endsnippet %} - - {%- render input, type: "text" -%} - {%- render no_leak -%} - LIQUID - expected = <<~OUTPUT - - - - - - - - - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_ignores_outside_context - template = <<~LIQUID.strip - {% assign color_scheme = 'dark' %} - - {% snippet header %} -
    - {{ message }} -
    - {% endsnippet %} - - - {% render header, message: 'Welcome!' %} - LIQUID - expected = <<~OUTPUT - - - - - - -
    - Welcome! -
    - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_inline_snippet_local_scope_takes_precedence - template = <<~LIQUID - {% assign color_scheme = 'dark' %} - - {% snippet header %} - {% assign color_scheme = 'light' %} -
    - {{ message }} -
    - {% endsnippet %} - - {{ color_scheme }} - - {% render header, message: 'Welcome!', color_scheme: color_scheme %} - - {{ color_scheme }} - LIQUID - expected = <<~OUTPUT - - - - - dark - - - -
    - Welcome! -
    - - - dark - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_forloop - template = <<~LIQUID.strip - {% snippet item %} -
  • {{ forloop.index }}: {{ item }}
  • - {% endsnippet %} - - {% assign items = "A,B,C" | split: "," %} - {%- render item for items -%} - LIQUID - expected = <<~OUTPUT - - - -
  • 1: A
  • - -
  • 2: B
  • - -
  • 3: C
  • - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_with - template = <<~LIQUID.strip - {% snippet header %} -
    {{ header }}
    - {% endsnippet %} - - {% assign product = "Apple" %} - {%- render header with product -%} - LIQUID - expected = <<~OUTPUT - - - -
    Apple
    - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_inline_snippet_alias - template = <<~LIQUID.strip - {% snippet product_card %} -
    {{ item }}
    - {% endsnippet %} - - {% assign featured = "Apple" %} - {%- render product_card with featured as item -%} - LIQUID - expected = <<~OUTPUT - - - -
    Apple
    - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_captured_snippet - template = <<~LIQUID - {% snippet header %} -
    - {{ message }} -
    - {% endsnippet %} - - {% capture up_header %} - {%- render header, message: 'Welcome!' -%} - {% endcapture %} - - {{ up_header | upcase }} - - {{ header | upcase }} - - {{ header }} - LIQUID - expected = <<~OUTPUT - - - - - -
    - WELCOME! -
    - - - SNIPPETDROP - - SnippetDrop - OUTPUT - - assert_template_result(expected, template, error_mode: :rigid) - end - - def test_render_with_invalid_identifier - template = "{% render 123 %}" - - exception = assert_raises(SyntaxError) do - Liquid::Template.parse(template, error_mode: :rigid) - end - - assert_match("Expected a string or identifier, found 123", exception.message) - end - - def test_render_with_non_existent_tag - template = Liquid::Template.parse(<<~LIQUID.chomp, line_numbers: true, error_mode: :rigid) - {% snippet foo %} - {% render non_existent %} - {% endsnippet %} - - {% render foo %} - LIQUID - - expected = <<~TEXT - - - - Liquid error (index line 2): internal - TEXT - template.name = "index" - - assert_equal(expected, template.render('errors' => ErrorDrop.new)) - end - - def test_render_handles_errors - template = Liquid::Template.parse(<<~LIQUID.chomp, line_numbers: true, error_mode: :rigid) - {% snippet foo %} - {% render non_existent %} will raise an error. - - Bla bla test. - - This is an argument error: {{ 'test' | slice: 'not a number' }} - {% endsnippet %} - - {% render foo %} - LIQUID - - expected = <<~TEXT - - - - Liquid error (index line 2): internal will raise an error. - - Bla bla test. - - This is an argument error: Liquid error (index line 6): invalid integer - TEXT - template.name = "index" - - assert_equal(expected, template.render('errors' => ErrorDrop.new)) - end - - def test_render_with_no_identifier - template = "{% render %}" - - exception = assert_raises(SyntaxError) do - Liquid::Template.parse(template, error_mode: :rigid) - end - - assert_match("Expected a string or identifier, found nothing", exception.message) - end - - def test_snippet_with_invalid_identifier - template = <<~LIQUID - {% snippet header foo bar %} - Invalid - {% endsnippet %} - LIQUID - - exception = assert_raises(SyntaxError) do - Liquid::Template.parse(template, error_mode: :rigid) - end - - assert_match("Expected end_of_string but found id", exception.message) - end - end - - class ResourceLimits < SnippetTest - def test_increment_assign_score_by_bytes_not_characters - t = Template.parse("{% snippet foo %}すごい{% endsnippet %}") - t.render! - assert_equal(9, t.resource_limits.assign_score) - end - end -end