From 63cbedc5d916e41e4c592ff6e22726dcb8dc6b35 Mon Sep 17 00:00:00 2001 From: Felipe Felix Date: Mon, 8 Sep 2025 11:37:19 -0300 Subject: [PATCH 1/2] Convert ERB code into Ruby before type-checking Use class << self for private methods --- lib/steep.rb | 1 + lib/steep/source.rb | 2 + lib/steep/source/erb_to_ruby_code.rb | 112 +++++++++++++++++++++ sig/steep/source/erb_to_ruby_code.rbs | 27 +++++ sig/test/cli_test.rbs | 4 + sig/test/source/erb_to_ruby_code_test.rbs | 19 ++++ test/cli_test.rb | 46 +++++++++ test/source/erb_to_ruby_code_test.rb | 115 ++++++++++++++++++++++ 8 files changed, 326 insertions(+) create mode 100644 lib/steep/source/erb_to_ruby_code.rb create mode 100644 sig/steep/source/erb_to_ruby_code.rbs create mode 100644 sig/test/source/erb_to_ruby_code_test.rbs create mode 100644 test/source/erb_to_ruby_code_test.rb diff --git a/lib/steep.rb b/lib/steep.rb index 2b582cbba..0da69015e 100644 --- a/lib/steep.rb +++ b/lib/steep.rb @@ -84,6 +84,7 @@ require "steep/module_helper" require "steep/source" require "steep/source/ignore_ranges" +require "steep/source/erb_to_ruby_code" require "steep/annotation_parser" require "steep/typing" require "steep/type_construction" diff --git a/lib/steep/source.rb b/lib/steep/source.rb index 2a8436a32..8ea08c6d5 100644 --- a/lib/steep/source.rb +++ b/lib/steep/source.rb @@ -38,6 +38,8 @@ def self.new_parser end def self.parse(source_code, path:, factory:) + source_code = ErbToRubyCode.convert(source_code) if path.to_s.end_with?(".erb") + buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code) node, comments = new_parser().parse_with_comments(buffer) diff --git a/lib/steep/source/erb_to_ruby_code.rb b/lib/steep/source/erb_to_ruby_code.rb new file mode 100644 index 000000000..c66628949 --- /dev/null +++ b/lib/steep/source/erb_to_ruby_code.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +module Steep + class Source + # Converts ERB template code to Ruby code by replacing ERB tags with Ruby statements + # and HTML content with spaces, preserving line numbers and basic spacing. + # + # Supports all ERB tag variations: + # - `<% ruby_code %>` - execution tags + # - `<%= ruby_code %>` - output tags + # - `<%- ruby_code %>` - execution tags with leading whitespace control + # - `<% ruby_code -%>` - execution tags with trailing whitespace control + # - `<%- ruby_code -%>` - execution tags with both leading and trailing whitespace control + # + # Adds semicolons after each ERB tag to separate multiple statements on the same line, + # except for comments (lines starting with #). + module ErbToRubyCode + ERB_TAG_PREFIX_POSITION_REGEX = /<%[-=]?/ + ERB_TAG_SUFIX_POSITION_REGEX = /%>/ + ERB_TAG_PREFIX_REGEX = /^<%[-=]?\s*/ + ERB_TAG_SUFFIX_REGEX = /\s*-?%>$/ + NON_NEWLINE_REGEX = /[^\n]/ + + private_constant :ERB_TAG_PREFIX_POSITION_REGEX, + :ERB_TAG_SUFIX_POSITION_REGEX, + :ERB_TAG_SUFFIX_REGEX, + :NON_NEWLINE_REGEX + + class << self + def convert(source_code) + idx = 0 + + while idx < source_code.length + erb_tag_prefix_position = source_code.index(ERB_TAG_PREFIX_POSITION_REGEX, idx) + break unless erb_tag_prefix_position + + replace_everything_before_erb_tag_with_whitespace(erb_tag_prefix_position:, idx:, source_code:) + + erb_tag_sufix_position = source_code.index(ERB_TAG_SUFIX_POSITION_REGEX, erb_tag_prefix_position) + if erb_tag_sufix_position.nil? + # Incomplete ERB tag, replace rest with spaces, preserving newlines + remaining = source_code[erb_tag_prefix_position..] + source_code[erb_tag_prefix_position..-1] = remaining&.gsub(NON_NEWLINE_REGEX, ' ') || '' + break + end + + erb_tag_full_content = source_code[erb_tag_prefix_position..(erb_tag_sufix_position + 1)] + unless erb_tag_full_content + raise 'Internal error: erb_tag_full_content should not be nil after finding start and end tags' + end + + erb_tag_prefix_length = erb_tag_prefix_length(erb_tag_full_content:) + erb_tag_sufix_length = erb_tag_sufix_length(erb_tag_full_content:) + + replacement_erb_tag = generate_replacement(erb_tag_full_content:, erb_tag_prefix_length:, + erb_tag_sufix_length:) + + source_code[erb_tag_prefix_position..(erb_tag_sufix_position + 1)] = replacement_erb_tag + idx = erb_tag_prefix_position + replacement_erb_tag.length + end + + replace_everything_after_erb_tag_with_whitespace(idx:, source_code:) + end + + private + + def replace_everything_before_erb_tag_with_whitespace(erb_tag_prefix_position:, idx:, source_code:) + before_erb = source_code[idx...erb_tag_prefix_position] || '' + source_code[idx...erb_tag_prefix_position] = before_erb.gsub(NON_NEWLINE_REGEX, ' ') + end + + def erb_tag_prefix_length(erb_tag_full_content:) + tag_prefix_match = erb_tag_full_content.match(ERB_TAG_PREFIX_REGEX) or raise + tag_prefix_string = tag_prefix_match[0] or raise + + tag_prefix_string.length + end + + def erb_tag_sufix_length(erb_tag_full_content:) + tag_suffix_match = erb_tag_full_content.match(ERB_TAG_SUFFIX_REGEX) or raise + tag_suffix_string = tag_suffix_match[0] or raise + + tag_suffix_string.length + end + + def generate_replacement(erb_tag_full_content:, erb_tag_prefix_length:, erb_tag_sufix_length:) + inner_with_tags_removed = inner_with_tags_removed(erb_tag_full_content:, erb_tag_prefix_length:, + erb_tag_sufix_length:) + + if inner_with_tags_removed.start_with?('#') + (' ' * erb_tag_prefix_length) + inner_with_tags_removed + (' ' * erb_tag_sufix_length) + else + "#{' ' * erb_tag_prefix_length}#{inner_with_tags_removed}#{' ' * (erb_tag_sufix_length - 1)};" + end + end + + def inner_with_tags_removed(erb_tag_full_content:, erb_tag_prefix_length:, erb_tag_sufix_length:) + erb_tag_full_content[erb_tag_prefix_length...-erb_tag_sufix_length] or raise + end + + def replace_everything_after_erb_tag_with_whitespace(idx:, source_code:) + return source_code if idx >= source_code.length + + remaining = source_code[idx..] + source_code[idx..-1] = remaining&.gsub(NON_NEWLINE_REGEX, ' ') || '' + + source_code + end + end + end + end +end diff --git a/sig/steep/source/erb_to_ruby_code.rbs b/sig/steep/source/erb_to_ruby_code.rbs new file mode 100644 index 000000000..8c784443c --- /dev/null +++ b/sig/steep/source/erb_to_ruby_code.rbs @@ -0,0 +1,27 @@ +module Steep + class Source + module ErbToRubyCode + def self.convert: (String erb_code) -> String + + private + + ERB_TAG_PREFIX_POSITION_REGEX: Regexp + ERB_TAG_SUFIX_POSITION_REGEX: Regexp + ERB_TAG_PREFIX_REGEX: Regexp + ERB_TAG_SUFFIX_REGEX: Regexp + NON_NEWLINE_REGEX: Regexp + + def self.replace_everything_before_erb_tag_with_whitespace: (idx: Integer, erb_tag_prefix_position: Integer, source_code: String) -> String + + def self.erb_tag_prefix_length: (erb_tag_full_content: String) -> Integer + + def self.erb_tag_sufix_length: (erb_tag_full_content: String) -> Integer + + def self.inner_with_tags_removed: (erb_tag_full_content: String, erb_tag_prefix_length: Integer, erb_tag_sufix_length: Integer) -> String + + def self.generate_replacement: (erb_tag_full_content: String, erb_tag_prefix_length: Integer, erb_tag_sufix_length: Integer) -> String + + def self.replace_everything_after_erb_tag_with_whitespace: (idx: Integer, source_code: String) -> String + end + end +end diff --git a/sig/test/cli_test.rbs b/sig/test/cli_test.rbs index aaf5324d1..57908fb91 100644 --- a/sig/test/cli_test.rbs +++ b/sig/test/cli_test.rbs @@ -21,6 +21,10 @@ class CLITest < Minitest::Test def test_check_failure: () -> untyped + def test_erb_check_failure: () -> untyped + + def test_erb_check_success: () -> untyped + def test_check_failure_with_formatter: () -> untyped def test_check_group__target: () -> untyped diff --git a/sig/test/source/erb_to_ruby_code_test.rbs b/sig/test/source/erb_to_ruby_code_test.rbs new file mode 100644 index 000000000..48a4dab16 --- /dev/null +++ b/sig/test/source/erb_to_ruby_code_test.rbs @@ -0,0 +1,19 @@ +class Steep::Source::ErbToRubyCodeTest < Minitest::Test + include TestHelper + + def test_erb_output_tag_to_ruby_code: () -> untyped + + def test_erb_output_tag_without_begin_space_to_ruby_code: () -> untyped + + def test_erb_output_tag_without_end_space_to_ruby_code: () -> untyped + + def test_erb_execution_tag_to_ruby_code: () -> untyped + + def test_erb_with_dash_to_ruby_code: () -> untyped + + def test_erb_to_ruby_code_handles_comments_html_and_multiple_tags: () -> untyped + + def test_erb_multiline_tag_with_closing_on_separate_line: () -> untyped + + def test_erb_multiple_tags_same_line_conversion: () -> untyped +end diff --git a/test/cli_test.rb b/test/cli_test.rb index 310ce1720..4316a08f5 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -125,6 +125,52 @@ def test_check_failure end end + def test_erb_check_failure + in_tmpdir do + (current_dir + "Steepfile").write(<<-EOF) +target :app do + check "app/views/**/*.erb" +end + EOF + + (current_dir + "app").mkdir + (current_dir + "app/views").mkdir + (current_dir + "app/views/companies").mkdir + + (current_dir + "app/views/companies/_form.html.erb").write(<<-EOF) +
Count: <%= 1 + "2" %>
+ EOF + + stdout, status = sh(*steep, "check") + + refute_predicate status, :success?, stdout + assert_match(/Detected 1 problem from 1 file/, stdout) + end + end + + def test_erb_check_success + in_tmpdir do + (current_dir + "Steepfile").write(<<-EOF) +target :app do + check "app/views/**/*.erb" +end + EOF + + (current_dir + "app").mkdir + (current_dir + "app/views").mkdir + (current_dir + "app/views/companies").mkdir + + (current_dir + "app/views/companies/_form.html.erb").write(<<-EOF) +
Count: <%= 1 + 2 %>
+ EOF + + stdout, status = sh(*steep, "check") + + assert_predicate status, :success?, stdout + assert_match(/No type error detected\./, stdout) + end + end + def test_check_failure_with_formatter in_tmpdir do (current_dir + "Steepfile").write(<<-EOF) diff --git a/test/source/erb_to_ruby_code_test.rb b/test/source/erb_to_ruby_code_test.rb new file mode 100644 index 000000000..55f998a51 --- /dev/null +++ b/test/source/erb_to_ruby_code_test.rb @@ -0,0 +1,115 @@ +require_relative "../test_helper" + +class Steep::Source::ErbToRubyCodeTest < Minitest::Test + include TestHelper + + def test_erb_output_tag_to_ruby_code + erb_source_code = "<%= if order.with_error? %>" + expected_ruby_code = " if order.with_error? ;" + + ruby_code = Steep::Source::ErbToRubyCode.convert(erb_source_code) + + assert_equal expected_ruby_code, ruby_code + end + + def test_erb_output_tag_without_begin_space_to_ruby_code + erb_source_code = "<%=if order.with_error? %>" + expected_ruby_code = " if order.with_error? ;" + + ruby_code = Steep::Source::ErbToRubyCode.convert(erb_source_code) + + assert_equal expected_ruby_code, ruby_code + end + + def test_erb_output_tag_without_end_space_to_ruby_code + erb_source_code = "<%=if order.with_error?%>" + expected_ruby_code = " if order.with_error? ;" + + ruby_code = Steep::Source::ErbToRubyCode.convert(erb_source_code) + + assert_equal expected_ruby_code, ruby_code + end + + def test_erb_execution_tag_to_ruby_code + erb_source_code = "
Count <% 1 + '2' %>
" + expected_ruby_code = " 1 + '2' ; " + + ruby_code = Steep::Source::ErbToRubyCode.convert(erb_source_code) + + assert_equal expected_ruby_code, ruby_code + end + + def test_erb_to_ruby_code_handles_comments_html_and_multiple_tags + form_erb = < +
+ <%= user.name %> + <% if user.admin? %> + <%= link_to "Admin Panel", admin_path %> + <% end %> +

