From c78bf20010e61e2d73e04ee81f391482f5c1094c Mon Sep 17 00:00:00 2001 From: "Charles-P. Clermont" Date: Tue, 30 Sep 2025 15:46:17 -0400 Subject: [PATCH] Add a rigid_parse method to `cycle` --- lib/liquid/tags/cycle.rb | 53 +++++++++++++++++++------ test/integration/tags/cycle_tag_test.rb | 15 +++++++ 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/lib/liquid/tags/cycle.rb b/lib/liquid/tags/cycle.rb index c2d94d5f..8f4d0689 100644 --- a/lib/liquid/tags/cycle.rb +++ b/lib/liquid/tags/cycle.rb @@ -22,18 +22,7 @@ module Liquid def initialize(tag_name, markup, options) super - case markup - when NamedSyntax - @variables = variables_from_string(Regexp.last_match(2)) - @name = parse_expression(Regexp.last_match(1)) - @is_named = true - when SimpleSyntax - @variables = variables_from_string(markup) - @name = @variables.to_s - @is_named = !@name.match?(/\w+:0x\h{8}/) - else - raise SyntaxError, options[:locale].t("errors.syntax.cycle") - end + parse_with_selected_parser(markup) end def named? @@ -65,6 +54,46 @@ module Liquid private + # cycle [name:] expression(, expression)* + def rigid_parse(markup) + $stderr.puts "using rigid" + p = @parse_context.new_parser(markup) + + if p.look(:id) && p.peek(1) == :colon + @name = p.consume(:id) + @is_named = true + p.consume(:colon) + end + + @variables = [] + while (var = p.expression) + @variables << var + break unless p.consume?(:comma) + end + + raise_syntax_error(options) if @variables.empty? + end + + # Temporarily until we migrate + def strict_parse(markup) + lax_parse(markup) + end + + def lax_parse(markup) + case markup + when NamedSyntax + @variables = variables_from_string(Regexp.last_match(2)) + @name = parse_expression(Regexp.last_match(1)) + @is_named = true + when SimpleSyntax + @variables = variables_from_string(markup) + @name = @variables.to_s + @is_named = !@name.match?(/\w+:0x\h{8}/) + else + raise SyntaxError, options[:locale].t("errors.syntax.cycle") + end + end + def variables_from_string(markup) markup.split(',').collect do |var| var =~ /\s*(#{QuotedFragment})\s*/o diff --git a/test/integration/tags/cycle_tag_test.rb b/test/integration/tags/cycle_tag_test.rb index a034db17..8cd6daac 100644 --- a/test/integration/tags/cycle_tag_test.rb +++ b/test/integration/tags/cycle_tag_test.rb @@ -45,4 +45,19 @@ class CycleTagTest < Minitest::Test assert_template_result("11", template) end + + def test_cycle_tag_with_error_mode + # QuotedFragment is more permissive than what Parser#expression allows. + [:lax, :strict].each do |mode| + with_error_mode(mode) do + assert_template_result("a", "{% cycle .5: 'a', 'b' %}") + assert_template_result("b", "{% assign 5 = 'b' %}{% cycle .5, .4 %}") + end + end + + with_error_mode(:rigid) do + assert_raises(Liquid::SyntaxError) { Template.parse("{% cycle .5: 'a', 'b' %}") } + assert_raises(Liquid::SyntaxError) { Template.parse("{% cycle .5, .4 %}") } + end + end end