class RuboCop::OptionsValidator

@api private
Validates option arguments and the options’ compatibility with each other.

def boolean_or_empty_cache?

def boolean_or_empty_cache?
  !@options.key?(:cache) || %w[true false].include?(@options[:cache])
end

def display_only_fail_level_offenses_with_autocorrect?

def display_only_fail_level_offenses_with_autocorrect?
  @options[:display_only_fail_level_offenses] && @options[:autocorrect]
end

def except_syntax?

def except_syntax?
  @options.key?(:except) &&
    (@options[:except] & %w[Lint/Syntax Syntax]).any?
end

def format_message_from(name, cop_names)

def format_message_from(name, cop_names)
  message = 'Unrecognized cop or department: %<name>s.'
  message_with_candidate = "%<message>s\nDid you mean? %<candidate>s"
  corrections = NameSimilarity.find_similar_names(name, cop_names)
  if corrections.empty?
    format(message, name: name)
  else
    format(message_with_candidate, message: format(message, name: name),
                                   candidate: corrections.join(', '))
  end
end

def incompatible_options

def incompatible_options
  @incompatible_options ||= @options.keys & Options::EXITING_OPTIONS
end

def initialize(options)

def initialize(options)
  @options = options
end

def only_includes_redundant_disable?

def only_includes_redundant_disable?
  @options.key?(:only) &&
    (@options[:only] & %w[Lint/RedundantCopDisableDirective
                          RedundantCopDisableDirective]).any?
end

def validate_auto_correct

def validate_auto_correct
  return if @options.key?(:auto_correct)
  return unless @options.key?(:disable_uncorrectable)
  raise OptionArgumentError,
        format('--disable-uncorrectable can only be used together with --auto-correct.')
end

def validate_auto_gen_config

def validate_auto_gen_config
  return if @options.key?(:auto_gen_config)
  message = '--%<flag>s can only be used together with --auto-gen-config.'
  %i[exclude_limit offense_counts auto_gen_timestamp
     auto_gen_only_exclude].each do |option|
    if @options.key?(option)
      raise OptionArgumentError,
            format(message, flag: option.to_s.tr('_', '-'))
    end
  end
end

def validate_cache_enabled_for_cache_root

def validate_cache_enabled_for_cache_root
  return unless @options[:cache] == 'false'
  raise OptionArgumentError, '--cache-root can not be used with ' \
                              '--cache false'
end

def validate_compatibility # rubocop:disable Metrics/MethodLength

rubocop:disable Metrics/MethodLength
rubocop:disable Metrics/AbcSize
def validate_compatibility # rubocop:disable Metrics/MethodLength
  if only_includes_redundant_disable?
    raise OptionArgumentError, 'Lint/RedundantCopDisableDirective cannot ' \
                               'be used with --only.'
  end
  raise OptionArgumentError, 'Syntax checking cannot be turned off.' if except_syntax?
  unless boolean_or_empty_cache?
    raise OptionArgumentError, '-C/--cache argument must be true or false'
  end
  if display_only_fail_level_offenses_with_autocorrect?
    raise OptionArgumentError, '--autocorrect cannot be used with ' \
      '--display-only-fail-level-offenses'
  end
  validate_auto_gen_config
  validate_auto_correct
  validate_display_only_failed
  validate_parallel
  return if incompatible_options.size <= 1
  raise OptionArgumentError, 'Incompatible cli options: ' \
                             "#{incompatible_options.inspect}"
end

def validate_cop_list(names)

called from within Options.
Cop name validation must be done later than option parsing, so it's not
def validate_cop_list(names)
  return unless names
  cop_names = Cop::Registry.global.names
  departments = Cop::Registry.global.departments.map(&:to_s)
  names.each do |name|
    next if cop_names.include?(name)
    next if departments.include?(name)
    next if SYNTAX_DEPARTMENTS.include?(name)
    raise IncorrectCopNameError, format_message_from(name, cop_names)
  end
end

def validate_cop_options

def validate_cop_options
  %i[only except].each do |opt|
    OptionsValidator.validate_cop_list(@options[opt])
  end
end

def validate_display_only_failed

def validate_display_only_failed
  return unless @options.key?(:display_only_failed)
  return if @options[:format] == 'junit'
  raise OptionArgumentError,
        format('--display-only-failed can only be used together with --format junit.')
end

def validate_exclude_limit_option

def validate_exclude_limit_option
  return if /^\d+$/.match?(@options[:exclude_limit])
  # Emulate OptionParser's behavior to make failures consistent regardless
  # of option order.
  raise OptionParser::MissingArgument
end

def validate_parallel

def validate_parallel
  return unless @options.key?(:parallel)
  if @options[:cache] == 'false'
    raise OptionArgumentError, '-P/--parallel uses caching to speed up ' \
                               'execution, so combining with --cache ' \
                               'false is not allowed.'
  end
  validate_parallel_with_combo_option
end

def validate_parallel_with_combo_option

def validate_parallel_with_combo_option
  combos = {
    auto_gen_config: '-P/--parallel uses caching to speed up execution, ' \
                     'while --auto-gen-config needs a non-cached run, ' \
                     'so they cannot be combined.',
    fail_fast: '-P/--parallel cannot be combined with -F/--fail-fast.',
    auto_correct: '-P/--parallel cannot be combined with --auto-correct.'
  }
  combos.each do |key, msg|
    raise OptionArgumentError, msg if @options.key?(key)
  end
end