From 35d5595706a3034a409d3e903adfd9f5f6818e8d Mon Sep 17 00:00:00 2001 From: Tim Tilberg Date: Thu, 25 Jun 2026 10:47:55 -0500 Subject: [PATCH 1/3] Allow inline pattern match expressions outside of case statements --- examples/in_as_expression.html.erb | 7 ++ src/analyze/analyze_helpers.c | 8 +- test/parser/match_predicate_test.rb | 46 +++++++++ ...ation_62286870c09e87da8fa0d1f862c811fe.txt | 13 +++ ...tion_0416edce0119986c84ba03c645b50717.txt} | 2 +- ...tion_12bf92840853103be656f8d585205a84.txt} | 2 +- ...tion_ba78b92bec7a4692a2043f2ba2ebe057.txt} | 2 +- ...tion_4ddb2a17755d3e775e3225970bc60a96.txt} | 2 +- ...tion_aa8aed9ef61b138a28efed42f4b72251.txt} | 2 +- ...tion_a702ca89e5a7ccec9e80bfc422053ffd.txt} | 2 +- ...tion_1729fad3a77618acdc687c9fb671b75b.txt} | 2 +- ...tion_d81de4ca83482c4836215ef7177d9eec.txt} | 2 +- ...tion_9c22f391d1d03fa66b3d18095354a236.txt} | 2 +- ...tion_0b1269c00fd15a74df125278ed6a9fc4.txt} | 2 +- ...tion_45fa7aa654c0dc06d1a1b9504002dfba.txt} | 2 +- ...tion_a705eb5ed83b4db368d7204baa136b36.txt} | 2 +- ...ition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt | 38 ++++++++ ...ition_c15b8d53c5b5e902b5189db1076b3819.txt | 93 +++++++++++++++++++ ...ition_8005b60bf10d027fa141d4bb52027c42.txt | 38 ++++++++ ...ssion_d9ec2e6b0c956487c77200fe980ba9d9.txt | 16 ++++ 20 files changed, 270 insertions(+), 13 deletions(-) create mode 100644 examples/in_as_expression.html.erb create mode 100644 test/parser/match_predicate_test.rb create mode 100644 test/snapshots/engine/examples_compilation_test/test_0019_in_as_expression_compilation_62286870c09e87da8fa0d1f862c811fe.txt rename test/snapshots/engine/examples_compilation_test/{test_0019_left_right_trim_compilation_0416edce0119986c84ba03c645b50717.txt => test_0020_left_right_trim_compilation_0416edce0119986c84ba03c645b50717.txt} (76%) rename test/snapshots/engine/examples_compilation_test/{test_0020_left_trim_compilation_12bf92840853103be656f8d585205a84.txt => test_0021_left_trim_compilation_12bf92840853103be656f8d585205a84.txt} (76%) rename test/snapshots/engine/examples_compilation_test/{test_0021_line_wrap_compilation_ba78b92bec7a4692a2043f2ba2ebe057.txt => test_0022_line_wrap_compilation_ba78b92bec7a4692a2043f2ba2ebe057.txt} (92%) rename test/snapshots/engine/examples_compilation_test/{test_0022_link_to_with_block_compilation_4ddb2a17755d3e775e3225970bc60a96.txt => test_0023_link_to_with_block_compilation_4ddb2a17755d3e775e3225970bc60a96.txt} (82%) rename test/snapshots/engine/examples_compilation_test/{test_0023_nested_if_and_blocks_compilation_aa8aed9ef61b138a28efed42f4b72251.txt => test_0024_nested_if_and_blocks_compilation_aa8aed9ef61b138a28efed42f4b72251.txt} (96%) rename test/snapshots/engine/examples_compilation_test/{test_0024_right_trim_compilation_a702ca89e5a7ccec9e80bfc422053ffd.txt => test_0025_right_trim_compilation_a702ca89e5a7ccec9e80bfc422053ffd.txt} (76%) rename test/snapshots/engine/examples_compilation_test/{test_0025_simple_block_compilation_1729fad3a77618acdc687c9fb671b75b.txt => test_0026_simple_block_compilation_1729fad3a77618acdc687c9fb671b75b.txt} (83%) rename test/snapshots/engine/examples_compilation_test/{test_0026_simple_erb_compilation_d81de4ca83482c4836215ef7177d9eec.txt => test_0027_simple_erb_compilation_d81de4ca83482c4836215ef7177d9eec.txt} (65%) rename test/snapshots/engine/examples_compilation_test/{test_0027_test_compilation_9c22f391d1d03fa66b3d18095354a236.txt => test_0028_test_compilation_9c22f391d1d03fa66b3d18095354a236.txt} (86%) rename test/snapshots/engine/examples_compilation_test/{test_0028_until_compilation_0b1269c00fd15a74df125278ed6a9fc4.txt => test_0029_until_compilation_0b1269c00fd15a74df125278ed6a9fc4.txt} (84%) rename test/snapshots/engine/examples_compilation_test/{test_0029_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt => test_0030_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt} (86%) rename test/snapshots/engine/examples_compilation_test/{test_0030_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt => test_0031_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt} (82%) create mode 100644 test/snapshots/parser/match_predicate_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt create mode 100644 test/snapshots/parser/match_predicate_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt create mode 100644 test/snapshots/parser/match_predicate_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt create mode 100644 test/snapshots/parser/match_predicate_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt diff --git a/examples/in_as_expression.html.erb b/examples/in_as_expression.html.erb new file mode 100644 index 000000000..0e686190f --- /dev/null +++ b/examples/in_as_expression.html.erb @@ -0,0 +1,7 @@ +

+ <% if 1 in Numeric %> +
Text1
+ <% else %> +
Text2
+ <% end %> +

