Class: Shirobai::Cop::RSpec::NamedSubject

Inherits:
RuboCop::Cop::Base
  • Object
show all
Includes:
BundleEligible
Defined in:
lib/shirobai/cop/rspec/named_subject.rb

Overview

Drop-in Rust reimplementation of RSpec/NamedSubject (rubocop-rspec 3.10.2).

Everything is computed on the shared walk. A reference is stock's hard-coded subject_usage search ($(send nil? :subject) — the literal name subject, never an alias nor subject!, zero arguments, no block-pass). Rust reports it when the reference has a plain-block example/hook ancestor (stock's on_block fires only for plain blocks, so a numblock/itblock example never qualifies) that is not enclosed by a shared example group under IgnoreSharedExamples, and, under EnforcedStyle: named_only, when the nearest enclosing subject definition is named. The offense range is the subject selector. This cop has no autocorrect (stock does not either).

Probed quirks live as differential specs in named_subject_edge_cases_spec.rb.

Constant Summary collapse

MSG =
"Name your test subject if you need to reference it explicitly."

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.badgeObject



28
# File 'lib/shirobai/cop/rspec/named_subject.rb', line 28

def self.badge = RuboCop::Cop::Badge.parse(cop_name)

.bundle_args(config) ⇒ Object

Packed args for the bundled run: [style, ignore_shared_examples] (style 0 always / 1 named_only; ignore 0 / 1).



32
33
34
35
36
37
38
# File 'lib/shirobai/cop/rspec/named_subject.rb', line 32

def self.bundle_args(config)
  cop_config = config.for_badge(badge)
  [
    cop_config.fetch("EnforcedStyle", "always").to_s == "named_only" ? 1 : 0,
    cop_config.fetch("IgnoreSharedExamples", true) ? 1 : 0
  ]
end

.cop_nameObject



27
# File 'lib/shirobai/cop/rspec/named_subject.rb', line 27

def self.cop_name = "RSpec/NamedSubject"

Instance Method Details

#on_new_investigationObject



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/shirobai/cop/rspec/named_subject.rb', line 40

def on_new_investigation
  offenses = resolved_offenses
  return if offenses.empty?

  buffer = processed_source.buffer
  source = bundle_eligible? ? processed_source.raw_source : buffer.source
  off = SourceOffsets.for(source)
  offenses.each do |(start, fin)|
    add_offense(Parser::Source::Range.new(buffer, off[start], off[fin]))
  end
end