class RuboCop::Cop::Commissioner

Commissioner class is responsible for processing the AST and delegating work to the specified cops.

Constants

CopError

Attributes

errors[R]

Public Class Methods

new(cops, forces = [], options = {}) click to toggle source
# File lib/rubocop/cop/commissioner.rb, line 14
def initialize(cops, forces = [], options = {})
  @cops = cops
  @forces = forces
  @options = options
  @callbacks = {}

  reset_errors
end

Public Instance Methods

investigate(processed_source) click to toggle source
# File lib/rubocop/cop/commissioner.rb, line 39
def investigate(processed_source)
  reset_errors
  remove_irrelevant_cops(processed_source.file_path)
  reset_callbacks
  prepare(processed_source)
  invoke_custom_processing(@cops, processed_source)
  invoke_custom_processing(@forces, processed_source)
  walk(processed_source.ast) unless processed_source.blank?
  invoke_custom_post_walk_processing(@cops, processed_source)
  @cops.flat_map(&:offenses)
end

Private Instance Methods

invoke_custom_post_walk_processing(cops, processed_source) click to toggle source

There are cops that require their own custom processing *after* the AST traversal. By performing the walk before invoking these custom processors, we allow these cops to build their own state during the primary AST traversal instead of performing their own AST traversals. Minimizing the number of walks is more efficient.

If they define the investigate_post_walk method, all input parameters passed to the commissioner will be passed to the cop too in order to do its own processing.

# File lib/rubocop/cop/commissioner.rb, line 116
def invoke_custom_post_walk_processing(cops, processed_source)
  cops.each do |cop|
    next unless cop.respond_to?(:investigate_post_walk)

    with_cop_error_handling(cop) do
      cop.investigate_post_walk(processed_source)
    end
  end
end
invoke_custom_processing(cops_or_forces, processed_source) click to toggle source

There are cops/forces that require their own custom processing. If they define the investigate method, all input parameters passed to the commissioner will be passed to the cop too in order to do its own processing.

These custom processors are invoked before the AST traversal, so they can build initial state that is later used by callbacks during the AST traversal.

# File lib/rubocop/cop/commissioner.rb, line 97
def invoke_custom_processing(cops_or_forces, processed_source)
  cops_or_forces.each do |cop|
    next unless cop.respond_to?(:investigate)

    with_cop_error_handling(cop) do
      cop.investigate(processed_source)
    end
  end
end
prepare(processed_source) click to toggle source

TODO: Bad design.

# File lib/rubocop/cop/commissioner.rb, line 85
def prepare(processed_source)
  @cops.each { |cop| cop.processed_source = processed_source }
end
remove_irrelevant_cops(filename) click to toggle source
# File lib/rubocop/cop/commissioner.rb, line 68
def remove_irrelevant_cops(filename)
  @cops.reject! { |cop| cop.excluded_file?(filename) }
  @cops.reject! do |cop|
    cop.class.respond_to?(:support_target_ruby_version?) &&
      !cop.class.support_target_ruby_version?(cop.target_ruby_version)
  end
  @cops.reject! do |cop|
    cop.class.respond_to?(:support_target_rails_version?) &&
      !cop.class.support_target_rails_version?(cop.target_rails_version)
  end
end
reset_callbacks() click to toggle source
# File lib/rubocop/cop/commissioner.rb, line 80
def reset_callbacks
  @callbacks.clear
end
reset_errors() click to toggle source
# File lib/rubocop/cop/commissioner.rb, line 64
def reset_errors
  @errors = Hash.new { |hash, k| hash[k] = [] }
end
trigger_responding_cops(callback, node) click to toggle source
# File lib/rubocop/cop/commissioner.rb, line 53
def trigger_responding_cops(callback, node)
  @callbacks[callback] ||= @cops.select do |cop|
    cop.respond_to?(callback)
  end
  @callbacks[callback].each do |cop|
    with_cop_error_handling(cop, node) do
      cop.send(callback, node)
    end
  end
end
with_cop_error_handling(cop, node = nil) { || ... } click to toggle source

Allow blind rescues here, since we're absorbing and packaging or re-raising exceptions that can be raised from within the individual cops' `#investigate` methods.

# File lib/rubocop/cop/commissioner.rb, line 129
def with_cop_error_handling(cop, node = nil)
  yield
rescue StandardError => e
  raise e if @options[:raise_error]

  if node
    line = node.first_line
    column = node.loc.column
  end
  error = CopError.new(e, line, column)
  @errors[cop] << error
end