diff --git a/lib/herb/engine/compiler.rb b/lib/herb/engine/compiler.rb
index f662a9959..67c602aad 100644
--- a/lib/herb/engine/compiler.rb
+++ b/lib/herb/engine/compiler.rb
@@ -350,11 +350,14 @@ def process_erb_tag(node, skip_comment_check: false)
end
return if erb_graphql?(opening)
- code = node.content.value.strip
+ raw_content = node.content.value
+ code = raw_content.strip
if erb_output?(opening)
process_erb_output(node, opening, code)
else
+ code = "\n#{code}" if raw_content.start_with?("\n")
+ code = "#{code}\n" if raw_content.match?(/\n[ \t]*\z/)
apply_trim(node, code)
end
end
@@ -590,7 +593,11 @@ def apply_trim(node, code)
if at_line_start?
leading_space = extract_and_remove_leading_space!
effective_leading_space = leading_space.empty? ? removed_whitespace : leading_space
- right_space = Herb::Engine.heredoc?(code) ? "\n" : " \n"
+ right_space = if code.end_with?("\n") || Herb::Engine.heredoc?(code)
+ "\n"
+ else
+ " \n"
+ end
@pending_leading_whitespace_insert_index = @tokens.length
@pending_leading_whitespace = effective_leading_space if !effective_leading_space.empty? && follows_newline
diff --git a/test/engine/whitespace_trimming_test.rb b/test/engine/whitespace_trimming_test.rb
index c31f1501e..efaa51974 100644
--- a/test/engine/whitespace_trimming_test.rb
+++ b/test/engine/whitespace_trimming_test.rb
@@ -364,5 +364,17 @@ class WhitespaceTrimmingTest < Minitest::Spec
assert_compiled_snapshot(template)
assert_evaluated_snapshot(template, enforce_erubi_equality: true)
end
+
+ test "multi-line code block preserves line count parity with erubi" do
+ template = "<%\n x = 1\n y = 2\n%>\n<%= x %>"
+
+ herb_engine = assert_compiled_snapshot(template)
+ erubi_engine = Erubi::Engine.new(template)
+
+ assert_equal erubi_engine.src.lines.count, herb_engine.src.lines.count,
+ "Herb should preserve line count for multi-line code blocks.\n " \
+ "Erubi (#{erubi_engine.src.lines.count} lines): #{erubi_engine.src.inspect}\n " \
+ "Herb (#{herb_engine.src.lines.count} lines): #{herb_engine.src.inspect}"
+ end
end
end
diff --git a/test/snapshots/engine/block_comments_test/test_0001_ruby_block_comments_with_=begin_and_=end_multiline_ff404c4e708f59f532b4042441e458ad.txt b/test/snapshots/engine/block_comments_test/test_0001_ruby_block_comments_with_=begin_and_=end_multiline_ff404c4e708f59f532b4042441e458ad.txt
index 1bde0c723..3a7c2e170 100644
--- a/test/snapshots/engine/block_comments_test/test_0001_ruby_block_comments_with_=begin_and_=end_multiline_ff404c4e708f59f532b4042441e458ad.txt
+++ b/test/snapshots/engine/block_comments_test/test_0001_ruby_block_comments_with_=begin_and_=end_multiline_ff404c4e708f59f532b4042441e458ad.txt
@@ -3,10 +3,12 @@ source: "Engine::BlockCommentsTest#test_0001_ruby block comments with =begin and
input: "{source: \"<%\\n=begin %>\\n This, while unusual, is a legal form of commenting.\\n<%\\n=end %>\\n
Hey there
\\n\", options: {}}"
---
_buf = ::String.new;
+
=begin
_buf << ' This, while unusual, is a legal form of commenting.
'.freeze;
+
=end
_buf << 'Hey there
diff --git a/test/snapshots/engine/block_comments_test/test_0002_ruby_block_comments_inside_erb_tags_95bcfa3f3e28634bf923f18df0cd38a1.txt b/test/snapshots/engine/block_comments_test/test_0002_ruby_block_comments_inside_erb_tags_95bcfa3f3e28634bf923f18df0cd38a1.txt
index 26d9b7e78..b1c8903ae 100644
--- a/test/snapshots/engine/block_comments_test/test_0002_ruby_block_comments_inside_erb_tags_95bcfa3f3e28634bf923f18df0cd38a1.txt
+++ b/test/snapshots/engine/block_comments_test/test_0002_ruby_block_comments_inside_erb_tags_95bcfa3f3e28634bf923f18df0cd38a1.txt
@@ -3,9 +3,11 @@ source: "Engine::BlockCommentsTest#test_0002_ruby block comments inside erb tags
input: "{source: \"<%\\n=begin\\nThis is a comment\\n=end\\n%>\\nContent
\\n\", options: {}}"
---
_buf = ::String.new;
+
=begin
This is a comment
-=end
+=end
+
_buf << 'Content
'.freeze;
diff --git a/test/snapshots/engine/block_comments_test/test_0003_ruby_block_comments_with_code_before_and_after_0ee0ba8a9a25359175b884cf66f37b2c.txt b/test/snapshots/engine/block_comments_test/test_0003_ruby_block_comments_with_code_before_and_after_0ee0ba8a9a25359175b884cf66f37b2c.txt
index a99b44c90..01184dd3f 100644
--- a/test/snapshots/engine/block_comments_test/test_0003_ruby_block_comments_with_code_before_and_after_0ee0ba8a9a25359175b884cf66f37b2c.txt
+++ b/test/snapshots/engine/block_comments_test/test_0003_ruby_block_comments_with_code_before_and_after_0ee0ba8a9a25359175b884cf66f37b2c.txt
@@ -4,10 +4,12 @@ input: "{source: \"<% x = 1 %>\\n<%\\n=begin\\nMulti-line comment\\nspanning mul
---
_buf = ::String.new; x = 1
+
=begin
Multi-line comment
spanning multiple lines
-=end
+=end
+
y = 2
_buf << ''.freeze; _buf << (x + y).to_s; _buf << '
diff --git a/test/snapshots/engine/block_comments_test/test_0007_ruby_block_comments_with_=begin_and_=end_mutliline_and_no_space_before_ERB_closing_tag_72379778fa34572e48b949a780f761b1.txt b/test/snapshots/engine/block_comments_test/test_0007_ruby_block_comments_with_=begin_and_=end_mutliline_and_no_space_before_ERB_closing_tag_72379778fa34572e48b949a780f761b1.txt
index adb7e49a9..144f8e6cc 100644
--- a/test/snapshots/engine/block_comments_test/test_0007_ruby_block_comments_with_=begin_and_=end_mutliline_and_no_space_before_ERB_closing_tag_72379778fa34572e48b949a780f761b1.txt
+++ b/test/snapshots/engine/block_comments_test/test_0007_ruby_block_comments_with_=begin_and_=end_mutliline_and_no_space_before_ERB_closing_tag_72379778fa34572e48b949a780f761b1.txt
@@ -3,10 +3,12 @@ source: "Engine::BlockCommentsTest#test_0007_ruby block comments with =begin and
input: "{source: \"<%\\n=begin%>\\n This, while unusual, is a legal form of commenting.\\n<%\\n=end%>\\nHey there
\\n\", options: {}}"
---
_buf = ::String.new;
+
=begin
_buf << ' This, while unusual, is a legal form of commenting.
'.freeze;
+
=end
_buf << 'Hey there
diff --git a/test/snapshots/engine/engine_test/test_0019_heredoc_in_code_tag_compiles_to_valid_Ruby_4af6472f81c8026291897a7a34e6ae0b.txt b/test/snapshots/engine/engine_test/test_0019_heredoc_in_code_tag_compiles_to_valid_Ruby_4af6472f81c8026291897a7a34e6ae0b.txt
index 39be3c687..090bd0828 100644
--- a/test/snapshots/engine/engine_test/test_0019_heredoc_in_code_tag_compiles_to_valid_Ruby_4af6472f81c8026291897a7a34e6ae0b.txt
+++ b/test/snapshots/engine/engine_test/test_0019_heredoc_in_code_tag_compiles_to_valid_Ruby_4af6472f81c8026291897a7a34e6ae0b.txt
@@ -2,7 +2,9 @@
source: "Engine::EngineTest#test_0019_heredoc in code tag compiles to valid Ruby"
input: "{source: \"<%\\n text = <<~TEXT\\n Hello, world!\\n TEXT\\n%>\\n\", options: {}}"
---
-_buf = ::String.new; text = <<~TEXT
+_buf = ::String.new;
+text = <<~TEXT
Hello, world!
TEXT
+
_buf.to_s
diff --git a/test/snapshots/engine/engine_test/test_0021_heredoc_with_dash_syntax_in_code_tag_compiles_to_valid_Ruby_61fc267bae73b15dae254d0d5f9fbe0e.txt b/test/snapshots/engine/engine_test/test_0021_heredoc_with_dash_syntax_in_code_tag_compiles_to_valid_Ruby_61fc267bae73b15dae254d0d5f9fbe0e.txt
index 00793dd4b..0405f6037 100644
--- a/test/snapshots/engine/engine_test/test_0021_heredoc_with_dash_syntax_in_code_tag_compiles_to_valid_Ruby_61fc267bae73b15dae254d0d5f9fbe0e.txt
+++ b/test/snapshots/engine/engine_test/test_0021_heredoc_with_dash_syntax_in_code_tag_compiles_to_valid_Ruby_61fc267bae73b15dae254d0d5f9fbe0e.txt
@@ -2,7 +2,9 @@
source: "Engine::EngineTest#test_0021_heredoc with dash syntax in code tag compiles to valid Ruby"
input: "{source: \"<%\\n text = <<-TEXT\\n Hello, world!\\n TEXT\\n%>\\n\", options: {}}"
---
-_buf = ::String.new; text = <<-TEXT
+_buf = ::String.new;
+text = <<-TEXT
Hello, world!
TEXT
+
_buf.to_s
diff --git a/test/snapshots/engine/engine_test/test_0022_heredoc_with_quoted_identifier_in_code_tag_compiles_to_valid_Ruby_c596f2621d8ae2223c3805e78ff1b3e3.txt b/test/snapshots/engine/engine_test/test_0022_heredoc_with_quoted_identifier_in_code_tag_compiles_to_valid_Ruby_c596f2621d8ae2223c3805e78ff1b3e3.txt
index c6c198568..18e779c7e 100644
--- a/test/snapshots/engine/engine_test/test_0022_heredoc_with_quoted_identifier_in_code_tag_compiles_to_valid_Ruby_c596f2621d8ae2223c3805e78ff1b3e3.txt
+++ b/test/snapshots/engine/engine_test/test_0022_heredoc_with_quoted_identifier_in_code_tag_compiles_to_valid_Ruby_c596f2621d8ae2223c3805e78ff1b3e3.txt
@@ -2,7 +2,9 @@
source: "Engine::EngineTest#test_0022_heredoc with quoted identifier in code tag compiles to valid Ruby"
input: "{source: \"<%\\n text = <<~'TEXT'\\n Hello, world!\\n TEXT\\n%>\\n\", options: {}}"
---
-_buf = ::String.new; text = <<~'TEXT'
+_buf = ::String.new;
+text = <<~'TEXT'
Hello, world!
TEXT
+
_buf.to_s
diff --git a/test/snapshots/engine/examples_compilation_test/test_0004_block_comment_compilation_d5c98b9f230e001f8aabf838d3774698.txt b/test/snapshots/engine/examples_compilation_test/test_0004_block_comment_compilation_d5c98b9f230e001f8aabf838d3774698.txt
index c88d96943..eb96167ff 100644
--- a/test/snapshots/engine/examples_compilation_test/test_0004_block_comment_compilation_d5c98b9f230e001f8aabf838d3774698.txt
+++ b/test/snapshots/engine/examples_compilation_test/test_0004_block_comment_compilation_d5c98b9f230e001f8aabf838d3774698.txt
@@ -3,10 +3,12 @@ source: "Engine::ExamplesCompilationTest#test_0004_block comment compilation"
input: "{source: \"<%\\n=begin %>\\n This, while unusual, is a legal form of commenting.\\n<%\\n=end %>\\n\\nContent
\\n\", options: {escape: false}}"
---
_buf = ::String.new;
+
=begin
_buf << ' This, while unusual, is a legal form of commenting.
'.freeze;
+
=end
_buf << '
diff --git a/test/snapshots/engine/whitespace_trimming_test/test_0045_multi-line_code_block_preserves_line_count_parity_with_erubi_056ad410b82f521050ab536ab6d01f5f.txt b/test/snapshots/engine/whitespace_trimming_test/test_0045_multi-line_code_block_preserves_line_count_parity_with_erubi_056ad410b82f521050ab536ab6d01f5f.txt
new file mode 100644
index 000000000..3143cbef1
--- /dev/null
+++ b/test/snapshots/engine/whitespace_trimming_test/test_0045_multi-line_code_block_preserves_line_count_parity_with_erubi_056ad410b82f521050ab536ab6d01f5f.txt
@@ -0,0 +1,10 @@
+---
+source: "Engine::WhitespaceTrimmingTest#test_0045_multi-line code block preserves line count parity with erubi"
+input: "{source: \"<%\\n x = 1\\n y = 2\\n%>\\n<%= x %>\", options: {}}"
+---
+_buf = ::String.new;
+x = 1
+ y = 2
+
+ _buf << (x).to_s;
+_buf.to_s