diff --git a/Gemfile.lock b/Gemfile.lock index eff33ff5..381c2b7e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,15 +1,9 @@ -GIT - remote: https://github.com/Shopify/liquid-c.git - revision: 5a786af7284df55e013ea20551c4b688d02e8326 - ref: main - specs: - liquid-c (4.2.0) - liquid (>= 5.0.1) - PATH remote: . specs: - liquid (5.6.0.alpha) + liquid (5.8.7) + bigdecimal + strscan (>= 3.1.1) GEM remote: https://rubygems.org/ @@ -17,8 +11,10 @@ GEM ast (2.4.2) base64 (0.2.0) benchmark-ips (2.13.0) + bigdecimal (3.2.3) json (2.7.2) language_server-protocol (3.17.0.3) + lru_redux (1.1.0) memory_profiler (1.0.1) minitest (5.22.3) parallel (1.24.0) @@ -50,6 +46,7 @@ GEM rubocop (~> 1.44) ruby-progressbar (1.13.0) stackprof (0.2.26) + strscan (3.1.5) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) unicode-display_width (2.5.0) @@ -62,7 +59,7 @@ DEPENDENCIES base64 benchmark-ips liquid! - liquid-c! + lru_redux memory_profiler minitest rake (~> 13.0) diff --git a/example/server/templates/index.liquid b/example/server/templates/index.liquid index 0862f216..a7a637db 100644 --- a/example/server/templates/index.liquid +++ b/example/server/templates/index.liquid @@ -5,12 +5,12 @@ Inline Snippets -
+ {% assign foo = true %} - {% assign link = "variable" %} - + {% assign linktext = "variable" %} + {% snippet main %} {% assign foo = false %}

Hi {{ arg | upcase }}!!!

@@ -18,7 +18,7 @@

This is an inline snippet

