Repository: rails/rails
File: railties/lib/rails/test_unit/test_parser.rb (Ruby)

Code before:
# frozen_string_literal: true

begin
  require "prism"
rescue LoadError
  # If Prism isn't available (because of using an older Ruby version) then we'll
  # define a fallback parser using ripper.
end

if defined?(Prism)
  module Rails
    module TestUnit
      # Parse a test file to extract the line ranges of all tests in both
      # method-style (def test_foo) and declarative-style (test "foo" do)
      module TestParser
        @@begins_to_ends = {}
        # Helper to translate a method object into the path and line range where
        # the method was defined.
        def self.definition_for(method)
          filepath, start_line = method.source_location
          @@begins_to_ends[filepath] ||= ranges(filepath)
          return unless end_line = @@begins_to_ends[filepath][start_line]
          [filepath, start_line..end_line]
        end

        private
          def self.ranges(filepath)
            queue = [Prism.parse_file(filepath).value]
            begins_to_ends = {}
            while (node = queue.shift)
              case node.type
              when :def_node
                begins_to_ends[node.location.start_line] = node.location.end_line
              when :call_node
                begins_to_ends[node.location.start_line] = node.location.end_line
              end

              queue.concat(node.compact_child_nodes)
            end
            begins_to_ends
          end

Review comment (suggestion):
https://docs.rubocop.org/rubocop/cops_style.html#styleclassvars

This rule doesn't seem to be enabled here but I generally agree that we should prefer singleton class instance variables over class variables. 
```suggestion
        @begins_to_ends = {}
```

Code after:
# frozen_string_literal: true

begin
  require "prism"
rescue LoadError
  # If Prism isn't available (because of using an older Ruby version) then we'll
  # define a fallback parser using ripper.
end

if defined?(Prism)
  module Rails
    module TestUnit
      # Parse a test file to extract the line ranges of all tests in both
      # method-style (def test_foo) and declarative-style (test "foo" do)
      module TestParser
        @begins_to_ends = {}
        # Helper to translate a method object into the path and line range where
        # the method was defined.
        def self.definition_for(method)
          filepath, start_line = method.source_location
          @begins_to_ends[filepath] ||= ranges(filepath)
          return unless end_line = @begins_to_ends[filepath][start_line]
          [filepath, start_line..end_line]
        end

        private
          def self.ranges(filepath)
            queue = [Prism.parse_file(filepath).value]
            begins_to_ends = {}
            while (node = queue.shift)
              case node.type
              when :def_node
                begins_to_ends[node.location.start_line] = node.location.end_line
              when :call_node
                begins_to_ends[node.location.start_line] = node.location.end_line
              end

              queue.concat(node.compact_child_nodes)
            end
            begins_to_ends
          end