File Manager
Viewing File: team.rb
# frozen_string_literal: true
module RuboCop
module Cop
# FIXME
class Team
# If these cops try to autocorrect the same file at the same time,
# bad things are liable to happen
INCOMPATIBLE_COPS = {
Style::SymbolProc => [Style::SpaceBeforeBlockBraces],
Style::SpaceBeforeBlockBraces => [Style::SymbolProc],
Style::LineEndConcatenation => [Style::UnneededInterpolation],
Style::UnneededInterpolation => [Style::LineEndConcatenation]
}.freeze
DEFAULT_OPTIONS = {
auto_correct: false,
debug: false
}.freeze
Investigation = Struct.new(:offenses, :errors)
attr_reader :errors, :warnings, :updated_source_file
alias updated_source_file? updated_source_file
def initialize(cop_classes, config, options = nil)
@cop_classes = cop_classes
@config = config
@options = options || DEFAULT_OPTIONS
@errors = []
@warnings = []
validate_config
end
def autocorrect?
@options[:auto_correct]
end
def debug?
@options[:debug]
end
def inspect_file(processed_source)
# If we got any syntax errors, return only the syntax offenses.
unless processed_source.valid_syntax?
return Lint::Syntax.offenses_from_processed_source(processed_source)
end
offenses(processed_source)
end
def cops
only_options = @options.fetch(:only, [])
@cops ||= @cop_classes.enabled(@config, only_options).map do |cop_class|
cop_class.new(@config, @options)
end
end
def forces
@forces ||= forces_for(cops)
end
def forces_for(cops)
Force.all.each_with_object([]) do |force_class, forces|
joining_cops = cops.select { |cop| cop.join_force?(force_class) }
next if joining_cops.empty?
forces << force_class.new(joining_cops)
end
end
def autocorrect(buffer, cops)
@updated_source_file = false
return unless autocorrect?
new_source = autocorrect_all_cops(buffer, cops)
return if new_source == buffer.source
if @options[:stdin]
# holds source read in from stdin, when --stdin option is used
@options[:stdin] = new_source
else
filename = buffer.name
File.open(filename, 'w') { |f| f.write(new_source) }
end
@updated_source_file = true
end
private
def offenses(processed_source)
# The autocorrection process may have to be repeated multiple times
# until there are no corrections left to perform
# To speed things up, run auto-correcting cops by themselves, and only
# run the other cops when no corrections are left
autocorrect_cops, other_cops = cops.partition(&:autocorrect?)
autocorrect =
investigate(autocorrect_cops, processed_source) do |offenses|
# We corrected some errors. Another round of inspection will be
# done, and any other offenses will be caught then, so we don't
# need to continue.
return offenses if autocorrect(processed_source.buffer,
autocorrect_cops)
end
other = investigate(other_cops, processed_source)
errors = autocorrect.errors.merge(other.errors)
process_commissioner_errors(processed_source.path, errors)
autocorrect.offenses.concat(other.offenses)
end
def investigate(cops, processed_source)
return Investigation.new([], {}) if cops.empty?
commissioner = Commissioner.new(cops, forces_for(cops))
offenses = commissioner.investigate(processed_source)
yield offenses if block_given?
Investigation.new(offenses, commissioner.errors)
end
def autocorrect_all_cops(buffer, cops)
corrector = Corrector.new(buffer)
skip = Set.new
cops.each do |cop|
next if cop.corrections.empty?
next if skip.include?(cop.class)
corrector.corrections.concat(cop.corrections)
incompatible = INCOMPATIBLE_COPS[cop.class]
skip.merge(incompatible) if incompatible
end
if !corrector.corrections.empty?
corrector.rewrite
else
buffer.source
end
end
def validate_config
cops.each do |cop|
cop.validate_config if cop.respond_to?(:validate_config)
end
end
def process_commissioner_errors(file, file_errors)
file_errors.each do |cop, errors|
errors.each do |cop_error|
e = cop_error.error
line = ":#{cop_error.line}" if cop_error.line
column = ":#{cop_error.column}" if cop_error.column
location = "#{file}#{line}#{column}"
if e.is_a?(Warning)
handle_warning(e, location)
else
handle_error(e, location, cop)
end
end
end
end
def handle_warning(e, location)
message = Rainbow("#{e.message} (from file: #{location})").yellow
@warnings << message
warn message
puts e.backtrace if debug?
end
def handle_error(e, location, cop)
message = Rainbow("An error occurred while #{cop.name}" \
" cop was inspecting #{location}.").red
@errors << message
warn message
if debug?
puts e.message, e.backtrace
else
warn 'To see the complete backtrace run rubocop -d.'
end
end
end
end
end