diff --git a/ext/herb/extension.c b/ext/herb/extension.c index 0ff90cf1..b58fb3ad 100644 --- a/ext/herb/extension.c +++ b/ext/herb/extension.c @@ -87,13 +87,30 @@ static VALUE Herb_parse_file(VALUE self, VALUE path) { return result; } -static VALUE Herb_extract_ruby(VALUE self, VALUE source) { +static VALUE Herb_extract_ruby(int argc, VALUE* argv, VALUE self) { + VALUE source, options; + rb_scan_args(argc, argv, "1:", &source, &options); + char* string = (char*) check_string(source); hb_buffer_T output; if (!hb_buffer_init(&output, strlen(string))) { return Qnil; } - herb_extract_ruby_to_buffer(string, &output); + bool semicolons = false; + if (!NIL_P(options)) { + VALUE with_semicolon_value = rb_hash_lookup(options, rb_utf8_str_new_cstr("semicolons")); + if (NIL_P(with_semicolon_value)) { + with_semicolon_value = rb_hash_lookup(options, ID2SYM(rb_intern("semicolons"))); + } + + if (!NIL_P(with_semicolon_value) && RTEST(with_semicolon_value)) { semicolons = true; } + } + + if (semicolons) { + herb_extract_ruby_to_buffer_with_semicolons(string, &output); + } else { + herb_extract_ruby_to_buffer(string, &output); + } VALUE result = rb_utf8_str_new_cstr(output.value); free(output.value); @@ -138,7 +155,7 @@ __attribute__((__visibility__("default"))) void Init_herb(void) { rb_define_singleton_method(mHerb, "lex", Herb_lex, 1); rb_define_singleton_method(mHerb, "parse_file", Herb_parse_file, 1); rb_define_singleton_method(mHerb, "lex_file", Herb_lex_file, 1); - rb_define_singleton_method(mHerb, "extract_ruby", Herb_extract_ruby, 1); + rb_define_singleton_method(mHerb, "extract_ruby", Herb_extract_ruby, -1); rb_define_singleton_method(mHerb, "extract_html", Herb_extract_html, 1); rb_define_singleton_method(mHerb, "version", Herb_version, 0); } diff --git a/sig/herb_c_extension.rbs b/sig/herb_c_extension.rbs index 1f285ca5..5447a004 100644 --- a/sig/herb_c_extension.rbs +++ b/sig/herb_c_extension.rbs @@ -4,4 +4,6 @@ module Herb def self.parse: (String input, ?track_whitespace: bool) -> ParseResult def self.lex: (String input) -> LexResult + def self.extract_ruby: (String source, ?semicolons: bool) -> String + def self.extract_html: (String source) -> String end diff --git a/test/extractor/extract_ruby_semicolons_test.rb b/test/extractor/extract_ruby_semicolons_test.rb new file mode 100644 index 00000000..77c83b56 --- /dev/null +++ b/test/extractor/extract_ruby_semicolons_test.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +module Extractor + class ExtractRubySemicolonsTest < Minitest::Spec + test "extract_ruby_single_erb_no_semicolon" do + source = "<% if %>\n<% end %>" + result = Herb.extract_ruby(source, semicolons: true) + + expected = " if \n end " + assert_equal expected, result + end + + test "extract_ruby_multiple_erb_same_line_with_semicolon" do + source = "<% x = 1 %> <% y = 2 %>" + result = Herb.extract_ruby(source, semicolons: true) + + assert_equal " x = 1 ; y = 2 ", result + end + + test "extract_ruby_three_erb_same_line_with_semicolons" do + source = "<% a = 1 %> <% b = 2 %> <% c = 3 %>" + result = Herb.extract_ruby(source, semicolons: true) + + assert_equal " a = 1 ; b = 2 ; c = 3 ", result + end + + test "extract_ruby_different_lines_no_semicolons" do + source = "<% x = 1 %>\n<% y = 2 %>" + result = Herb.extract_ruby(source, semicolons: true) + + expected = " x = 1 \n y = 2 " + assert_equal expected, result + end + + test "extract_ruby_mixed_lines" do + source = "<% a = 1 %> <% b = 2 %>\n<% c = 3 %>" + result = Herb.extract_ruby(source, semicolons: true) + + expected = " a = 1 ; b = 2 \n c = 3 " + assert_equal expected, result + end + + test "extract_ruby_output_tags_same_line" do + source = "<%= x %> <%= y %>" + result = Herb.extract_ruby(source, semicolons: true) + + assert_equal " x ; y ", result + end + + test "extract_ruby_empty_erb_same_line" do + source = "<% %> <% %>" + result = Herb.extract_ruby(source, semicolons: true) + + assert_equal " ; ", result + end + + test "extract_ruby_comments_skipped" do + source = "<%# comment %> <% code %>" + result = Herb.extract_ruby(source, semicolons: true) + + assert_equal " code ", result + end + + test "extract_ruby_issue_135_if_without_condition" do + source = "<% if %>\n<% end %>" + result = Herb.extract_ruby(source, semicolons: true) + + expected = " if \n end " + assert_equal expected, result + end + + test "extract_ruby_inline_comment_same_line" do + source = "<% if true %><% # Comment here %><% end %>" + result = Herb.extract_ruby(source, semicolons: true) + + assert_equal " if true ; end ", result + end + + test "extract_ruby_inline_comment_with_newline" do + source = "<% if true %><% # Comment here %>\n<% end %>" + result = Herb.extract_ruby(source, semicolons: true) + + expected = " if true ; \n end " + assert_equal expected, result + end + + test "extract_ruby_inline_comment_with_spaces" do + source = "<% # Comment %> <% code %>" + result = Herb.extract_ruby(source, semicolons: true) + + assert_equal " code ", result + end + + test "extract_ruby_inline_comment_multiline" do + source = "<% # Comment\nmore %> <% code %>" + result = Herb.extract_ruby(source, semicolons: true) + + expected = " # Comment\nmore ; code " + assert_equal expected, result + end + + test "extract_ruby_inline_comment_between_code" do + source = "<% if true %><% # Comment here %><%= hello %><% end %>" + result = Herb.extract_ruby(source, semicolons: true) + + assert_equal " if true ; hello ; end ", result + end + + test "extract_ruby_inline_comment_complex" do + source = "<% # Comment here %><% if true %><% # Comment here %><%= hello %><% end %>" + result = Herb.extract_ruby(source, semicolons: true) + + assert_equal " if true ; hello ; end ", result + end + end +end