Class: Shirobai::Cop::Rails::DynamicFindBy

Inherits:
RuboCop::Cop::Base
  • Object
show all
Extended by:
RuboCop::Cop::AutoCorrector
Includes:
BundleEligible
Defined in:
lib/shirobai/cop/rails/dynamic_find_by.rb

Overview

Drop-in Rust reimplementation of Rails/DynamicFindBy (rubocop-rails 2.35.5).

Rust replicates the on_send / on_csend detection (the /^find_by_(.+?)(!)?$/ name match, the argument count / no-splat / no-hash rules, the AllowedMethods / AllowedReceivers / Whitelist suppressions, and the receiverless-inside-ActiveRecord class check) and the full autocorrect: replace the selector with find_by / find_by! and insert each col: keyword before its argument. The wrapper owns only the fixed MSG (the method name comes from the selector range).

Constant Summary collapse

MSG =
"Use `%<static_name>s` instead of dynamic `%<method>s`."

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.badgeObject



23
# File 'lib/shirobai/cop/rails/dynamic_find_by.rb', line 23

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

.bundle_args(config) ⇒ Object

Contributes [nums, lists] pieces to the rails segment: [[], [AllowedMethods, AllowedReceivers, Whitelist]].



27
28
29
30
# File 'lib/shirobai/cop/rails/dynamic_find_by.rb', line 27

def self.bundle_args(config)
  cop = config.for_badge(badge)
  [[], [cop["AllowedMethods"] || [], cop["AllowedReceivers"] || [], cop["Whitelist"] || []]]
end

.cop_nameObject



22
# File 'lib/shirobai/cop/rails/dynamic_find_by.rb', line 22

def self.cop_name = "Rails/DynamicFindBy"

Instance Method Details

#on_new_investigationObject



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/shirobai/cop/rails/dynamic_find_by.rb', line 32

def on_new_investigation
  buffer = processed_source.buffer
  source = bundle_eligible? ? processed_source.raw_source : buffer.source
  off = SourceOffsets.for(source)
  resolved_offenses.each do |start_o, end_o, static_name, sel_s, sel_e, inserts|
    range = Parser::Source::Range.new(buffer, off[start_o], off[end_o])
    sel_range = Parser::Source::Range.new(buffer, off[sel_s], off[sel_e])
    message = format(MSG, static_name: static_name, method: sel_range.source)
    add_offense(range, message: message) do |corrector|
      corrector.replace(sel_range, static_name)
      inserts.each do |arg_start, keyword|
        pos = off[arg_start]
        corrector.insert_before(Parser::Source::Range.new(buffer, pos, pos), keyword)
      end
    end
  end
end