Module: Shirobai::Inject

Defined in:
lib/shirobai/inject.rb

Class Method Summary collapse

Class Method Details

.align_autocorrect_incompatibilities!Object

Team#each_corrector skips a cop's corrector for the round when an earlier-merged cop's autocorrect_incompatible_with includes the cop's CLASS. Badge replacement breaks that identity check in both directions: a wrapper copying stock's list still names the dismissed stock class, and a stock cop that stays stock (Style/SymbolProc) names a class whose registry slot a wrapper took over. Either way skips.include?(cop.class) misses, the skip never fires, and the -a round applies corrections stock would have dropped — the corrected trees then drift (fluentd types.rb / log.rb: SpaceInsideBlockBraces lists BlockDelimiters).

Rewrite every active cop's list through the stock-to-shirobai map: wrappers get stock's list (the drop-in truth) translated, and remaining stock cops get their own list translated. Runs after all core wrapper classes are defined (each auto-enlists via Base.inherited), again at each shirobai plugin gem's require (their stock departments — e.g. Rails/SafeNavigation listing Style::RedundantSelf — enlist between aligner runs), and lazily when the registry grew since the last run (third-party plugins like rubocop-capybara load during config resolution, after every shirobai require; see align_if_registry_grew! and Dispatch.bundle_token). Idempotent: an already-translated list maps to itself and is skipped.

The rewritten methods return a FRESH copy per call, like stock's per-call array literals: rubocop-performance and rubocop-capybara prepend singleton modules that do super.push(...), so a shared (or frozen) array would accumulate duplicates across calls (or raise FrozenError).



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/shirobai/inject.rb', line 52

def self.align_autocorrect_incompatibilities!
  registry = RuboCop::Cop::Registry.global
  cops = registry.cops
  @aligned_registry_size = cops.size

  replacements = {}
  cops.each do |cop|
    next unless cop.name&.start_with?("Shirobai::")

    stock = stock_counterpart(cop)
    replacements[stock] = cop if stock
  end

  replacements.each do |stock, wrapper|
    list = stock.autocorrect_incompatible_with
                .map { |klass| replacements.fetch(klass, klass) }.freeze
    wrapper.define_singleton_method(:autocorrect_incompatible_with) { list.dup }
  end
  cops.each do |cop|
    next if replacements.value?(cop)

    list = cop.autocorrect_incompatible_with
    mapped = list.map { |klass| replacements.fetch(klass, klass) }
    next if mapped == list

    mapped.freeze
    cop.define_singleton_method(:autocorrect_incompatible_with) { mapped.dup }
  end
end

.align_if_registry_grew!Object

Cheap re-alignment guard for plugins that load AFTER every shirobai require: rubocop resolves plugins: / require: gems while loading the corpus config, and those gems (rubocop-capybara et al.) may list a replaced class or enlist new cops. Badge replacement keeps the registry count, but a plugin load only ever ADDS badges, so a size change is the signal; called from Dispatch.bundle_token on each new config, which happens after config resolution and before any correction round.



89
90
91
92
93
94
# File 'lib/shirobai/inject.rb', line 89

def self.align_if_registry_grew!
  size = RuboCop::Cop::Registry.global.cops.size
  return if @aligned_registry_size == size

  align_autocorrect_incompatibilities!
end

.replace_cops!Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/shirobai/inject.rb', line 5

def self.replace_cops!
  registry = RuboCop::Cop::Registry.global

  Shirobai::Cop.constants(false).each do |department|
    mod = Shirobai::Cop.const_get(department)
    next unless mod.is_a?(Module)

    mod.constants(false).each do |cop_name|
      klass = mod.const_get(cop_name)
      next unless klass < RuboCop::Cop::Base

      original = registry.find { |c| c.cop_name == klass.cop_name }
      next unless original

      registry.dismiss(original)
      registry.enlist(klass)
    end
  end
end

.stock_counterpart(klass) ⇒ Object

The stock class whose badge klass took over, or nil when the stock constant does not exist (a shirobai-only cop).



98
99
100
101
102
103
# File 'lib/shirobai/inject.rb', line 98

def self.stock_counterpart(klass)
  department, name = klass.cop_name.split("/")
  RuboCop::Cop.const_get(department, false).const_get(name, false)
rescue NameError
  nil
end