Class: Shirobai::Cop::RSpec::EmptyExampleGroup

Inherits:
RuboCop::Cop::Base
  • Object
show all
Extended by:
RuboCop::Cop::AutoCorrector
Includes:
RuboCop::Cop::RSpec::InsideExample, RuboCop::Cop::RangeHelp, RuboCop::RSpec::Language, BundleEligible
Defined in:
lib/shirobai/cop/rspec/empty_example_group.rb

Overview

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

Architecture B (relocate-and-dispatch): Rust identifies candidate example-group blocks on the shared walk; this wrapper locates the parser-gem block node via NodeLocator and runs stock's detection logic VERBATIM. The mutually recursive examples? matcher is deep parser-AST structural matching that cannot be reproduced bytewise. The autocorrect is simple (remove whole lines via range_by_whole_lines).

Stock entry method on_block is renamed to process_candidate so the Commissioner never dispatches a per-node on_block; only on_new_investigation is a real callback.

Constant Summary collapse

MSG =
"Empty example group detected."

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.badgeObject



30
# File 'lib/shirobai/cop/rspec/empty_example_group.rb', line 30

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

.bundle_args(_config) ⇒ Object

Config-less (the segment's role lists cover everything).



33
34
35
# File 'lib/shirobai/cop/rspec/empty_example_group.rb', line 33

def self.bundle_args(_config)
  []
end

.cop_nameObject



29
# File 'lib/shirobai/cop/rspec/empty_example_group.rb', line 29

def self.cop_name = "RSpec/EmptyExampleGroup"

Instance Method Details

#example_group_body(node) ⇒ Object



40
41
42
# File 'lib/shirobai/cop/rspec/empty_example_group.rb', line 40

def_node_matcher :example_group_body, <<~PATTERN
  (block (send #rspec? #ExampleGroups.all ...) args $_)
PATTERN

#example_or_group_or_include?(node) ⇒ Object



45
46
47
48
49
50
51
52
# File 'lib/shirobai/cop/rspec/empty_example_group.rb', line 45

def_node_matcher :example_or_group_or_include?, <<~PATTERN
  {
    (block
      (send #rspec? {#Examples.all #ExampleGroups.all #Includes.all} ...)
    ...)
    (send nil? {#Examples.all #Includes.all} ...)
  }
PATTERN

#examples?(node) ⇒ Object



68
69
70
71
72
73
74
75
# File 'lib/shirobai/cop/rspec/empty_example_group.rb', line 68

def_node_matcher :examples?, <<~PATTERN
  {
    #examples_directly_or_in_block?
    #examples_in_branches?
    (begin <#examples_directly_or_in_block? ...>)
    (begin <#examples_in_branches? ...>)
  }
PATTERN

#examples_directly_or_in_block?(node) ⇒ Object



60
61
62
63
64
65
# File 'lib/shirobai/cop/rspec/empty_example_group.rb', line 60

def_node_matcher :examples_directly_or_in_block?, <<~PATTERN
  {
    #example_or_group_or_include?
    #examples_inside_block?
  }
PATTERN

#examples_inside_block?(node) ⇒ Object



55
56
57
# File 'lib/shirobai/cop/rspec/empty_example_group.rb', line 55

def_node_matcher :examples_inside_block?, <<~PATTERN
  (block !(send nil? #Hooks.all ...) _ #examples?)
PATTERN

#on_new_investigationObject



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/shirobai/cop/rspec/empty_example_group.rb', line 77

def on_new_investigation
  RuboCop::RSpec::Language.config = config["RSpec"]["Language"]
  ranges = resolved_candidates
  return if ranges.nil? || ranges.empty?

  source = bundle_eligible? ? processed_source.raw_source : processed_source.buffer.source
  off = SourceOffsets.for(source)
  keys = ranges.map { |(start, fin)| [off[start], off[fin]] }
  located = Shirobai::RSpec::NodeLocator.locate(processed_source, keys)

  keys.each do |key|
    node = located[key]
    process_candidate(node) if node&.block_type?
  end
end