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, https://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 |