class RuboCop::CLI

The CLI is a class responsible of handling all the command line interface logic.

Constants

PHASE_1
PHASE_1_DISABLED
PHASE_1_OVERRIDDEN
PHASE_2
STATUS_ERROR
STATUS_INTERRUPTED
STATUS_OFFENSES
STATUS_SUCCESS

Attributes

config_store[R]
options[R]

Public Class Methods

new() click to toggle source
# File lib/rubocop/cli.rb, line 27
def initialize
  @options = {}
  @config_store = ConfigStore.new
end

Public Instance Methods

run(args = ARGV) click to toggle source

@api public

Entry point for the application logic. Here we do the command line arguments processing and inspect the target files.

@param args [Array<String>] command line arguments @return [Integer] UNIX exit code

rubocop:disable Metrics/MethodLength, Metrics/AbcSize

# File lib/rubocop/cli.rb, line 42
def run(args = ARGV)
  @options, paths = Options.new.parse(args)

  if @options[:init]
    init_dotfile
  else
    validate_options_vs_config
    act_on_options
    apply_default_formatter
    execute_runners(paths)
  end
rescue ConfigNotFoundError, IncorrectCopNameError, OptionArgumentError => e
  warn e.message
  STATUS_ERROR
rescue RuboCop::Error => e
  warn Rainbow("Error: #{e.message}").red
  STATUS_ERROR
rescue Finished
  STATUS_SUCCESS
rescue OptionParser::InvalidOption => e
  warn e.message
  warn 'For usage information, use --help'
  STATUS_ERROR
rescue StandardError, SyntaxError, LoadError => e
  warn e.message
  warn e.backtrace
  STATUS_ERROR
end

Private Instance Methods

act_on_options() click to toggle source
# File lib/rubocop/cli.rb, line 187
def act_on_options
  ConfigLoader.debug = @options[:debug]
  ConfigLoader.auto_gen_config = @options[:auto_gen_config]
  ConfigLoader.ignore_parent_exclusion = @options[:ignore_parent_exclusion]
  ConfigLoader.options_config = @options[:config]

  @config_store.options_config = @options[:config] if @options[:config]
  @config_store.force_default_config! if @options[:force_default_config]

  handle_exiting_options

  if @options[:color]
    # color output explicitly forced on
    Rainbow.enabled = true
  elsif @options[:color] == false
    # color output explicitly forced off
    Rainbow.enabled = false
  end
end
apply_default_formatter() click to toggle source
# File lib/rubocop/cli.rb, line 235
def apply_default_formatter
  # This must be done after the options have already been processed,
  # because they can affect how ConfigStore behaves
  @options[:formatters] ||= begin
    if @options[:auto_gen_config]
      formatter = 'autogenconf'
    else
      cfg = @config_store.for(Dir.pwd).for_all_cops
      formatter = cfg['DefaultFormatter'] || 'progress'
    end
    [[formatter, @options[:output_path]]]
  end

  return unless @options[:auto_gen_config]

  @options[:formatters] << [Formatter::DisabledConfigFormatter,
                            ConfigLoader::AUTO_GENERATED_FILE]
end
config_lines(cop) click to toggle source
# File lib/rubocop/cli.rb, line 300
def config_lines(cop)
  cnf = @config_store.for(Dir.pwd).for_cop(cop)
  cnf.to_yaml.lines.to_a.drop(1).map { |line| '  ' + line }
end
cops_of_department(cops, department) click to toggle source
# File lib/rubocop/cli.rb, line 296
def cops_of_department(cops, department)
  cops.with_department(department).sort!
end
display_error_summary(errors) click to toggle source
# File lib/rubocop/cli.rb, line 313
    def display_error_summary(errors)
      return if errors.empty?

      warn Rainbow("\n#{pluralize(errors.size, 'error')} occurred:").red

      errors.each { |error| warn error }

      warn <<~WARNING
        Errors are usually caused by RuboCop bugs.
        Please, report your problems to RuboCop's issue tracker.
        #{Gem.loaded_specs['rubocop'].metadata['bug_tracker_uri']}

        Mention the following information in the issue report:
        #{RuboCop::Version.version(true)}
      WARNING
    end
display_warning_summary(warnings) click to toggle source
# File lib/rubocop/cli.rb, line 305
def display_warning_summary(warnings)
  return if warnings.empty?

  warn Rainbow("\n#{pluralize(warnings.size, 'warning')}:").yellow

  warnings.each { |warning| warn warning }
end
execute_runner(paths) click to toggle source
# File lib/rubocop/cli.rb, line 207
def execute_runner(paths)
  runner = Runner.new(@options, @config_store)

  all_passed = runner.run(paths)
  display_warning_summary(runner.warnings)
  display_error_summary(runner.errors)
  maybe_print_corrected_source

  all_pass_or_excluded = all_passed || @options[:auto_gen_config]

  if runner.aborting?
    STATUS_INTERRUPTED
  elsif all_pass_or_excluded && runner.errors.empty?
    STATUS_SUCCESS
  else
    STATUS_OFFENSES
  end
end
execute_runners(paths) click to toggle source

rubocop:enable Metrics/MethodLength, Metrics/AbcSize

# File lib/rubocop/cli.rb, line 74
def execute_runners(paths)
  if @options[:auto_gen_config]
    reset_config_and_auto_gen_file
    line_length_contents = maybe_run_line_length_cop(paths)
    run_all_cops_auto_gen_config(line_length_contents, paths)
  else
    execute_runner(paths)
  end
