diff --git a/lib/rubocop/options.rb b/lib/rubocop/options.rb index 6a598cf8414..04e7b5a2b40 100644 --- a/lib/rubocop/options.rb +++ b/lib/rubocop/options.rb @@ -59,86 +59,111 @@ def args_from_env def define_options OptionParser.new do |opts| - opts.banner = 'Usage: rubocop [options] [file1, file2, ...]' + opts.banner = rainbow.wrap('Usage: rubocop [options] [file1, file2, ...]').bright - add_list_options(opts) - add_only_options(opts) - add_configuration_options(opts) - add_formatting_options(opts) - - option(opts, '-r', '--require FILE') { |f| require_feature(f) } - - add_severity_option(opts) - add_flags_with_optional_args(opts) + add_check_options(opts) add_cache_options(opts) - add_boolean_flags(opts) - add_aliases(opts) + add_output_options(opts) + add_autocorrection_options(opts) + add_config_generation_options(opts) + add_additional_modes(opts) + add_general_options(opts) + end + end + def add_check_options(opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + section(opts, 'Basic Options') do + option(opts, '-l', '--lint') do + @options[:only] ||= [] + @options[:only] << 'Lint' + end + option(opts, '-x', '--fix-layout') do + @options[:only] ||= [] + @options[:only] << 'Layout' + @options[:auto_correct] = true + end + option(opts, '--safe') + add_cop_selection_csv_option('except', opts) + add_cop_selection_csv_option('only', opts) + option(opts, '--only-guide-cops') + option(opts, '-F', '--fail-fast') + option(opts, '--disable-pending-cops') + option(opts, '--enable-pending-cops') + option(opts, '--ignore-disable-comments') + option(opts, '--force-exclusion') + option(opts, '--only-recognized-file-types') + option(opts, '--ignore-parent-exclusion') + option(opts, '--force-default-config') option(opts, '-s', '--stdin FILE') + option(opts, '-P', '--[no-]parallel') + add_severity_option(opts) end end - def add_only_options(opts) - add_cop_selection_csv_option('except', opts) - add_cop_selection_csv_option('only', opts) - option(opts, '--only-guide-cops') - end + def add_output_options(opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + section(opts, 'Output Options') do + option(opts, '-f', '--format FORMATTER') do |key| + @options[:formatters] ||= [] + @options[:formatters] << [key] + end - def add_cop_selection_csv_option(option, opts) - option(opts, "--#{option} [COP1,COP2,...]") do |list| - unless list - message = "--#{option} argument should be [COP1,COP2,...]." + option(opts, '-D', '--[no-]display-cop-names') + option(opts, '-E', '--extra-details') + option(opts, '-S', '--display-style-guide') - raise OptionArgumentError, message + option(opts, '-o', '--out FILE') do |path| + if @options[:formatters] + @options[:formatters].last << path + else + @options[:output_path] = path + end end - @options[:"#{option}"] = list.empty? ? [''] : list.split(',') + option(opts, '--stderr') + option(opts, '--display-time') + option(opts, '--display-only-failed') + option(opts, '--display-only-fail-level-offenses') end end - def add_configuration_options(opts) - option(opts, '-c', '--config FILE') - option(opts, '--force-exclusion') - option(opts, '--only-recognized-file-types') - option(opts, '--ignore-parent-exclusion') - option(opts, '--force-default-config') - add_auto_gen_options(opts) - end - - def add_auto_gen_options(opts) - option(opts, '--auto-gen-config') - - option(opts, '--regenerate-todo') do - @options.replace(ConfigRegeneration.new.options.merge(@options)) + def add_autocorrection_options(opts) + section(opts, 'Auto-correction') do + option(opts, '-a', '--auto-correct') { @options[:safe_auto_correct] = true } + option(opts, '--safe-auto-correct') do + warn '--safe-auto-correct is deprecated; use --auto-correct' + @options[:safe_auto_correct] = @options[:auto_correct] = true + end + option(opts, '-A', '--auto-correct-all') { @options[:auto_correct] = true } + option(opts, '--disable-uncorrectable') end + end - option(opts, '--exclude-limit COUNT') { @validator.validate_exclude_limit_option } + def add_config_generation_options(opts) + section(opts, 'Config Generation') do + option(opts, '--auto-gen-config') - option(opts, '--disable-uncorrectable') + option(opts, '--regenerate-todo') do + @options.replace(ConfigRegeneration.new.options.merge(@options)) + end - option(opts, '--[no-]offense-counts') - option(opts, '--[no-]auto-gen-only-exclude') - option(opts, '--[no-]auto-gen-timestamp') + option(opts, '--exclude-limit COUNT') { @validator.validate_exclude_limit_option } - option(opts, '--init') + option(opts, '--[no-]offense-counts') + option(opts, '--[no-]auto-gen-only-exclude') + option(opts, '--[no-]auto-gen-timestamp') + end end - def add_formatting_options(opts) - option(opts, '-f', '--format FORMATTER') do |key| - @options[:formatters] ||= [] - @options[:formatters] << [key] - end + def add_cop_selection_csv_option(option, opts) + option(opts, "--#{option} [COP1,COP2,...]") do |list| + unless list + message = "--#{option} argument should be [COP1,COP2,...]." - option(opts, '-o', '--out FILE') do |path| - if @options[:formatters] - @options[:formatters].last << path - else - @options[:output_path] = path + raise OptionArgumentError, message end - end - option(opts, '--display-time') - option(opts, '--display-only-failed') + @options[:"#{option}"] = list.empty? ? [''] : list.split(',') + end end def add_severity_option(opts) @@ -148,62 +173,50 @@ def add_severity_option(opts) table) do |severity| @options[:fail_level] = severity end - option(opts, '--display-only-fail-level-offenses') end - def add_flags_with_optional_args(opts) - option(opts, '--show-cops [COP1,COP2,...]') do |list| - @options[:show_cops] = list.nil? ? [] : list.split(',') + def add_cache_options(opts) + section(opts, 'Caching') do + option(opts, '-C', '--cache FLAG') + option(opts, '--cache-root DIR') { @validator.validate_cache_enabled_for_cache_root } end end - def add_cache_options(opts) - option(opts, '-C', '--cache FLAG') - option(opts, '--cache-root DIR') { @validator.validate_cache_enabled_for_cache_root } - end - - # rubocop:disable Metrics/MethodLength, Metrics/AbcSize - def add_boolean_flags(opts) - option(opts, '-F', '--fail-fast') - option(opts, '-d', '--debug') - option(opts, '-D', '--[no-]display-cop-names') - option(opts, '-E', '--extra-details') - option(opts, '-S', '--display-style-guide') - option(opts, '-a', '--auto-correct') { @options[:safe_auto_correct] = true } - option(opts, '--safe-auto-correct') do - warn '--safe-auto-correct is deprecated; use --auto-correct' - @options[:safe_auto_correct] = @options[:auto_correct] = true + def add_additional_modes(opts) + section(opts, 'Additional Modes') do + option(opts, '-L', '--list-target-files') + option(opts, '--show-cops [COP1,COP2,...]') do |list| + @options[:show_cops] = list.nil? ? [] : list.split(',') + end end - option(opts, '-A', '--auto-correct-all') { @options[:auto_correct] = true } - option(opts, '--disable-pending-cops') - option(opts, '--enable-pending-cops') - option(opts, '--ignore-disable-comments') - - option(opts, '--safe') - - option(opts, '--stderr') - option(opts, '--[no-]color') - - option(opts, '-v', '--version') - option(opts, '-V', '--verbose-version') - option(opts, '-P', '--[no-]parallel') end - # rubocop:enable Metrics/MethodLength, Metrics/AbcSize - def add_aliases(opts) - option(opts, '-l', '--lint') do - @options[:only] ||= [] - @options[:only] << 'Lint' + def add_general_options(opts) + section(opts, 'General Options') do + option(opts, '--init') + option(opts, '-c', '--config FILE') + option(opts, '-d', '--debug') + option(opts, '-r', '--require FILE') { |f| require_feature(f) } + option(opts, '--[no-]color') + option(opts, '-v', '--version') + option(opts, '-V', '--verbose-version') end - option(opts, '-x', '--fix-layout') do - @options[:only] ||= [] - @options[:only] << 'Layout' - @options[:auto_correct] = true + end + + def rainbow + @rainbow ||= begin + rainbow = Rainbow.new + rainbow.enabled = false if ARGV.include?('--no-color') + rainbow end end - def add_list_options(opts) - option(opts, '-L', '--list-target-files') + # Creates a section of options in order to separate them visually when + # using `--help`. + def section(opts, heading, &_block) + heading = rainbow.wrap(heading).bright + opts.separator("\n#{heading}:\n") + yield end # Sets a value in the @options hash, based on the given long option and its @@ -403,7 +416,7 @@ module OptionsHelp only: 'Run only the given cop(s).', only_guide_cops: ['Run only cops for rules that link to a', 'style guide.'], - except: 'Disable the given cop(s).', + except: 'Exclude the given cop(s).', require: 'Require Ruby file.', config: 'Specify configuration file.', auto_gen_config: ['Generate a configuration file acting as a', @@ -422,29 +435,29 @@ module OptionsHelp 'when running --auto-gen-config, except if the', 'number of files with offenses is bigger than', 'exclude-limit. Default is false.'], - exclude_limit: ['Used together with --auto-gen-config to', - 'set the limit for how many Exclude', - "properties to generate. Default is #{MAX_EXCL}."], + exclude_limit: ['Set the limit for how many files to explicitly exclude.', + 'If there are more files than the limit, the cop will', + "be disabled instead. Default is #{MAX_EXCL}."], disable_uncorrectable: ['Used with --auto-correct to annotate any', 'offenses that do not support autocorrect', 'with `rubocop:todo` comments.'], - force_exclusion: ['Force excluding files specified in the', - 'configuration `Exclude` even if they are', - 'explicitly passed as arguments.'], + force_exclusion: ['Any files excluded by `Exclude` in configuration files', + 'will be excluded, even if given explictly as arguments.'], only_recognized_file_types: ['Inspect files given on the command line only if', - 'they are listed in AllCops/Include parameters', + 'they are listed in `AllCops/Include` parameters', 'of user configuration or default configuration.'], ignore_disable_comments: ['Run cops even when they are disabled locally', - 'with a comment.'], - ignore_parent_exclusion: ['Prevent from inheriting AllCops/Exclude from', + 'by a `rubocop:disable` directive.'], + ignore_parent_exclusion: ['Prevent from inheriting `AllCops/Exclude` from', 'parent folders.'], force_default_config: ['Use default configuration even if configuration', 'files are present in the directory tree.'], format: ['Choose an output formatter. This option', 'can be specified multiple times to enable', 'multiple formatters at the same time.', - '[p]rogress is used by default', - *FORMATTER_OPTION_LIST.map { |item| " #{item}" }, + *FORMATTER_OPTION_LIST.map do |item| + " #{item}#{' (default)' if item == '[p]rogress'}" + end, ' custom formatter class name'], out: ['Write output to a file instead of STDOUT.', 'This option applies to the previously', diff --git a/spec/rubocop/options_spec.rb b/spec/rubocop/options_spec.rb index 4221a6e00c1..2bf173e77c8 100644 --- a/spec/rubocop/options_spec.rb +++ b/spec/rubocop/options_spec.rb @@ -34,47 +34,51 @@ def abs(path) expected_help = <<~OUTPUT Usage: rubocop [options] [file1, file2, ...] - -L, --list-target-files List all files RuboCop will inspect. - --except [COP1,COP2,...] Disable the given cop(s). + + Basic Options: + -l, --lint Run only lint cops. + -x, --fix-layout Run only layout cops, with auto-correct on. + --safe Run only safe cops. + --except [COP1,COP2,...] Exclude the given cop(s). --only [COP1,COP2,...] Run only the given cop(s). --only-guide-cops Run only cops for rules that link to a style guide. - -c, --config FILE Specify configuration file. - --force-exclusion Force excluding files specified in the - configuration `Exclude` even if they are - explicitly passed as arguments. + -F, --fail-fast Inspect files in order of modification + time and stop after the first file + containing offenses. + --disable-pending-cops Run without pending cops. + --enable-pending-cops Run with pending cops. + --ignore-disable-comments Run cops even when they are disabled locally + by a `rubocop:disable` directive. + --force-exclusion Any files excluded by `Exclude` in configuration files + will be excluded, even if given explictly as arguments. --only-recognized-file-types Inspect files given on the command line only if - they are listed in AllCops/Include parameters + they are listed in `AllCops/Include` parameters of user configuration or default configuration. - --ignore-parent-exclusion Prevent from inheriting AllCops/Exclude from + --ignore-parent-exclusion Prevent from inheriting `AllCops/Exclude` from parent folders. --force-default-config Use default configuration even if configuration files are present in the directory tree. - --auto-gen-config Generate a configuration file acting as a - TODO list. - --regenerate-todo Regenerate the TODO configuration file using - the last configuration. If there is no existing - TODO file, acts like --auto-gen-config. - --exclude-limit COUNT Used together with --auto-gen-config to - set the limit for how many Exclude - properties to generate. Default is 15. - --disable-uncorrectable Used with --auto-correct to annotate any - offenses that do not support autocorrect - with `rubocop:todo` comments. - --[no-]offense-counts Include offense counts in configuration - file generated by --auto-gen-config. - Default is true. - --[no-]auto-gen-only-exclude Generate only Exclude parameters and not Max - when running --auto-gen-config, except if the - number of files with offenses is bigger than - exclude-limit. Default is false. - --[no-]auto-gen-timestamp Include the date and time when the --auto-gen-config - was run in the file it generates. Default is true. - --init Generate a .rubocop.yml file in the current directory. + -s, --stdin FILE Pipe source from STDIN, using FILE in offense + reports. This is useful for editor integration. + -P, --[no-]parallel Use available CPUs to execute inspection in + parallel. Default is true. + --fail-level SEVERITY Minimum severity (A/I/R/C/W/E/F) for exit + with error code. + + Caching: + -C, --cache FLAG Use result caching (FLAG=true) or don't + (FLAG=false), default determined by + configuration parameter AllCops: UseCache. + --cache-root DIR Set the cache root directory. + Takes precedence over the configuration + parameter AllCops: CacheRootDirectory and + the $RUBOCOP_CACHE_ROOT environment variable. + + Output Options: -f, --format FORMATTER Choose an output formatter. This option can be specified multiple times to enable multiple formatters at the same time. - [p]rogress is used by default [a]utogenconf [c]lang [e]macs @@ -86,63 +90,71 @@ def abs(path) [ju]nit [o]ffenses [pa]cman - [p]rogress + [p]rogress (default) [q]uiet [s]imple [t]ap [w]orst custom formatter class name + -D, --[no-]display-cop-names Display cop names in offense messages. + Default is true. + -E, --extra-details Display extra details in offense messages. + -S, --display-style-guide Display style guide URLs in offense messages. -o, --out FILE Write output to a file instead of STDOUT. This option applies to the previously specified --format, or the default format if no format is specified. + --stderr Write all output to stderr except for the + autocorrected source. This is especially useful + when combined with --auto-correct and --stdin. --display-time Display elapsed time in seconds. --display-only-failed Only output offense messages. Omit passing cops. Only valid for --format junit. - -r, --require FILE Require Ruby file. - --fail-level SEVERITY Minimum severity (A/I/R/C/W/E/F) for exit - with error code. --display-only-fail-level-offenses Only output offense messages at the specified --fail-level or above + + Auto-correction: + -a, --auto-correct Auto-correct offenses (only when it's safe). + --safe-auto-correct (same, deprecated) + -A, --auto-correct-all Auto-correct offenses (safe and unsafe) + --disable-uncorrectable Used with --auto-correct to annotate any + offenses that do not support autocorrect + with `rubocop:todo` comments. + + Config Generation: + --auto-gen-config Generate a configuration file acting as a + TODO list. + --regenerate-todo Regenerate the TODO configuration file using + the last configuration. If there is no existing + TODO file, acts like --auto-gen-config. + --exclude-limit COUNT Set the limit for how many files to explicitly exclude. + If there are more files than the limit, the cop will + be disabled instead. Default is 15. + --[no-]offense-counts Include offense counts in configuration + file generated by --auto-gen-config. + Default is true. + --[no-]auto-gen-only-exclude Generate only Exclude parameters and not Max + when running --auto-gen-config, except if the + number of files with offenses is bigger than + exclude-limit. Default is false. + --[no-]auto-gen-timestamp Include the date and time when the --auto-gen-config + was run in the file it generates. Default is true. + + Additional Modes: + -L, --list-target-files List all files RuboCop will inspect. --show-cops [COP1,COP2,...] Shows the given cops, or all cops by default, and their configurations for the current directory. - -C, --cache FLAG Use result caching (FLAG=true) or don't - (FLAG=false), default determined by - configuration parameter AllCops: UseCache. - --cache-root DIR Set the cache root directory. - Takes precedence over the configuration - parameter AllCops: CacheRootDirectory and - the $RUBOCOP_CACHE_ROOT environment variable. - -F, --fail-fast Inspect files in order of modification - time and stop after the first file - containing offenses. + + General Options: + --init Generate a .rubocop.yml file in the current directory. + -c, --config FILE Specify configuration file. -d, --debug Display debug info. - -D, --[no-]display-cop-names Display cop names in offense messages. - Default is true. - -E, --extra-details Display extra details in offense messages. - -S, --display-style-guide Display style guide URLs in offense messages. - -a, --auto-correct Auto-correct offenses (only when it's safe). - --safe-auto-correct (same, deprecated) - -A, --auto-correct-all Auto-correct offenses (safe and unsafe) - --disable-pending-cops Run without pending cops. - --enable-pending-cops Run with pending cops. - --ignore-disable-comments Run cops even when they are disabled locally - with a comment. - --safe Run only safe cops. - --stderr Write all output to stderr except for the - autocorrected source. This is especially useful - when combined with --auto-correct and --stdin. + -r, --require FILE Require Ruby file. --[no-]color Force color output on or off. -v, --version Display version. -V, --verbose-version Display verbose version. - -P, --[no-]parallel Use available CPUs to execute inspection in - parallel. Default is true. - -l, --lint Run only lint cops. - -x, --fix-layout Run only layout cops, with auto-correct on. - -s, --stdin FILE Pipe source from STDIN, using FILE in offense - reports. This is useful for editor integration. OUTPUT expect($stdout.string).to eq(expected_help)