Replace `method_source` gem with stdlib equivalent

The `method_source` gem was added in
https://github.com/rails/rails/pull/19216. It was used to determine the
last line number of a given test method to support running tests by line
number. But this is not something that requires an external dependency:
Ripper can do this easily, and it has the added advantage of not using
repeated calls to `eval` to do it.

Drop `method_source` and replace it with a simple handler for Ripper's
`on_def` parser event.

I don't believe that there are any mainstream rubies at this point that
can run Rails and don't support Ripper but correct me if I'm wrong.
This commit is contained in:
Carl Brasic 2022-08-29 14:19:24 -05:00
parent 9b6abb50b2
commit 7690290068
4 changed files with 54 additions and 6 deletions

View File

@ -94,7 +94,6 @@ PATH
railties (7.1.0.alpha)
actionpack (= 7.1.0.alpha)
activesupport (= 7.1.0.alpha)
method_source
rake (>= 12.2)
thor (~> 1.0)
zeitwerk (~> 2.6)
@ -315,7 +314,6 @@ GEM
marcel (1.0.2)
matrix (0.4.2)
memoist (0.16.2)
method_source (1.0.0)
mini_magick (4.11.0)
mini_mime (1.1.2)
mini_portile2 (2.8.0)

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
require "shellwords"
require "method_source"
require "rake/file_list"
require "active_support"
require "active_support/core_ext/module/attribute_accessors"
require "ripper"
module Rails
module TestUnit
@ -169,10 +169,33 @@ module Rails
private
def definition_for(method)
file, start_line = method.source_location
end_line = method.source.count("\n") + start_line - 1
end_line = MethodEndFinder.call(source: File.read(file), target: method.name)
return file, start_line..end_line
end
# Finds the line number where the definition of method named +target+ ends.
module MethodEndFinder # :nodoc:
def self.call(source:, target:)
catch(:line_number_is) do
DefParser.new(source: source, target: target).parse
return nil
end
end
class DefParser < Ripper # :nodoc:
def initialize(source:, target:)
@target = String(target)
super(source)
end
def on_def(method_name, *)
if method_name == @target
throw(:line_number_is, lineno)
end
end
end
end
end
end
end

View File

@ -42,7 +42,6 @@ Gem::Specification.new do |s|
s.add_dependency "rake", ">= 12.2"
s.add_dependency "thor", "~> 1.0"
s.add_dependency "method_source"
s.add_dependency "zeitwerk", "~> 2.6"
s.add_development_dependency "actionview", version

View File

@ -376,7 +376,7 @@ module ApplicationTests
end
end
def test_more_than_one_line_filter
def test_more_than_one_line_filter_macro_syntax
app_file "test/models/post_test.rb", <<-RUBY
require "test_helper"
@ -404,6 +404,34 @@ module ApplicationTests
end
end
def test_more_than_one_line_filter_test_method_syntax
app_file "test/models/post_test.rb", <<-RUBY
require "test_helper"
class PostTest < ActiveSupport::TestCase
def test_first_filter
puts 'PostTest:FirstFilter'
assert true
end
def test_second_filter
puts 'PostTest:SecondFilter'
assert true
end
def test_line_filter_does_not_run_this
assert true
end
end
RUBY
run_test_command("test/models/post_test.rb:4:9").tap do |output|
assert_match "PostTest:FirstFilter", output
assert_match "PostTest:SecondFilter", output
assert_match "2 runs, 2 assertions", output
end
end
def test_more_than_one_line_filter_with_multiple_files
app_file "test/models/account_test.rb", <<-RUBY
require "test_helper"