Class: Shirobai::Cop::Layout::ExtraSpacing

Inherits:
RuboCop::Cop::Base
  • Object
show all
Extended by:
RuboCop::Cop::AutoCorrector
Includes:
RuboCop::Cop::RangeHelp
Defined in:
lib/shirobai/cop/layout/extra_spacing.rb

Overview

Drop-in Rust reimplementation of Layout/ExtraSpacing.

A token-scan cop with an AST side input: Rust walks the parser-gem token stream as adjacent pairs (tokens.each_cons(2), stock's check_tokens) and, for the AllowForAlignment / ignored_ranges decisions, consults the whole token list (the shared alignment helper) and the AST (the key↔value spans of multi-line hash pairs, left to Layout/HashAlignment). Both run in the bundle's walk-outer phase; Rust returns one record per offense: [start, end, message, action, edits].

[start, end) is the offense highlight. action is 0 (corrector.remove(range) — the usual "delete extra spacing" fix) or 1 (ForceEqualSignAlignment: apply each [edit_start, edit_end, text] of edits with corrector.replace — a zero-width range inserts, an empty text deletes; Rust has already applied the @corrected dedup so each token's edit appears under exactly one offense).

Config inputs: AllowForAlignment (default true) / AllowBeforeTrailingComments (default false) / ForceEqualSignAlignment (default false). All are purely config-driven, so the cop is always bundle eligible — except when raw_source != buffer.source (CRLF/BOM normalization), where the token byte positions would not line up and it falls back to a standalone lex of buffer.source. (CRLF/buffer.source trap, aee0e8e.)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.badgeObject



35
# File 'lib/shirobai/cop/layout/extra_spacing.rb', line 35

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

.bundle_args(config) ⇒ Object

Packed config nums: [enabled, allow_for_alignment, allow_before_trailing_comments, force_equal_sign_alignment].

enabled is a token-cop gate the bundle ORs into its decision to collect the parser-gem token stream. It is a superset of "this cop runs": a false positive only costs the token pass on a file the cop never reads, never a wrong offense, so we only turn it off when Enabled is literally false.

force_equal_sign_alignment is the same config key (Layout/ExtraSpacing ForceEqualSignAlignment) that Layout/SpaceAroundOperators reads; the bundle packs it once (num 126) as the single wire source. It is carried here for the standalone fallback call below.



51
52
53
54
55
56
57
58
# File 'lib/shirobai/cop/layout/extra_spacing.rb', line 51

def self.bundle_args(config)
  cop_config = config.for_badge(badge)
  enabled = cop_config["Enabled"] == false ? 0 : 1
  allow = cop_config.fetch("AllowForAlignment", true) ? 1 : 0
  trailing = cop_config["AllowBeforeTrailingComments"] ? 1 : 0
  force = cop_config["ForceEqualSignAlignment"] ? 1 : 0
  [[enabled, allow, trailing, force]]
end

.cop_nameObject



34
# File 'lib/shirobai/cop/layout/extra_spacing.rb', line 34

def self.cop_name = "Layout/ExtraSpacing"

Instance Method Details

#on_new_investigationObject



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/shirobai/cop/layout/extra_spacing.rb', line 60

def on_new_investigation
  buffer = processed_source.buffer
  source_for_offsets = bundle_eligible? ? processed_source.raw_source : buffer.source
  off = SourceOffsets.for(source_for_offsets)
  ranges = ignored_ranges(source_for_offsets)

  resolved_result.each do |start_pos, end_pos, message, action, edits|
    # `ignored_range?(ast, range.begin_pos)`: applied here (not in Rust)
    # with the memoized `@ignored_ranges`, reproducing stock's instance
    # memoization — across an autocorrect re-pass on a reused instance the
    # ranges go stale exactly as stock's do. Only the "remove extra space"
    # action (0) is subject to it; the ForceEqualSignAlignment action (1)
    # is not.
    next if action == 0 && ranges.any? { |s, e| (s...e).cover?(start_pos) }

    range = Parser::Source::Range.new(buffer, off[start_pos], off[end_pos])
    add_offense(range, message: message) do |corrector|
      if action == 0
        corrector.remove(range)
      else
        edits.each do |edit_start, edit_end, text|
          edit_range = Parser::Source::Range.new(buffer, off[edit_start], off[edit_end])
          corrector.replace(edit_range, text)
        end
      end
    end
  end
end