Class: RuboCop::Cop::Gusto::DescribedClassConstantReference
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::Gusto::DescribedClassConstantReference
- Extended by:
- AutoCorrector
- Defined in:
- lib/rubocop/cop/gusto/described_class_constant_reference.rb
Overview
Flags constants that are scoped through ‘described_class`, e.g. `described_class::Worker`.
‘described_class` is an RSpec helper method resolved at runtime, so Sorbet’s static analysis treats ‘described_class::Worker` as a dynamic constant reference and cannot resolve it (`Dynamic constant references are unsupported`, srb.help/5001). Reference the constant by its fully-qualified name instead. A bare `described_class` (with no `::` constant lookup) is an ordinary method call and is left alone.
Autocorrection replaces ‘described_class` with the constant that the enclosing example group describes. It is marked unsafe (`SafeAutoCorrect: false`) because the rewrite relies on the described constant being a statically-written name; review the result before committing. In particular, a constant defined on an ancestor of the described class is qualified against the described class itself, which is correct at runtime but which Sorbet cannot resolve through the inheritance chain – re-point those to the defining ancestor by hand.
Constant Summary collapse
- MSG =
"Use the fully-qualified constant name instead of scoping it through " \ "`described_class`, which Sorbet cannot resolve statically."
Instance Method Summary collapse
-
#const_scoped_on_described_class?(node) ⇒ Object
A constant whose scope is a no-receiver ‘described_class`, e.g.
-
#example_group_described_argument(node) ⇒ Object
An example group, capturing its first argument: a constant (‘RSpec.describe Foo do`, `context Foo do`), `self` (`RSpec.describe self do`), and so on.
- #on_const(node) ⇒ Object
-
#scoped_through_described_class?(node) ⇒ Object
Whether a node routes through a no-receiver ‘described_class`.
Instance Method Details
#const_scoped_on_described_class?(node) ⇒ Object
A constant whose scope is a no-receiver ‘described_class`, e.g. `described_class::Worker`.
58 59 60 |
# File 'lib/rubocop/cop/gusto/described_class_constant_reference.rb', line 58 def_node_matcher :const_scoped_on_described_class?, <<~PATTERN (const (send nil? :described_class) _) PATTERN |
#example_group_described_argument(node) ⇒ Object
An example group, capturing its first argument: a constant (‘RSpec.describe Foo do`, `context Foo do`), `self` (`RSpec.describe self do`), and so on.
66 67 68 69 70 71 72 |
# File 'lib/rubocop/cop/gusto/described_class_constant_reference.rb', line 66 def_node_matcher :example_group_described_argument, <<~PATTERN (block (send {(const nil? :RSpec) nil?} {:describe :xdescribe :fdescribe :context :xcontext :fcontext :feature :example_group} $_ ...) ...) PATTERN |
#on_const(node) ⇒ Object
80 81 82 83 84 85 86 87 88 |
# File 'lib/rubocop/cop/gusto/described_class_constant_reference.rb', line 80 def on_const(node) return unless const_scoped_on_described_class?(node) scope = node.children[0] add_offense(scope) do |corrector| replacement = described_class_replacement(node) corrector.replace(scope, replacement) if replacement end end |
#scoped_through_described_class?(node) ⇒ Object
Whether a node routes through a no-receiver ‘described_class`.
76 77 78 |
# File 'lib/rubocop/cop/gusto/described_class_constant_reference.rb', line 76 def_node_search :scoped_through_described_class?, <<~PATTERN (send nil? :described_class) PATTERN |