end
handle_exiting_options() click to toggle source
# File lib/rubocop/cli.rb, line 226
def handle_exiting_options
  return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o }

  puts RuboCop::Version.version(false) if @options[:version]
  puts RuboCop::Version.version(true) if @options[:verbose_version]
  print_available_cops if @options[:show_cops]
  raise Finished
end
init_dotfile() click to toggle source
# File lib/rubocop/cli.rb, line 140
    def init_dotfile
      path = File.expand_path(ConfigLoader::DOTFILE)

      if File.exist?(ConfigLoader::DOTFILE)
        warn Rainbow("#{ConfigLoader::DOTFILE} already exists at #{path}").red

        STATUS_ERROR
      else
        description = <<~DESC
          # The behavior of RuboCop can be controlled via the .rubocop.yml
          # configuration file. It makes it possible to enable/disable
          # certain cops (checks) and to alter their behavior if they accept
          # any parameters. The file can be placed either in your home
          # directory or in some project directory.
          #
          # RuboCop will start looking for the configuration file in the directory
          # where the inspected file is and continue its way up to the root directory.
          #
          # See https://github.com/rubocop-hq/rubocop/blob/master/manual/configuration.md
        DESC

        File.open(ConfigLoader::DOTFILE, 'w') do |f|
          f.write(description)
        end

        puts "Writing new #{ConfigLoader::DOTFILE} to #{path}"

        STATUS_SUCCESS
      end
    end
line_length_cop(config) click to toggle source
# File lib/rubocop/cli.rb, line 110
def line_length_cop(config)
  config.for_cop('Metrics/LineLength')
end
line_length_enabled?(config) click to toggle source
# File lib/rubocop/cli.rb, line 98
def line_length_enabled?(config)
  line_length_cop(config)['Enabled']
end
max_line_length(config) click to toggle source
# File lib/rubocop/cli.rb, line 106
def max_line_length(config)
  line_length_cop(config)['Max']
end
maybe_print_corrected_source() click to toggle source
# File lib/rubocop/cli.rb, line 330
def maybe_print_corrected_source
  # If we are asked to autocorrect source code read from stdin, the only
  # reasonable place to write it is to stdout
  # Unfortunately, we also write other information to stdout
  # So a delimiter is needed for tools to easily identify where the
  # autocorrected source begins
  return unless @options[:stdin] && @options[:auto_correct]

  puts '=' * 20
  print @options[:stdin]
end
maybe_run_line_length_cop(paths) click to toggle source
# File lib/rubocop/cli.rb, line 84
def maybe_run_line_length_cop(paths)
  if !line_length_enabled?(@config_store.for(Dir.pwd))
    puts Rainbow("#{PHASE_1} #{PHASE_1_DISABLED}").yellow
    ''
  elsif !same_max_line_length?(
    @config_store.for(Dir.pwd), ConfigLoader.default_configuration
  )
    puts Rainbow("#{PHASE_1} #{PHASE_1_OVERRIDDEN}").yellow
    ''
  else
    run_line_length_cop_auto_gen_config(paths)
  end
end
print_available_cops() click to toggle source
print_cop_details(cops) click to toggle source
print_cops_of_department(registry, department, show_all) click to toggle source
reset_config_and_auto_gen_file() click to toggle source
# File lib/rubocop/cli.rb, line 171
def reset_config_and_auto_gen_file
  @config_store = ConfigStore.new
  @config_store.options_config = @options[:config] if @options[:config]
  File.open(ConfigLoader::AUTO_GENERATED_FILE, 'w') {}
  ConfigLoader.add_inheritance_from_auto_generated_file
end
run_all_cops_auto_gen_config(line_length_contents, paths) click to toggle source
# File lib/rubocop/cli.rb, line 129
def run_all_cops_auto_gen_config(line_length_contents, paths)
  puts Rainbow(PHASE_2).yellow
  result = execute_runner(paths)
  # This run was made with the current maximum length allowed, so append
  # the saved setting for LineLength.
  File.open(ConfigLoader::AUTO_GENERATED_FILE, 'a') do |f|
    f.write(line_length_contents)
  end
  result
end
run_line_length_cop_auto_gen_config(paths) click to toggle source

Do an initial run with only Metrics/LineLength so that cops that depend on Metrics/LineLength:Max get the correct value for that parameter.

# File lib/rubocop/cli.rb, line 116
def run_line_length_cop_auto_gen_config(paths)
  puts Rainbow(PHASE_1).yellow
  @options[:only] = ['Metrics/LineLength']
  execute_runner(paths)
  @options.delete(:only)
  @config_store = ConfigStore.new
  # Save the todo configuration of the LineLength cop.
  IO.read(ConfigLoader::AUTO_GENERATED_FILE)
    .lines
    .drop_while { |line| line.start_with?('#') }
    .join
end
same_max_line_length?(config1, config2) click to toggle source
# File lib/rubocop/cli.rb, line 102
def same_max_line_length?(config1, config2)
  max_line_length(config1) == max_line_length(config2)
end
selected_cops_of_department(cops, department) click to toggle source
# File lib/rubocop/cli.rb, line 290
def selected_cops_of_department(cops, department)
  cops_of_department(cops, department).select do |cop|
    @options[:show_cops].include?(cop.cop_name)
  end
end
validate_options_vs_config() click to toggle source
# File lib/rubocop/cli.rb, line 178
def validate_options_vs_config
  if @options[:parallel] &&
     !@config_store.for(Dir.pwd).for_all_cops['UseCache']
    raise OptionArgumentError, '-P/--parallel uses caching to speed up ' \
                               'execution, so combining with AllCops: ' \
                               'UseCache: false is not allowed.'
  end
end