class RuboCop::Cop::Commissioner
Commissioner
class is responsible for processing the AST
and delegating work to the specified cops.
Constants
- CopError
Attributes
Public Class Methods
# 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
# 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
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
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
TODO: Bad design.
# File lib/rubocop/cop/commissioner.rb, line 85 def prepare(processed_source) @cops.each { |cop| cop.processed_source = processed_source } end
# 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
# File lib/rubocop/cop/commissioner.rb, line 80 def reset_callbacks @callbacks.clear end
# File lib/rubocop/cop/commissioner.rb, line 64 def reset_errors @errors = Hash.new { |hash, k| hash[k] = [] } end
# 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
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