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 disable_parallel_when_invalid_option_combo
def disable_parallel_when_invalid_option_combo return unless @options.key?(:parallel) invalid_options = [ { name: :auto_gen_config, value: true, flag: '--auto-gen-config' }, { name: :fail_fast, value: true, flag: '-F/--fail-fast.' }, { name: :auto_correct, value: true, flag: '--auto-correct.' }, { name: :cache, value: 'false', flag: '--cache false' } ] invalid_flags = invalid_options.each_with_object([]) do |option, flags| # `>` rather than `>=` because `@options` will also contain `parallel: true` flags << option[:flag] if @options > { option[:name] => option[:value] } end return if invalid_flags.empty? @options.delete(:parallel) puts '-P/--parallel is being ignored because ' \ "it is not compatible with #{invalid_flags.join(', ')}" 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/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 disable_parallel_when_invalid_option_combo return if incompatible_options.size <= 1 raise OptionArgumentError, "Incompatible cli options: #{incompatible_options.inspect}" end
def validate_cop_list(names)
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 { |opt| OptionsValidator.validate_cop_list(@options[opt]) } 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