diff --git a/src/analyze/analyze_helpers.c b/src/analyze/analyze_helpers.c index 7a54577f4..b0d6f2b1b 100644 --- a/src/analyze/analyze_helpers.c +++ b/src/analyze/analyze_helpers.c @@ -277,7 +277,13 @@ bool search_in_nodes(const pm_node_t* node, void* data) { analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data; if (node->type == PM_IN_NODE) { analyzed->in_node_count++; } - if (node->type == PM_MATCH_PREDICATE_NODE) { analyzed->in_node_count++; } + if (node->type == PM_CASE_MATCH_NODE) { + const pm_case_match_node_t* case_match_node = (const pm_case_match_node_t*) node; + + if (case_match_node->predicate != NULL && case_match_node->predicate->type == PM_MATCH_PREDICATE_NODE) { + analyzed->in_node_count++; + } + } pm_visit_child_nodes(node, search_in_nodes, analyzed); diff --git a/test/parser/match_predicate_test.rb b/test/parser/match_predicate_test.rb new file mode 100644 index 000000000..7255b4f2b --- /dev/null +++ b/test/parser/match_predicate_test.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +module Parser + # A one-line pattern match (`value in pattern`) is a complete boolean expression, not a + # `case`/`in` control flow clause. It shouldn't be treated as a case control flow block. + # + # See marcoroth/herb#1758. + # + class MatchPredicateTest < Minitest::Spec + include SnapshotUtils + + test "one-line pattern match against regexp as if condition" do + assert_parsed_snapshot(<<~HTML) + <% if attribute in /...+/ %> + <%= attribute %> + <% end %> + HTML + end + + test "one-line pattern match as if/else condition" do + assert_parsed_snapshot(<<~HTML) + <% if 1 in Numeric %> +
Text1
+ <% else %> +
Text2
+ <% end %> + HTML + end + + test "one-line pattern match as unless condition" do + assert_parsed_snapshot(<<~HTML) + <% unless value in [Integer] %> + <%= value %> + <% end %> + HTML + end + + test "one-line pattern match as output expression" do + assert_parsed_snapshot(<<~HTML) + <%= value in [Integer] %> + HTML + end + end +end diff --git a/test/snapshots/engine/examples_compilation_test/test_0019_in_as_expression_compilation_62286870c09e87da8fa0d1f862c811fe.txt b/test/snapshots/engine/examples_compilation_test/test_0019_in_as_expression_compilation_62286870c09e87da8fa0d1f862c811fe.txt new file mode 100644 index 000000000..ae7d78b7f --- /dev/null +++ b/test/snapshots/engine/examples_compilation_test/test_0019_in_as_expression_compilation_62286870c09e87da8fa0d1f862c811fe.txt @@ -0,0 +1,13 @@ +--- +source: "Engine::ExamplesCompilationTest#test_0019_in as expression compilation" +input: "{source: \"

\\n <% if 1 in Numeric %>\\n
Text1
\\n <% else %>\\n
Text2
\\n <% end %>\\n

\\n\", options: {escape: false}}" +--- +_buf = ::String.new; _buf << '

+'.freeze; if 1 in Numeric + _buf << '
Text1
+'.freeze; else + _buf << '
Text2
+'.freeze; end + _buf << '

+'.freeze; +_buf.to_s diff --git a/test/snapshots/engine/examples_compilation_test/test_0019_left_right_trim_compilation_0416edce0119986c84ba03c645b50717.txt b/test/snapshots/engine/examples_compilation_test/test_0020_left_right_trim_compilation_0416edce0119986c84ba03c645b50717.txt similarity index 76% rename from test/snapshots/engine/examples_compilation_test/test_0019_left_right_trim_compilation_0416edce0119986c84ba03c645b50717.txt rename to test/snapshots/engine/examples_compilation_test/test_0020_left_right_trim_compilation_0416edce0119986c84ba03c645b50717.txt index 8f70cb772..baa78159c 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0019_left_right_trim_compilation_0416edce0119986c84ba03c645b50717.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0020_left_right_trim_compilation_0416edce0119986c84ba03c645b50717.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0019_left right trim compilation" +source: "Engine::ExamplesCompilationTest#test_0020_left right trim compilation" input: "{source: \"<%- if true -%>\\n

Content

\\n<%- end -%>\\n\", options: {escape: false}}" --- _buf = ::String.new; if true diff --git a/test/snapshots/engine/examples_compilation_test/test_0020_left_trim_compilation_12bf92840853103be656f8d585205a84.txt b/test/snapshots/engine/examples_compilation_test/test_0021_left_trim_compilation_12bf92840853103be656f8d585205a84.txt similarity index 76% rename from test/snapshots/engine/examples_compilation_test/test_0020_left_trim_compilation_12bf92840853103be656f8d585205a84.txt rename to test/snapshots/engine/examples_compilation_test/test_0021_left_trim_compilation_12bf92840853103be656f8d585205a84.txt index b4c952762..ecfd64e24 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0020_left_trim_compilation_12bf92840853103be656f8d585205a84.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0021_left_trim_compilation_12bf92840853103be656f8d585205a84.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0020_left trim compilation" +source: "Engine::ExamplesCompilationTest#test_0021_left trim compilation" input: "{source: \"<%- if true %>\\n

Content

\\n<%- end %>\\n\", options: {escape: false}}" --- _buf = ::String.new; if true diff --git a/test/snapshots/engine/examples_compilation_test/test_0021_line_wrap_compilation_ba78b92bec7a4692a2043f2ba2ebe057.txt b/test/snapshots/engine/examples_compilation_test/test_0022_line_wrap_compilation_ba78b92bec7a4692a2043f2ba2ebe057.txt similarity index 92% rename from test/snapshots/engine/examples_compilation_test/test_0021_line_wrap_compilation_ba78b92bec7a4692a2043f2ba2ebe057.txt rename to test/snapshots/engine/examples_compilation_test/test_0022_line_wrap_compilation_ba78b92bec7a4692a2043f2ba2ebe057.txt index c95d9a482..5b3570d44 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0021_line_wrap_compilation_ba78b92bec7a4692a2043f2ba2ebe057.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0022_line_wrap_compilation_ba78b92bec7a4692a2043f2ba2ebe057.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0021_line wrap compilation" +source: "Engine::ExamplesCompilationTest#test_0022_line wrap compilation" input: "{source: \"
\\n\", options: {escape: false}}" --- _buf = ::String.new; _buf << '
diff --git a/test/snapshots/engine/examples_compilation_test/test_0022_link_to_with_block_compilation_4ddb2a17755d3e775e3225970bc60a96.txt b/test/snapshots/engine/examples_compilation_test/test_0023_link_to_with_block_compilation_4ddb2a17755d3e775e3225970bc60a96.txt similarity index 82% rename from test/snapshots/engine/examples_compilation_test/test_0022_link_to_with_block_compilation_4ddb2a17755d3e775e3225970bc60a96.txt rename to test/snapshots/engine/examples_compilation_test/test_0023_link_to_with_block_compilation_4ddb2a17755d3e775e3225970bc60a96.txt index e8f5143cf..5a709cfe4 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0022_link_to_with_block_compilation_4ddb2a17755d3e775e3225970bc60a96.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0023_link_to_with_block_compilation_4ddb2a17755d3e775e3225970bc60a96.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0022_link to with block compilation" +source: "Engine::ExamplesCompilationTest#test_0023_link to with block compilation" input: "{source: \"<%= link_to root_path do %>\\n
\\n Test\\n
\\n<% end %>\\n\", options: {escape: false}}" --- _buf = ::String.new; _buf << (link_to root_path do; _buf << ' diff --git a/test/snapshots/engine/examples_compilation_test/test_0023_nested_if_and_blocks_compilation_aa8aed9ef61b138a28efed42f4b72251.txt b/test/snapshots/engine/examples_compilation_test/test_0024_nested_if_and_blocks_compilation_aa8aed9ef61b138a28efed42f4b72251.txt similarity index 96% rename from test/snapshots/engine/examples_compilation_test/test_0023_nested_if_and_blocks_compilation_aa8aed9ef61b138a28efed42f4b72251.txt rename to test/snapshots/engine/examples_compilation_test/test_0024_nested_if_and_blocks_compilation_aa8aed9ef61b138a28efed42f4b72251.txt index 20a647326..0d735806b 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0023_nested_if_and_blocks_compilation_aa8aed9ef61b138a28efed42f4b72251.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0024_nested_if_and_blocks_compilation_aa8aed9ef61b138a28efed42f4b72251.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0023_nested if and blocks compilation" +source: "Engine::ExamplesCompilationTest#test_0024_nested if and blocks compilation" input: "{source: \"
\\n <%= tag.div class: \\\"div\\\" do %>\\n <% if Date.today.friday? %>\\n

\\n Happy\\n <% current_hour = Time.now.hour %>\\n\\n <% if current_hour < 12 %>\\n Early Friday\\n <% elsif current_hour >= 18 %>\\n Late Friday\\n <% else %>\\n Friday\\n <% end %>\\n

\\n <% elsif Date.today.saturday? %>\\n

\\n It's\\n Saturday\\n <%= \\\" - Time to relax!\\\" %>\\n

\\n <% else %>\\n

\\n Oh no, it's\\n Not Friday\\n <%= \\\" - Keep going!\\\" %>\\n

\\n <% end %>\\n <% end %>\\n
\\n\", options: {escape: false}}" --- _buf = ::String.new; _buf << '
diff --git a/test/snapshots/engine/examples_compilation_test/test_0024_right_trim_compilation_a702ca89e5a7ccec9e80bfc422053ffd.txt b/test/snapshots/engine/examples_compilation_test/test_0025_right_trim_compilation_a702ca89e5a7ccec9e80bfc422053ffd.txt similarity index 76% rename from test/snapshots/engine/examples_compilation_test/test_0024_right_trim_compilation_a702ca89e5a7ccec9e80bfc422053ffd.txt rename to test/snapshots/engine/examples_compilation_test/test_0025_right_trim_compilation_a702ca89e5a7ccec9e80bfc422053ffd.txt index 27bb2cb35..27fc1ae59 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0024_right_trim_compilation_a702ca89e5a7ccec9e80bfc422053ffd.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0025_right_trim_compilation_a702ca89e5a7ccec9e80bfc422053ffd.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0024_right trim compilation" +source: "Engine::ExamplesCompilationTest#test_0025_right trim compilation" input: "{source: \"<% if true -%>\\n

Content

\\n<% end -%>\\n\", options: {escape: false}}" --- _buf = ::String.new; if true diff --git a/test/snapshots/engine/examples_compilation_test/test_0025_simple_block_compilation_1729fad3a77618acdc687c9fb671b75b.txt b/test/snapshots/engine/examples_compilation_test/test_0026_simple_block_compilation_1729fad3a77618acdc687c9fb671b75b.txt similarity index 83% rename from test/snapshots/engine/examples_compilation_test/test_0025_simple_block_compilation_1729fad3a77618acdc687c9fb671b75b.txt rename to test/snapshots/engine/examples_compilation_test/test_0026_simple_block_compilation_1729fad3a77618acdc687c9fb671b75b.txt index d99461176..61e66c9ae 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0025_simple_block_compilation_1729fad3a77618acdc687c9fb671b75b.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0026_simple_block_compilation_1729fad3a77618acdc687c9fb671b75b.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0025_simple block compilation" +source: "Engine::ExamplesCompilationTest#test_0026_simple block compilation" input: "{source: \"<% tag.div do %>\\n <% if true %>\\n Hello1\\n <% else %>\\n Hello2\\n <% end %>\\n<% end %>\\n\", options: {escape: false}}" --- _buf = ::String.new; tag.div do diff --git a/test/snapshots/engine/examples_compilation_test/test_0026_simple_erb_compilation_d81de4ca83482c4836215ef7177d9eec.txt b/test/snapshots/engine/examples_compilation_test/test_0027_simple_erb_compilation_d81de4ca83482c4836215ef7177d9eec.txt similarity index 65% rename from test/snapshots/engine/examples_compilation_test/test_0026_simple_erb_compilation_d81de4ca83482c4836215ef7177d9eec.txt rename to test/snapshots/engine/examples_compilation_test/test_0027_simple_erb_compilation_d81de4ca83482c4836215ef7177d9eec.txt index 61c2eb328..13a024512 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0026_simple_erb_compilation_d81de4ca83482c4836215ef7177d9eec.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0027_simple_erb_compilation_d81de4ca83482c4836215ef7177d9eec.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0026_simple erb compilation" +source: "Engine::ExamplesCompilationTest#test_0027_simple erb compilation" input: "{source: \"<% title %>\\n\", options: {escape: false}}" --- _buf = ::String.new; title diff --git a/test/snapshots/engine/examples_compilation_test/test_0027_test_compilation_9c22f391d1d03fa66b3d18095354a236.txt b/test/snapshots/engine/examples_compilation_test/test_0028_test_compilation_9c22f391d1d03fa66b3d18095354a236.txt similarity index 86% rename from test/snapshots/engine/examples_compilation_test/test_0027_test_compilation_9c22f391d1d03fa66b3d18095354a236.txt rename to test/snapshots/engine/examples_compilation_test/test_0028_test_compilation_9c22f391d1d03fa66b3d18095354a236.txt index aac67eaed..251e6ea7b 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0027_test_compilation_9c22f391d1d03fa66b3d18095354a236.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0028_test_compilation_9c22f391d1d03fa66b3d18095354a236.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0027_test compilation" +source: "Engine::ExamplesCompilationTest#test_0028_test compilation" input: "{source: \"\\n\\n

\\n Hello World <%= RUBY_VERSION %>\\n

\\n\", options: {escape: false}}" --- _buf = ::String.new; _buf << ' diff --git a/test/snapshots/engine/examples_compilation_test/test_0028_until_compilation_0b1269c00fd15a74df125278ed6a9fc4.txt b/test/snapshots/engine/examples_compilation_test/test_0029_until_compilation_0b1269c00fd15a74df125278ed6a9fc4.txt similarity index 84% rename from test/snapshots/engine/examples_compilation_test/test_0028_until_compilation_0b1269c00fd15a74df125278ed6a9fc4.txt rename to test/snapshots/engine/examples_compilation_test/test_0029_until_compilation_0b1269c00fd15a74df125278ed6a9fc4.txt index fa0bb1cee..fde890959 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0028_until_compilation_0b1269c00fd15a74df125278ed6a9fc4.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0029_until_compilation_0b1269c00fd15a74df125278ed6a9fc4.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0028_until compilation" +source: "Engine::ExamplesCompilationTest#test_0029_until compilation" input: "{source: \"<% i = 0 %>\\n\\n<% until i == 10 %>\\n <%= i %> is less than 10\\n <% i += 1 %>\\n<% end %>\\n\", options: {escape: false}}" --- _buf = ::String.new; i = 0 diff --git a/test/snapshots/engine/examples_compilation_test/test_0029_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt b/test/snapshots/engine/examples_compilation_test/test_0030_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt similarity index 86% rename from test/snapshots/engine/examples_compilation_test/test_0029_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt rename to test/snapshots/engine/examples_compilation_test/test_0030_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt index 2163ab3cb..bf75999f5 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0029_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0030_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0029_utf8 compilation" +source: "Engine::ExamplesCompilationTest#test_0030_utf8 compilation" input: "{source: \"Sitename • Title\\n\\n<% @title = \\\"Home\\\" %>\\n\\n<%= [@title, \\\"Sitename\\\"].compact.join(\\\" • \\\") %>\\n\", options: {escape: false}}" --- _buf = ::String.new; _buf << 'Sitename • Title diff --git a/test/snapshots/engine/examples_compilation_test/test_0030_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt b/test/snapshots/engine/examples_compilation_test/test_0031_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt similarity index 82% rename from test/snapshots/engine/examples_compilation_test/test_0030_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt rename to test/snapshots/engine/examples_compilation_test/test_0031_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt index 81557f4f6..021b0d4ea 100644 --- a/test/snapshots/engine/examples_compilation_test/test_0030_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt +++ b/test/snapshots/engine/examples_compilation_test/test_0031_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt @@ -1,5 +1,5 @@ --- -source: "Engine::ExamplesCompilationTest#test_0030_while compilation" +source: "Engine::ExamplesCompilationTest#test_0031_while compilation" input: "{source: \"<% while i < 10 %>\\n <%= i %> is less than 10\\n <% i += 1 %>\\n<% end %>\\n\", options: {escape: false}}" --- _buf = ::String.new; while i < 10 diff --git a/test/snapshots/parser/match_predicate_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt b/test/snapshots/parser/match_predicate_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt new file mode 100644 index 000000000..ea12341c1 --- /dev/null +++ b/test/snapshots/parser/match_predicate_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt @@ -0,0 +1,38 @@ +--- +source: "Parser::MatchPredicateTest#test_0001_one-line pattern match against regexp as if condition" +input: |2- +<% if attribute in /...+/ %> + <%= attribute %> +<% end %> +--- +@ DocumentNode (location: (1:0)-(4:0)) +└── children: (2 items) + ├── @ ERBIfNode (location: (1:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " if attribute in /...+/ " (location: (1:2)-(1:26)) + │ ├── tag_closing: "%>" (location: (1:26)-(1:28)) + │ ├── then_keyword: ∅ + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:28)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:18)) + │ │ │ ├── tag_opening: "<%=" (location: (2:2)-(2:5)) + │ │ │ ├── content: " attribute " (location: (2:5)-(2:16)) + │ │ │ ├── tag_closing: "%>" (location: (2:16)-(2:18)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:18)-(3:0)) + │ │ └── content: "\n" + │ │ + │ ├── subsequent: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (3:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ ├── content: " end " (location: (3:2)-(3:7)) + │ └── tag_closing: "%>" (location: (3:7)-(3:9)) + │ + │ + └── @ HTMLTextNode (location: (3:9)-(4:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/parser/match_predicate_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt b/test/snapshots/parser/match_predicate_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt new file mode 100644 index 000000000..6929acb5d --- /dev/null +++ b/test/snapshots/parser/match_predicate_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt @@ -0,0 +1,93 @@ +--- +source: "Parser::MatchPredicateTest#test_0002_one-line pattern match as if/else condition" +input: |2- +<% if 1 in Numeric %> +
Text1
+<% else %> +
Text2
+<% end %> +--- +@ DocumentNode (location: (1:0)-(6:0)) +└── children: (2 items) + ├── @ ERBIfNode (location: (1:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " if 1 in Numeric " (location: (1:2)-(1:19)) + │ ├── tag_closing: "%>" (location: (1:19)-(1:21)) + │ ├── then_keyword: ∅ + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:21)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (2:2)-(2:18)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (2:2)-(2:7)) + │ │ │ │ ├── tag_opening: "<" (location: (2:2)-(2:3)) + │ │ │ │ ├── tag_name: "div" (location: (2:3)-(2:6)) + │ │ │ │ ├── tag_closing: ">" (location: (2:6)-(2:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (2:3)-(2:6)) + │ │ │ ├── body: (1 item) + │ │ │ │ └── @ HTMLTextNode (location: (2:7)-(2:12)) + │ │ │ │ └── content: "Text1" + │ │ │ │ + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (2:12)-(2:18)) + │ │ │ │ ├── tag_opening: "" (location: (2:17)-(2:18)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── element_source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:18)-(3:0)) + │ │ └── content: "\n" + │ │ + │ ├── subsequent: + │ │ └── @ ERBElseNode (location: (3:0)-(5:0)) + │ │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ │ ├── content: " else " (location: (3:2)-(3:8)) + │ │ ├── tag_closing: "%>" (location: (3:8)-(3:10)) + │ │ └── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (3:10)-(4:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (4:2)-(4:18)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (4:2)-(4:7)) + │ │ │ │ ├── tag_opening: "<" (location: (4:2)-(4:3)) + │ │ │ │ ├── tag_name: "div" (location: (4:3)-(4:6)) + │ │ │ │ ├── tag_closing: ">" (location: (4:6)-(4:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (4:3)-(4:6)) + │ │ │ ├── body: (1 item) + │ │ │ │ └── @ HTMLTextNode (location: (4:7)-(4:12)) + │ │ │ │ └── content: "Text2" + │ │ │ │ + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (4:12)-(4:18)) + │ │ │ │ ├── tag_opening: "" (location: (4:17)-(4:18)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── element_source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (4:18)-(5:0)) + │ │ └── content: "\n" + │ │ + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (5:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (5:0)-(5:2)) + │ ├── content: " end " (location: (5:2)-(5:7)) + │ └── tag_closing: "%>" (location: (5:7)-(5:9)) + │ + │ + └── @ HTMLTextNode (location: (5:9)-(6:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/parser/match_predicate_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt b/test/snapshots/parser/match_predicate_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt new file mode 100644 index 000000000..263d65666 --- /dev/null +++ b/test/snapshots/parser/match_predicate_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt @@ -0,0 +1,38 @@ +--- +source: "Parser::MatchPredicateTest#test_0003_one-line pattern match as unless condition" +input: |2- +<% unless value in [Integer] %> + <%= value %> +<% end %> +--- +@ DocumentNode (location: (1:0)-(4:0)) +└── children: (2 items) + ├── @ ERBUnlessNode (location: (1:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " unless value in [Integer] " (location: (1:2)-(1:29)) + │ ├── tag_closing: "%>" (location: (1:29)-(1:31)) + │ ├── then_keyword: ∅ + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:31)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:14)) + │ │ │ ├── tag_opening: "<%=" (location: (2:2)-(2:5)) + │ │ │ ├── content: " value " (location: (2:5)-(2:12)) + │ │ │ ├── tag_closing: "%>" (location: (2:12)-(2:14)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:14)-(3:0)) + │ │ └── content: "\n" + │ │ + │ ├── else_clause: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (3:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ ├── content: " end " (location: (3:2)-(3:7)) + │ └── tag_closing: "%>" (location: (3:7)-(3:9)) + │ + │ + └── @ HTMLTextNode (location: (3:9)-(4:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/parser/match_predicate_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt b/test/snapshots/parser/match_predicate_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt new file mode 100644 index 000000000..89e121f80 --- /dev/null +++ b/test/snapshots/parser/match_predicate_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt @@ -0,0 +1,16 @@ +--- +source: "Parser::MatchPredicateTest#test_0004_one-line pattern match as output expression" +input: |2- +<%= value in [Integer] %> +--- +@ DocumentNode (location: (1:0)-(2:0)) +└── children: (2 items) + ├── @ ERBContentNode (location: (1:0)-(1:25)) + │ ├── tag_opening: "<%=" (location: (1:0)-(1:3)) + │ ├── content: " value in [Integer] " (location: (1:3)-(1:23)) + │ ├── tag_closing: "%>" (location: (1:23)-(1:25)) + │ ├── parsed: true + │ └── valid: true + │ + └── @ HTMLTextNode (location: (1:25)-(2:0)) + └── content: "\n" \ No newline at end of file From 6ac11ae08bdc1156a094da74cf9ab9f09dd73c63 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Sun, 28 Jun 2026 18:10:43 +0200 Subject: [PATCH 2/3] Add more test cases and rename test file --- ...ch_predicate_test.rb => inline_in_test.rb} | 41 +++++- ...ition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt | 2 +- ...ition_c15b8d53c5b5e902b5189db1076b3819.txt | 2 +- ...ition_8005b60bf10d027fa141d4bb52027c42.txt | 2 +- ...ssion_d9ec2e6b0c956487c77200fe980ba9d9.txt | 2 +- ...ition_ddbf4811dcd2ae7aeabf06c24e2bb829.txt | 134 ++++++++++++++++++ ...ition_dee0cc2aa891afa7cc74dc164db4b6e4.txt | 36 +++++ ...ition_de7e6a7bdd8626a76eb12a3bb2b21a83.txt | 36 +++++ ...ssion_ec0f2afb7102885502f6fbae86e02038.txt | 16 +++ ..._body_76c175623eee5884806e73756cb200a8.txt | 68 +++++++++ 10 files changed, 329 insertions(+), 10 deletions(-) rename test/parser/{match_predicate_test.rb => inline_in_test.rb} (50%) rename test/snapshots/parser/{match_predicate_test => inline_in_test}/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt (94%) rename test/snapshots/parser/{match_predicate_test => inline_in_test}/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt (98%) rename test/snapshots/parser/{match_predicate_test => inline_in_test}/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt (94%) rename test/snapshots/parser/{match_predicate_test => inline_in_test}/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt (85%) create mode 100644 test/snapshots/parser/inline_in_test/test_0005_one-line_pattern_match_as_elsif_condition_ddbf4811dcd2ae7aeabf06c24e2bb829.txt create mode 100644 test/snapshots/parser/inline_in_test/test_0006_one-line_pattern_match_as_while_condition_dee0cc2aa891afa7cc74dc164db4b6e4.txt create mode 100644 test/snapshots/parser/inline_in_test/test_0007_one-line_pattern_match_as_until_condition_de7e6a7bdd8626a76eb12a3bb2b21a83.txt create mode 100644 test/snapshots/parser/inline_in_test/test_0008_one-line_pattern_match_in_ternary_expression_ec0f2afb7102885502f6fbae86e02038.txt create mode 100644 test/snapshots/parser/inline_in_test/test_0009_one-line_pattern_match_inside_a_block_body_76c175623eee5884806e73756cb200a8.txt diff --git a/test/parser/match_predicate_test.rb b/test/parser/inline_in_test.rb similarity index 50% rename from test/parser/match_predicate_test.rb rename to test/parser/inline_in_test.rb index 7255b4f2b..6bda7e5b7 100644 --- a/test/parser/match_predicate_test.rb +++ b/test/parser/inline_in_test.rb @@ -3,12 +3,7 @@ require_relative "../test_helper" module Parser - # A one-line pattern match (`value in pattern`) is a complete boolean expression, not a - # `case`/`in` control flow clause. It shouldn't be treated as a case control flow block. - # - # See marcoroth/herb#1758. - # - class MatchPredicateTest < Minitest::Spec + class InlineInTest < Minitest::Spec include SnapshotUtils test "one-line pattern match against regexp as if condition" do @@ -42,5 +37,39 @@ class MatchPredicateTest < Minitest::Spec <%= value in [Integer] %> HTML end + + test "one-line pattern match as elsif condition" do + assert_parsed_snapshot(<<~HTML) + <% if value in Integer %> +
Integer
+ <% elsif value in String %> +
String
+ <% else %> +
Other
+ <% end %> + HTML + end + + test "one-line pattern match as while condition" do + assert_parsed_snapshot(<<~HTML) + <% while value in Integer %> + <%= value %> + <% end %> + HTML + end + + test "one-line pattern match as until condition" do + assert_parsed_snapshot(<<~HTML) + <% until value in Done %> + <%= value %> + <% end %> + HTML + end + + test "one-line pattern match in ternary expression" do + assert_parsed_snapshot(<<~HTML) + <%= (value in Integer) ? "yes" : "no" %> + HTML + end end end diff --git a/test/snapshots/parser/match_predicate_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt b/test/snapshots/parser/inline_in_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt similarity index 94% rename from test/snapshots/parser/match_predicate_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt rename to test/snapshots/parser/inline_in_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt index ea12341c1..80d5f8e20 100644 --- a/test/snapshots/parser/match_predicate_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt +++ b/test/snapshots/parser/inline_in_test/test_0001_one-line_pattern_match_against_regexp_as_if_condition_27ed6d4e7e4dc6227c1a8ff7758e2b38.txt @@ -1,5 +1,5 @@ --- -source: "Parser::MatchPredicateTest#test_0001_one-line pattern match against regexp as if condition" +source: "Parser::InlineInTest#test_0001_one-line pattern match against regexp as if condition" input: |2- <% if attribute in /...+/ %> <%= attribute %> diff --git a/test/snapshots/parser/match_predicate_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt b/test/snapshots/parser/inline_in_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt similarity index 98% rename from test/snapshots/parser/match_predicate_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt rename to test/snapshots/parser/inline_in_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt index 6929acb5d..28d23a840 100644 --- a/test/snapshots/parser/match_predicate_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt +++ b/test/snapshots/parser/inline_in_test/test_0002_one-line_pattern_match_as_if_else_condition_c15b8d53c5b5e902b5189db1076b3819.txt @@ -1,5 +1,5 @@ --- -source: "Parser::MatchPredicateTest#test_0002_one-line pattern match as if/else condition" +source: "Parser::InlineInTest#test_0002_one-line pattern match as if/else condition" input: |2- <% if 1 in Numeric %>
Text1
diff --git a/test/snapshots/parser/match_predicate_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt b/test/snapshots/parser/inline_in_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt similarity index 94% rename from test/snapshots/parser/match_predicate_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt rename to test/snapshots/parser/inline_in_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt index 263d65666..e141efca2 100644 --- a/test/snapshots/parser/match_predicate_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt +++ b/test/snapshots/parser/inline_in_test/test_0003_one-line_pattern_match_as_unless_condition_8005b60bf10d027fa141d4bb52027c42.txt @@ -1,5 +1,5 @@ --- -source: "Parser::MatchPredicateTest#test_0003_one-line pattern match as unless condition" +source: "Parser::InlineInTest#test_0003_one-line pattern match as unless condition" input: |2- <% unless value in [Integer] %> <%= value %> diff --git a/test/snapshots/parser/match_predicate_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt b/test/snapshots/parser/inline_in_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt similarity index 85% rename from test/snapshots/parser/match_predicate_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt rename to test/snapshots/parser/inline_in_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt index 89e121f80..6f6cdd9c8 100644 --- a/test/snapshots/parser/match_predicate_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt +++ b/test/snapshots/parser/inline_in_test/test_0004_one-line_pattern_match_as_output_expression_d9ec2e6b0c956487c77200fe980ba9d9.txt @@ -1,5 +1,5 @@ --- -source: "Parser::MatchPredicateTest#test_0004_one-line pattern match as output expression" +source: "Parser::InlineInTest#test_0004_one-line pattern match as output expression" input: |2- <%= value in [Integer] %> --- diff --git a/test/snapshots/parser/inline_in_test/test_0005_one-line_pattern_match_as_elsif_condition_ddbf4811dcd2ae7aeabf06c24e2bb829.txt b/test/snapshots/parser/inline_in_test/test_0005_one-line_pattern_match_as_elsif_condition_ddbf4811dcd2ae7aeabf06c24e2bb829.txt new file mode 100644 index 000000000..3d4a31d05 --- /dev/null +++ b/test/snapshots/parser/inline_in_test/test_0005_one-line_pattern_match_as_elsif_condition_ddbf4811dcd2ae7aeabf06c24e2bb829.txt @@ -0,0 +1,134 @@ +--- +source: "Parser::InlineInTest#test_0005_one-line pattern match as elsif condition" +input: |2- +<% if value in Integer %> +
Integer
+<% elsif value in String %> +
String
+<% else %> +
Other
+<% end %> +--- +@ DocumentNode (location: (1:0)-(8:0)) +└── children: (2 items) + ├── @ ERBIfNode (location: (1:0)-(7:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " if value in Integer " (location: (1:2)-(1:23)) + │ ├── tag_closing: "%>" (location: (1:23)-(1:25)) + │ ├── then_keyword: ∅ + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:25)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (2:2)-(2:20)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (2:2)-(2:7)) + │ │ │ │ ├── tag_opening: "<" (location: (2:2)-(2:3)) + │ │ │ │ ├── tag_name: "div" (location: (2:3)-(2:6)) + │ │ │ │ ├── tag_closing: ">" (location: (2:6)-(2:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (2:3)-(2:6)) + │ │ │ ├── body: (1 item) + │ │ │ │ └── @ HTMLTextNode (location: (2:7)-(2:14)) + │ │ │ │ └── content: "Integer" + │ │ │ │ + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (2:14)-(2:20)) + │ │ │ │ ├── tag_opening: "" (location: (2:19)-(2:20)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── element_source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:20)-(3:0)) + │ │ └── content: "\n" + │ │ + │ ├── subsequent: + │ │ └── @ ERBIfNode (location: (3:0)-(5:0)) + │ │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ │ ├── content: " elsif value in String " (location: (3:2)-(3:25)) + │ │ ├── tag_closing: "%>" (location: (3:25)-(3:27)) + │ │ ├── then_keyword: ∅ + │ │ ├── statements: (3 items) + │ │ │ ├── @ HTMLTextNode (location: (3:27)-(4:2)) + │ │ │ │ └── content: "\n " + │ │ │ │ + │ │ │ ├── @ HTMLElementNode (location: (4:2)-(4:19)) + │ │ │ │ ├── open_tag: + │ │ │ │ │ └── @ HTMLOpenTagNode (location: (4:2)-(4:7)) + │ │ │ │ │ ├── tag_opening: "<" (location: (4:2)-(4:3)) + │ │ │ │ │ ├── tag_name: "div" (location: (4:3)-(4:6)) + │ │ │ │ │ ├── tag_closing: ">" (location: (4:6)-(4:7)) + │ │ │ │ │ ├── children: [] + │ │ │ │ │ └── is_void: false + │ │ │ │ │ + │ │ │ │ ├── tag_name: "div" (location: (4:3)-(4:6)) + │ │ │ │ ├── body: (1 item) + │ │ │ │ │ └── @ HTMLTextNode (location: (4:7)-(4:13)) + │ │ │ │ │ └── content: "String" + │ │ │ │ │ + │ │ │ │ ├── close_tag: + │ │ │ │ │ └── @ HTMLCloseTagNode (location: (4:13)-(4:19)) + │ │ │ │ │ ├── tag_opening: "" (location: (4:18)-(4:19)) + │ │ │ │ │ + │ │ │ │ ├── is_void: false + │ │ │ │ └── element_source: "HTML" + │ │ │ │ + │ │ │ └── @ HTMLTextNode (location: (4:19)-(5:0)) + │ │ │ └── content: "\n" + │ │ │ + │ │ ├── subsequent: + │ │ │ └── @ ERBElseNode (location: (5:0)-(7:0)) + │ │ │ ├── tag_opening: "<%" (location: (5:0)-(5:2)) + │ │ │ ├── content: " else " (location: (5:2)-(5:8)) + │ │ │ ├── tag_closing: "%>" (location: (5:8)-(5:10)) + │ │ │ └── statements: (3 items) + │ │ │ ├── @ HTMLTextNode (location: (5:10)-(6:2)) + │ │ │ │ └── content: "\n " + │ │ │ │ + │ │ │ ├── @ HTMLElementNode (location: (6:2)-(6:18)) + │ │ │ │ ├── open_tag: + │ │ │ │ │ └── @ HTMLOpenTagNode (location: (6:2)-(6:7)) + │ │ │ │ │ ├── tag_opening: "<" (location: (6:2)-(6:3)) + │ │ │ │ │ ├── tag_name: "div" (location: (6:3)-(6:6)) + │ │ │ │ │ ├── tag_closing: ">" (location: (6:6)-(6:7)) + │ │ │ │ │ ├── children: [] + │ │ │ │ │ └── is_void: false + │ │ │ │ │ + │ │ │ │ ├── tag_name: "div" (location: (6:3)-(6:6)) + │ │ │ │ ├── body: (1 item) + │ │ │ │ │ └── @ HTMLTextNode (location: (6:7)-(6:12)) + │ │ │ │ │ └── content: "Other" + │ │ │ │ │ + │ │ │ │ ├── close_tag: + │ │ │ │ │ └── @ HTMLCloseTagNode (location: (6:12)-(6:18)) + │ │ │ │ │ ├── tag_opening: "" (location: (6:17)-(6:18)) + │ │ │ │ │ + │ │ │ │ ├── is_void: false + │ │ │ │ └── element_source: "HTML" + │ │ │ │ + │ │ │ └── @ HTMLTextNode (location: (6:18)-(7:0)) + │ │ │ └── content: "\n" + │ │ │ + │ │ │ + │ │ └── end_node: ∅ + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (7:0)-(7:9)) + │ ├── tag_opening: "<%" (location: (7:0)-(7:2)) + │ ├── content: " end " (location: (7:2)-(7:7)) + │ └── tag_closing: "%>" (location: (7:7)-(7:9)) + │ + │ + └── @ HTMLTextNode (location: (7:9)-(8:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/parser/inline_in_test/test_0006_one-line_pattern_match_as_while_condition_dee0cc2aa891afa7cc74dc164db4b6e4.txt b/test/snapshots/parser/inline_in_test/test_0006_one-line_pattern_match_as_while_condition_dee0cc2aa891afa7cc74dc164db4b6e4.txt new file mode 100644 index 000000000..1fd10ed98 --- /dev/null +++ b/test/snapshots/parser/inline_in_test/test_0006_one-line_pattern_match_as_while_condition_dee0cc2aa891afa7cc74dc164db4b6e4.txt @@ -0,0 +1,36 @@ +--- +source: "Parser::InlineInTest#test_0006_one-line pattern match as while condition" +input: |2- +<% while value in Integer %> + <%= value %> +<% end %> +--- +@ DocumentNode (location: (1:0)-(4:0)) +└── children: (2 items) + ├── @ ERBWhileNode (location: (1:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " while value in Integer " (location: (1:2)-(1:26)) + │ ├── tag_closing: "%>" (location: (1:26)-(1:28)) + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:28)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:14)) + │ │ │ ├── tag_opening: "<%=" (location: (2:2)-(2:5)) + │ │ │ ├── content: " value " (location: (2:5)-(2:12)) + │ │ │ ├── tag_closing: "%>" (location: (2:12)-(2:14)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:14)-(3:0)) + │ │ └── content: "\n" + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (3:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ ├── content: " end " (location: (3:2)-(3:7)) + │ └── tag_closing: "%>" (location: (3:7)-(3:9)) + │ + │ + └── @ HTMLTextNode (location: (3:9)-(4:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/parser/inline_in_test/test_0007_one-line_pattern_match_as_until_condition_de7e6a7bdd8626a76eb12a3bb2b21a83.txt b/test/snapshots/parser/inline_in_test/test_0007_one-line_pattern_match_as_until_condition_de7e6a7bdd8626a76eb12a3bb2b21a83.txt new file mode 100644 index 000000000..82df74574 --- /dev/null +++ b/test/snapshots/parser/inline_in_test/test_0007_one-line_pattern_match_as_until_condition_de7e6a7bdd8626a76eb12a3bb2b21a83.txt @@ -0,0 +1,36 @@ +--- +source: "Parser::InlineInTest#test_0007_one-line pattern match as until condition" +input: |2- +<% until value in Done %> + <%= value %> +<% end %> +--- +@ DocumentNode (location: (1:0)-(4:0)) +└── children: (2 items) + ├── @ ERBUntilNode (location: (1:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " until value in Done " (location: (1:2)-(1:23)) + │ ├── tag_closing: "%>" (location: (1:23)-(1:25)) + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:25)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:14)) + │ │ │ ├── tag_opening: "<%=" (location: (2:2)-(2:5)) + │ │ │ ├── content: " value " (location: (2:5)-(2:12)) + │ │ │ ├── tag_closing: "%>" (location: (2:12)-(2:14)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:14)-(3:0)) + │ │ └── content: "\n" + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (3:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ ├── content: " end " (location: (3:2)-(3:7)) + │ └── tag_closing: "%>" (location: (3:7)-(3:9)) + │ + │ + └── @ HTMLTextNode (location: (3:9)-(4:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/parser/inline_in_test/test_0008_one-line_pattern_match_in_ternary_expression_ec0f2afb7102885502f6fbae86e02038.txt b/test/snapshots/parser/inline_in_test/test_0008_one-line_pattern_match_in_ternary_expression_ec0f2afb7102885502f6fbae86e02038.txt new file mode 100644 index 000000000..ef7f4cb8d --- /dev/null +++ b/test/snapshots/parser/inline_in_test/test_0008_one-line_pattern_match_in_ternary_expression_ec0f2afb7102885502f6fbae86e02038.txt @@ -0,0 +1,16 @@ +--- +source: "Parser::InlineInTest#test_0008_one-line pattern match in ternary expression" +input: |2- +<%= (value in Integer) ? "yes" : "no" %> +--- +@ DocumentNode (location: (1:0)-(2:0)) +└── children: (2 items) + ├── @ ERBContentNode (location: (1:0)-(1:40)) + │ ├── tag_opening: "<%=" (location: (1:0)-(1:3)) + │ ├── content: " (value in Integer) ? "yes" : "no" " (location: (1:3)-(1:38)) + │ ├── tag_closing: "%>" (location: (1:38)-(1:40)) + │ ├── parsed: true + │ └── valid: true + │ + └── @ HTMLTextNode (location: (1:40)-(2:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/parser/inline_in_test/test_0009_one-line_pattern_match_inside_a_block_body_76c175623eee5884806e73756cb200a8.txt b/test/snapshots/parser/inline_in_test/test_0009_one-line_pattern_match_inside_a_block_body_76c175623eee5884806e73756cb200a8.txt new file mode 100644 index 000000000..d1f6fc98e --- /dev/null +++ b/test/snapshots/parser/inline_in_test/test_0009_one-line_pattern_match_inside_a_block_body_76c175623eee5884806e73756cb200a8.txt @@ -0,0 +1,68 @@ +--- +source: "Parser::InlineInTest#test_0009_one-line pattern match inside a block body" +input: |2- +<% items.each do |n| %> + <% if n in Integer %> + <%= n %> + <% end %> +<% end %> +--- +@ DocumentNode (location: (1:0)-(6:0)) +└── children: (2 items) + ├── @ ERBBlockNode (location: (1:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " items.each do |n| " (location: (1:2)-(1:21)) + │ ├── tag_closing: "%>" (location: (1:21)-(1:23)) + │ ├── body: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:23)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBIfNode (location: (2:2)-(4:11)) + │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ │ │ ├── content: " if n in Integer " (location: (2:4)-(2:21)) + │ │ │ ├── tag_closing: "%>" (location: (2:21)-(2:23)) + │ │ │ ├── then_keyword: ∅ + │ │ │ ├── statements: (3 items) + │ │ │ │ ├── @ HTMLTextNode (location: (2:23)-(3:4)) + │ │ │ │ │ └── content: "\n " + │ │ │ │ │ + │ │ │ │ ├── @ ERBContentNode (location: (3:4)-(3:12)) + │ │ │ │ │ ├── tag_opening: "<%=" (location: (3:4)-(3:7)) + │ │ │ │ │ ├── content: " n " (location: (3:7)-(3:10)) + │ │ │ │ │ ├── tag_closing: "%>" (location: (3:10)-(3:12)) + │ │ │ │ │ ├── parsed: true + │ │ │ │ │ └── valid: true + │ │ │ │ │ + │ │ │ │ └── @ HTMLTextNode (location: (3:12)-(4:2)) + │ │ │ │ └── content: "\n " + │ │ │ │ + │ │ │ ├── subsequent: ∅ + │ │ │ └── end_node: + │ │ │ └── @ ERBEndNode (location: (4:2)-(4:11)) + │ │ │ ├── tag_opening: "<%" (location: (4:2)-(4:4)) + │ │ │ ├── content: " end " (location: (4:4)-(4:9)) + │ │ │ └── tag_closing: "%>" (location: (4:9)-(4:11)) + │ │ │ + │ │ │ + │ │ └── @ HTMLTextNode (location: (4:11)-(5:0)) + │ │ └── content: "\n" + │ │ + │ ├── block_arguments: (1 item) + │ │ └── @ RubyParameterNode (location: (1:18)-(1:19)) + │ │ ├── name: "n" (location: (1:18)-(1:19)) + │ │ ├── default_value: ∅ + │ │ ├── kind: "positional" + │ │ └── required: true + │ │ + │ ├── rescue_clause: ∅ + │ ├── else_clause: ∅ + │ ├── ensure_clause: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (5:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (5:0)-(5:2)) + │ ├── content: " end " (location: (5:2)-(5:7)) + │ └── tag_closing: "%>" (location: (5:7)-(5:9)) + │ + │ + └── @ HTMLTextNode (location: (5:9)-(6:0)) + └── content: "\n" \ No newline at end of file From a6f1bb4f4686f1892e056711bc3995f9ee700094 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Sun, 28 Jun 2026 18:27:50 +0200 Subject: [PATCH 3/3] add missing test --- test/parser/inline_in_test.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/parser/inline_in_test.rb b/test/parser/inline_in_test.rb index 6bda7e5b7..baccad436 100644 --- a/test/parser/inline_in_test.rb +++ b/test/parser/inline_in_test.rb @@ -71,5 +71,15 @@ class InlineInTest < Minitest::Spec <%= (value in Integer) ? "yes" : "no" %> HTML end + + test "one-line pattern match inside a block body" do + assert_parsed_snapshot(<<~HTML) + <% items.each do |n| %> + <% if n in Integer %> + <%= n %> + <% end %> + <% end %> + HTML + end end end