Module: RSpec::Signal::Symptoms::RubyError

Defined in:
lib/rspec/signal/symptoms/ruby_error.rb

Overview

Two Ruby-level messages specific enough to cluster on: a method called on the wrong thing, and a constant that was never defined.

undefined method 'progress' for nil in six specs is one nil, not six bugs. Both the method and the receiver are part of the key, so #name for nil and #total for nil stay apart.

Constant Summary collapse

UNDEFINED_METHOD =

Ruby 3.4 quotes with 'x', earlier versions with `x'.

/undefined method [`'"](?<name>[^'"`]+)['"`] for (?:an instance of )?(?<receiver>\S+)/
UNINITIALIZED =
/uninitialized constant (?<constant>[A-Z]\w*(?:::\w+)*)/

Class Method Summary collapse

Class Method Details

.call(_failure, text) ⇒ Object



19
20
21
# File 'lib/rspec/signal/symptoms/ruby_error.rb', line 19

def call(_failure, text)
  undefined_method(text) || uninitialized_constant(text)
end

.receiver_name(raw) ⇒ Object

nil:NilClass, #<User:0x00007f9a> and an instance of User all name a class; use it, so two receivers of the same class cluster.



45
46
47
48
49
50
51
# File 'lib/rspec/signal/symptoms/ruby_error.rb', line 45

def receiver_name(raw)
  text = raw.to_s
  return "nil" if text.start_with?("nil")
  return ::Regexp.last_match(1) if text =~ /\A#<([A-Z]\w*(?:::\w+)*)/

  text.split(":").first.to_s
end

.undefined_method(text) ⇒ Object



23
24
25
26
27
28
29
30
31
32
# File 'lib/rspec/signal/symptoms/ruby_error.rb', line 23

def undefined_method(text)
  match = UNDEFINED_METHOD.match(text)
  return nil unless match

  name = match[:name]
  receiver = receiver_name(match[:receiver])
  Symptom.new(kind: :undefined_method, key: "undefined-method:#{name}:#{receiver}",
              label: "undefined method `#{name}` on #{receiver}",
              detail: "undefined `#{name}` for #{receiver}")
end

.uninitialized_constant(text) ⇒ Object



34
35
36
37
38
39
40
41
# File 'lib/rspec/signal/symptoms/ruby_error.rb', line 34

def uninitialized_constant(text)
  match = UNINITIALIZED.match(text)
  return nil unless match

  constant = match[:constant]
  Symptom.new(kind: :missing_constant, key: "missing-constant:#{constant}",
              label: "uninitialized constant `#{constant}`", detail: "uninitialized #{constant}")
end