diff --git a/lib/liquid/tags/render.rb b/lib/liquid/tags/render.rb index e84397b0..db8fa768 100644 --- a/lib/liquid/tags/render.rb +++ b/lib/liquid/tags/render.rb @@ -52,14 +52,24 @@ module Liquid def render_tag(context, output) template_name = @template_name_expr + is_inline = template_name.is_a?(VariableLookup) + is_file = template_name.is_a?(String) - # For inline snippets, @template_name_expr is a VariableLookup - if template_name.is_a?(VariableLookup) - - snippet_drop = context[template_name.name] - + if is_inline + template_name = template_name.name + snippet_drop = context[template_name] raise ::ArgumentError unless snippet_drop.is_a?(Liquid::SnippetDrop) + partial = snippet_drop.body + else + raise ::ArgumentError unless is_file + + partial = PartialCache.load(template_name, context: context, parse_context: parse_context) + end + + context_variable_name = @alias_name || template_name.split('/').last + + render_partial_func = ->(var, forloop) { inner_context = context.new_isolated_subcontext if is_file @@ -68,7 +78,6 @@ module Liquid end if is_inline && inherit_context? - context.scopes.each do |scope| scope.each do |key, value| inner_context[key] = value @@ -80,30 +89,9 @@ module Liquid inner_context[key] = context.evaluate(value) end - return output << snippet_drop.body.render(inner_context) - end - - # Otherwise, the expression should be a String literal, which parses to a String object - raise ::ArgumentError unless template_name.is_a?(String) - - 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 = partial.name - inner_context.partial = true - inner_context['forloop'] = forloop if forloop - - @attributes.each do |key, value| - inner_context[key] = context.evaluate(value) - end inner_context[context_variable_name] = var unless var.nil? + inner_context['forloop'] = forloop if forloop + partial.render_to_output_buffer(inner_context, output) forloop&.send(:increment!) } diff --git a/lib/liquid/tags/snippet.rb b/lib/liquid/tags/snippet.rb index e1d978b6..aede69b7 100644 --- a/lib/liquid/tags/snippet.rb +++ b/lib/liquid/tags/snippet.rb @@ -18,8 +18,9 @@ module Liquid def initialize(tag_name, markup, options) super - if markup =~ SYNTAX - @to = Regexp.last_match(1) + p = @parse_context.new_parser(markup) + if p.look(:id) + @to = p.consume(:id) else raise SyntaxError, options[:locale].t("errors.syntax.snippet") end diff --git a/test/integration/tags/render_tag_test.rb b/test/integration/tags/render_tag_test.rb index d6453fb5..e4ce0c29 100644 --- a/test/integration/tags/render_tag_test.rb +++ b/test/integration/tags/render_tag_test.rb @@ -102,7 +102,9 @@ class RenderTagTest < Minitest::Test end def test_dynamically_choosen_templates_are_not_allowed - assert_syntax_error("{% assign name = 'snippet' %}{% render name %}") + assert_raises(::ArgumentError) do + Template.parse('{% assign name = "snippet" %}{% render name %}').render! + end end def test_rigid_parsing_errors diff --git a/test/integration/tags/snippet_test.rb b/test/integration/tags/snippet_test.rb index 9824a16e..8699b359 100644 --- a/test/integration/tags/snippet_test.rb +++ b/test/integration/tags/snippet_test.rb @@ -319,31 +319,31 @@ class SnippetTest < Minitest::Test end def test_render_inline_snippet_with_outside_context_rigid - template = <<~LIQUID.strip - {% assign color_scheme = 'dark' %} + template = <<~LIQUID.strip + {% assign color_scheme = 'dark' %} - {% snippet header %} -
- {{ message }} -
- {% endsnippet %} + {% snippet header %} +
+ {{ message }} +
+ {% endsnippet %} - {% render header, ..., message: 'Welcome!' %} - LIQUID - expected = <<~OUTPUT + {% render header, ..., message: 'Welcome!' %} + LIQUID + expected = <<~OUTPUT -
- Welcome! -
- OUTPUT +
+ Welcome! +
+ OUTPUT - assert_template_result(expected, template, error_mode: :rigid) + assert_template_result(expected, template, error_mode: :rigid) end def test_inline_snippet_local_scope_takes_precedence @@ -467,83 +467,94 @@ class SnippetTest < Minitest::Test assert_template_result(expected, template) end - # def test_render_inline_snippet_inside_loop - # template = <<~LIQUID.strip - # {% assign color_scheme = 'dark' %} - # {% assign array = '1,2,3' | split: ',' %} + def test_render_inline_snippet_forloop + template = <<~LIQUID.strip + {% snippet item %} +
  • {{ forloop.index }}: {{ item }}
  • + {% endsnippet %} - # {% for i in array %} - # {% snippet header %} - #
    - # {{ message }} {{ i }} - #
    - # {% endsnippet %} - # {% endfor %} + {% assign items = "A,B,C" | split: "," %} + {%- render item for items -%} + LIQUID + expected = <<~OUTPUT - # {% render header, ..., message: '👉' %} - # LIQUID - # expected = <<~OUTPUT - #
    - # 👉 3 - #
    - # OUTPUT - # assert_template_result(expected, template) - # end +
  • 1: A
  • - # def test_render_inline_snippet_forloop - # template = <<~LIQUID.strip - # {% snippet item %} - #
  • {{ forloop.index }}: {{ item }}
  • - # {% endsnippet %} +
  • 2: B
  • - # {% assign items = "A,B,C" | split: "," %} - # {%- render item for items -%} - # LIQUID - # expected = <<~OUTPUT +
  • 3: C
  • + OUTPUT - #
  • 1: A
  • + assert_template_result(expected, template) + end - #
  • 2: B
  • + def test_render_inline_snippet_with + template = <<~LIQUID.strip + {% snippet header %} +
    {{ header }}
    + {% endsnippet %} - #
  • 3: C
  • - # OUTPUT + {% assign product = "Apple" %} + {%- render header with product -%} + LIQUID + expected = <<~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 - #
    Apple
    - # OUTPUT + assert_template_result(expected, template) + end - # assert_template_result(expected, template) - # end + def test_render_inline_snippet_alias + template = <<~LIQUID.strip + {% snippet product_card %} +
    {{ item }}
    + {% endsnippet %} - # 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 - # {% assign featured = "Apple" %} - # {%- render product_card with featured as item -%} - # LIQUID - # expected = <<~OUTPUT - #
    Apple
    - # OUTPUT - # assert_template_result(expected, template) - # end +
    Apple
    + OUTPUT + + assert_template_result(expected, template) + end + + def test_render_inline_snippet_inside_loop + template = <<~LIQUID.strip + {% assign color_scheme = 'dark' %} + {% assign array = '1,2,3' | split: ',' %} + + {% for i in array %} + {% snippet header %} +
    + {{ message }} {{ i }} +
    + {% endsnippet %} + {% endfor %} + + {% render header, ..., message: '👉' %} + LIQUID + expected = <<~OUTPUT + + + + + + +
    + 👉#{" "} +
    + OUTPUT + + assert_template_result(expected, template) + end end