Welcome!

+
+ERB + + ruby_result = Steep::Source::ErbToRubyCode.convert(form_erb) + + expected_ruby_result = < +ERB + + expected_ruby_code = < + <%= t("messages.welcome") %> <%= current_user.name %> + +<%= link_to "Home", root_path %> +ERB + + expected_ruby_with_two_tags = < Date: Sun, 22 Mar 2026 04:32:45 -0300 Subject: [PATCH 2/2] Use Herb gem to extract Ruby code from ERB --- Gemfile | 1 + Gemfile.lock | 3 + lib/steep.rb | 1 - lib/steep/source.rb | 8 +- lib/steep/source/erb_to_ruby_code.rb | 112 --------------------- sig/steep/source/erb_to_ruby_code.rbs | 27 ----- sig/test/source/erb_to_ruby_code_test.rbs | 19 ---- steep.gemspec | 1 + test/source/erb_to_ruby_code_test.rb | 115 ---------------------- test/test_helper.rb | 2 +- 10 files changed, 13 insertions(+), 276 deletions(-) delete mode 100644 lib/steep/source/erb_to_ruby_code.rb delete mode 100644 sig/steep/source/erb_to_ruby_code.rbs delete mode 100644 sig/test/source/erb_to_ruby_code_test.rbs delete mode 100644 test/source/erb_to_ruby_code_test.rb diff --git a/Gemfile b/Gemfile index e8784ebae..2fb3f7495 100644 --- a/Gemfile +++ b/Gemfile @@ -18,3 +18,4 @@ end # gem "rbs", path: "../rbs" gem "rbs", git: "https://github.com/ruby/rbs.git", branch: "master" +gem "herb", "~> 0.9" diff --git a/Gemfile.lock b/Gemfile.lock index c7fe1ce9a..1e66a19d0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,6 +16,7 @@ PATH concurrent-ruby (>= 1.1.10) csv (>= 3.0.9) fileutils (>= 1.1.0) + herb (>= 0.9.0) json (>= 2.1.0) language_server-protocol (>= 3.17.0.4, < 4.0) listen (~> 3.0) @@ -58,6 +59,7 @@ GEM erb (6.0.2) ffi (1.17.3) fileutils (1.8.0) + herb (0.9.0) i18n (1.14.8) concurrent-ruby (~> 1.0) io-console (0.8.2) @@ -122,6 +124,7 @@ PLATFORMS DEPENDENCIES debug + herb (~> 0.9) majo memory_profiler minitest (~> 5.25) diff --git a/lib/steep.rb b/lib/steep.rb index 0da69015e..2b582cbba 100644 --- a/lib/steep.rb +++ b/lib/steep.rb @@ -84,7 +84,6 @@ require "steep/module_helper" require "steep/source" require "steep/source/ignore_ranges" -require "steep/source/erb_to_ruby_code" require "steep/annotation_parser" require "steep/typing" require "steep/type_construction" diff --git a/lib/steep/source.rb b/lib/steep/source.rb index 8ea08c6d5..6bf6d3584 100644 --- a/lib/steep/source.rb +++ b/lib/steep/source.rb @@ -1,3 +1,5 @@ +require "herb" + module Steep class Source attr_reader :buffer @@ -38,7 +40,7 @@ def self.new_parser end def self.parse(source_code, path:, factory:) - source_code = ErbToRubyCode.convert(source_code) if path.to_s.end_with?(".erb") + source_code = extract_ruby_from_erb(source_code) if path.to_s.end_with?(".erb") buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code) node, comments = new_parser().parse_with_comments(buffer) @@ -100,6 +102,10 @@ def self.parse(source_code, path:, factory:) new(buffer: buffer, path: path, node: node, mapping: map, comments: comments, ignores: ignores) end + def self.extract_ruby_from_erb(source_code) + ::Herb.extract_ruby(source_code, semicolons: true, comments: true) + end + def self.construct_mapping(node:, annotations:, mapping:, line_range: nil) case node.type when :if diff --git a/lib/steep/source/erb_to_ruby_code.rb b/lib/steep/source/erb_to_ruby_code.rb deleted file mode 100644 index c66628949..000000000 --- a/lib/steep/source/erb_to_ruby_code.rb +++ /dev/null @@ -1,112 +0,0 @@ -# frozen_string_literal: true - -module Steep - class Source - # Converts ERB template code to Ruby code by replacing ERB tags with Ruby statements - # and HTML content with spaces, preserving line numbers and basic spacing. - # - # Supports all ERB tag variations: - # - `<% ruby_code %>` - execution tags - # - `<%= ruby_code %>` - output tags - # - `<%- ruby_code %>` - execution tags with leading whitespace control - # - `<% ruby_code -%>` - execution tags with trailing whitespace control - # - `<%- ruby_code -%>` - execution tags with both leading and trailing whitespace control - # - # Adds semicolons after each ERB tag to separate multiple statements on the same line, - # except for comments (lines starting with #). - module ErbToRubyCode - ERB_TAG_PREFIX_POSITION_REGEX = /<%[-=]?/ - ERB_TAG_SUFIX_POSITION_REGEX = /%>/ - ERB_TAG_PREFIX_REGEX = /^<%[-=]?\s*/ - ERB_TAG_SUFFIX_REGEX = /\s*-?%>$/ - NON_NEWLINE_REGEX = /[^\n]/ - - private_constant :ERB_TAG_PREFIX_POSITION_REGEX, - :ERB_TAG_SUFIX_POSITION_REGEX, - :ERB_TAG_SUFFIX_REGEX, - :NON_NEWLINE_REGEX - - class << self - def convert(source_code) - idx = 0 - - while idx < source_code.length - erb_tag_prefix_position = source_code.index(ERB_TAG_PREFIX_POSITION_REGEX, idx) - break unless erb_tag_prefix_position - - replace_everything_before_erb_tag_with_whitespace(erb_tag_prefix_position:, idx:, source_code:) - - erb_tag_sufix_position = source_code.index(ERB_TAG_SUFIX_POSITION_REGEX, erb_tag_prefix_position) - if erb_tag_sufix_position.nil? - # Incomplete ERB tag, replace rest with spaces, preserving newlines - remaining = source_code[erb_tag_prefix_position..] - source_code[erb_tag_prefix_position..-1] = remaining&.gsub(NON_NEWLINE_REGEX, ' ') || '' - break - end - - erb_tag_full_content = source_code[erb_tag_prefix_position..(erb_tag_sufix_position + 1)] - unless erb_tag_full_content - raise 'Internal error: erb_tag_full_content should not be nil after finding start and end tags' - end - - erb_tag_prefix_length = erb_tag_prefix_length(erb_tag_full_content:) - erb_tag_sufix_length = erb_tag_sufix_length(erb_tag_full_content:) - - replacement_erb_tag = generate_replacement(erb_tag_full_content:, erb_tag_prefix_length:, - erb_tag_sufix_length:) - - source_code[erb_tag_prefix_position..(erb_tag_sufix_position + 1)] = replacement_erb_tag - idx = erb_tag_prefix_position + replacement_erb_tag.length - end - - replace_everything_after_erb_tag_with_whitespace(idx:, source_code:) - end - - private - - def replace_everything_before_erb_tag_with_whitespace(erb_tag_prefix_position:, idx:, source_code:) - before_erb = source_code[idx...erb_tag_prefix_position] || '' - source_code[idx...erb_tag_prefix_position] = before_erb.gsub(NON_NEWLINE_REGEX, ' ') - end - - def erb_tag_prefix_length(erb_tag_full_content:) - tag_prefix_match = erb_tag_full_content.match(ERB_TAG_PREFIX_REGEX) or raise - tag_prefix_string = tag_prefix_match[0] or raise - - tag_prefix_string.length - end - - def erb_tag_sufix_length(erb_tag_full_content:) - tag_suffix_match = erb_tag_full_content.match(ERB_TAG_SUFFIX_REGEX) or raise - tag_suffix_string = tag_suffix_match[0] or raise - - tag_suffix_string.length - end - - def generate_replacement(erb_tag_full_content:, erb_tag_prefix_length:, erb_tag_sufix_length:) - inner_with_tags_removed = inner_with_tags_removed(erb_tag_full_content:, erb_tag_prefix_length:, - erb_tag_sufix_length:) - - if inner_with_tags_removed.start_with?('#') - (' ' * erb_tag_prefix_length) + inner_with_tags_removed + (' ' * erb_tag_sufix_length) - else - "#{' ' * erb_tag_prefix_length}#{inner_with_tags_removed}#{' ' * (erb_tag_sufix_length - 1)};" - end - end - - def inner_with_tags_removed(erb_tag_full_content:, erb_tag_prefix_length:, erb_tag_sufix_length:) - erb_tag_full_content[erb_tag_prefix_length...-erb_tag_sufix_length] or raise - end - - def replace_everything_after_erb_tag_with_whitespace(idx:, source_code:) - return source_code if idx >= source_code.length - - remaining = source_code[idx..] - source_code[idx..-1] = remaining&.gsub(NON_NEWLINE_REGEX, ' ') || '' - - source_code - end - end - end - end -end diff --git a/sig/steep/source/erb_to_ruby_code.rbs b/sig/steep/source/erb_to_ruby_code.rbs deleted file mode 100644 index 8c784443c..000000000 --- a/sig/steep/source/erb_to_ruby_code.rbs +++ /dev/null @@ -1,27 +0,0 @@ -module Steep - class Source - module ErbToRubyCode - def self.convert: (String erb_code) -> String - - private - - ERB_TAG_PREFIX_POSITION_REGEX: Regexp - ERB_TAG_SUFIX_POSITION_REGEX: Regexp - ERB_TAG_PREFIX_REGEX: Regexp - ERB_TAG_SUFFIX_REGEX: Regexp - NON_NEWLINE_REGEX: Regexp - - def self.replace_everything_before_erb_tag_with_whitespace: (idx: Integer, erb_tag_prefix_position: Integer, source_code: String) -> String - - def self.erb_tag_prefix_length: (erb_tag_full_content: String) -> Integer - - def self.erb_tag_sufix_length: (erb_tag_full_content: String) -> Integer - - def self.inner_with_tags_removed: (erb_tag_full_content: String, erb_tag_prefix_length: Integer, erb_tag_sufix_length: Integer) -> String - - def self.generate_replacement: (erb_tag_full_content: String, erb_tag_prefix_length: Integer, erb_tag_sufix_length: Integer) -> String - - def self.replace_everything_after_erb_tag_with_whitespace: (idx: Integer, source_code: String) -> String - end - end -end diff --git a/sig/test/source/erb_to_ruby_code_test.rbs b/sig/test/source/erb_to_ruby_code_test.rbs deleted file mode 100644 index 48a4dab16..000000000 --- a/sig/test/source/erb_to_ruby_code_test.rbs +++ /dev/null @@ -1,19 +0,0 @@ -class Steep::Source::ErbToRubyCodeTest < Minitest::Test - include TestHelper - - def test_erb_output_tag_to_ruby_code: () -> untyped - - def test_erb_output_tag_without_begin_space_to_ruby_code: () -> untyped - - def test_erb_output_tag_without_end_space_to_ruby_code: () -> untyped - - def test_erb_execution_tag_to_ruby_code: () -> untyped - - def test_erb_with_dash_to_ruby_code: () -> untyped - - def test_erb_to_ruby_code_handles_comments_html_and_multiple_tags: () -> untyped - - def test_erb_multiline_tag_with_closing_on_separate_line: () -> untyped - - def test_erb_multiple_tags_same_line_conversion: () -> untyped -end diff --git a/steep.gemspec b/steep.gemspec index 42d84cc6d..d95bf62d9 100644 --- a/steep.gemspec +++ b/steep.gemspec @@ -52,4 +52,5 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency "strscan", ">= 1.0.0" spec.add_runtime_dependency "csv", ">= 3.0.9" spec.add_runtime_dependency "uri", ">= 0.12.0" + spec.add_runtime_dependency "herb", ">= 0.9" end diff --git a/test/source/erb_to_ruby_code_test.rb b/test/source/erb_to_ruby_code_test.rb deleted file mode 100644 index 55f998a51..000000000 --- a/test/source/erb_to_ruby_code_test.rb +++ /dev/null @@ -1,115 +0,0 @@ -require_relative "../test_helper" - -class Steep::Source::ErbToRubyCodeTest < Minitest::Test - include TestHelper - - def test_erb_output_tag_to_ruby_code - erb_source_code = "<%= if order.with_error? %>" - expected_ruby_code = " if order.with_error? ;" - - ruby_code = Steep::Source::ErbToRubyCode.convert(erb_source_code) - - assert_equal expected_ruby_code, ruby_code - end - - def test_erb_output_tag_without_begin_space_to_ruby_code - erb_source_code = "<%=if order.with_error? %>" - expected_ruby_code = " if order.with_error? ;" - - ruby_code = Steep::Source::ErbToRubyCode.convert(erb_source_code) - - assert_equal expected_ruby_code, ruby_code - end - - def test_erb_output_tag_without_end_space_to_ruby_code - erb_source_code = "<%=if order.with_error?%>" - expected_ruby_code = " if order.with_error? ;" - - ruby_code = Steep::Source::ErbToRubyCode.convert(erb_source_code) - - assert_equal expected_ruby_code, ruby_code - end - - def test_erb_execution_tag_to_ruby_code - erb_source_code = "
Count <% 1 + '2' %>
" - expected_ruby_code = " 1 + '2' ; " - - ruby_code = Steep::Source::ErbToRubyCode.convert(erb_source_code) - - assert_equal expected_ruby_code, ruby_code - end - - def test_erb_to_ruby_code_handles_comments_html_and_multiple_tags - form_erb = < -
- <%= user.name %> - <% if user.admin? %> - <%= link_to "Admin Panel", admin_path %> - <% end %> -

Welcome!

-
-ERB - - ruby_result = Steep::Source::ErbToRubyCode.convert(form_erb) - - expected_ruby_result = < -ERB - - expected_ruby_code = < - <%= t("messages.welcome") %> <%= current_user.name %> - -<%= link_to "Home", root_path %> -ERB - - expected_ruby_with_two_tags = < void } -> void def assert_any!(collection, size: nil, &block)