Class: Shirobai::Cop::Metrics::AbcSize

Inherits:
RuboCop::Cop::Base
  • Object
show all
Extended by:
RuboCop::ExcludeLimit
Includes:
RuboCop::Cop::AllowedMethods, RuboCop::Cop::AllowedPattern
Defined in:
lib/shirobai/cop/metrics/abc_size.rb

Overview

Drop-in Rust reimplementation of ‘Metrics/AbcSize`.

Rust returns the per-method ‘<assignment, branch, condition>` counts for every method whose squared vector exceeds the configured `Max.floor` (`bundle_args` packs `Max.floor`; a non-natural `Max` packs `-1` so every method is returned and the exact `score > Max` filter below stays the behavioral source of truth). The float score, the vector string and the message are derived here so floats never cross the FFI boundary.

Constant Summary collapse

MSG =
"Assignment Branch Condition size for `%<method>s` is too high. " \
"[%<abc_vector>s %<complexity>.4g/%<max>.4g]"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.badgeObject



25
# File 'lib/shirobai/cop/metrics/abc_size.rb', line 25

def self.badge = RuboCop::Cop::Badge.parse("Metrics/AbcSize")

.bundle_args(config) ⇒ Object

Packed args for the bundled run: ‘[max_floor, discount_repeated]`. `max_floor` is the cop’s ‘Max.floor` (conservative prefilter: a float `Max` floors down, an integer one is exact); a non-natural `Max` disables the prefilter with `-1`. `discount_repeated` is `!CountRepeatedAttributes` (default `CountRepeatedAttributes: true`).



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

def self.bundle_args(config)
  cop_config = config.for_badge(badge)
  max = cop_config["Max"]
  max_floor = max.is_a?(Numeric) && max >= 0 ? max.floor : -1
  discount = cop_config["CountRepeatedAttributes"] == false
  [max_floor, discount ? 1 : 0]
end

.cop_nameObject



24
# File 'lib/shirobai/cop/metrics/abc_size.rb', line 24

def self.cop_name = "Metrics/AbcSize"

Instance Method Details

#on_new_investigationObject



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/shirobai/cop/metrics/abc_size.rb', line 40

def on_new_investigation
  max = cop_config["Max"]

  analysis = Dispatch.offenses_for(processed_source, config, :abc_size)
  off = SourceOffsets.for(processed_source.raw_source)
  analysis.each do |start, fin, head_end, name, assignment, branch, condition|
    next if allowed_method?(name) || matches_allowed_pattern?(name)

    complexity = Math.sqrt((assignment**2) + (branch**2) + (condition**2)).round(2)
    next unless complexity > max

    abc_vector = "<#{assignment}, #{branch}, #{condition}>"
    stop = RuboCop::LSP.enabled? ? head_end : fin
    range = Parser::Source::Range.new(processed_source.buffer, off[start], off[stop])
    message = format(MSG, method: name, complexity: complexity, abc_vector: abc_vector, max: max)
    add_offense(range, message: message) { self.max = complexity.ceil }
  end
end