From c39b454be528b7ee601a6397e70920eeccd253fe Mon Sep 17 00:00:00 2001 From: Miles Stanfield Date: Sat, 23 Nov 2024 06:19:47 -0500 Subject: [PATCH 1/8] updated standard to 1.37.0 and other related gems --- Gemfile | 4 ++-- Gemfile.lock | 60 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/Gemfile b/Gemfile index 98a12e2d..4cf5891a 100644 --- a/Gemfile +++ b/Gemfile @@ -2,10 +2,10 @@ source "https://rubygems.org" gem "activesupport", require: false gem "mry", "~> 0.52.0", require: false -gem "parser", "~> 3.0.2" +gem "parser", "~> 3.3.0" gem "pry", require: false gem "safe_yaml" -gem "standard", "~> 1.4", require: false +gem "standard", "1.37.0", require: false group :test do gem "rake" diff --git a/Gemfile.lock b/Gemfile.lock index 52bf2b0b..32947b36 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,20 +13,25 @@ GEM diff-lcs (1.4.4) i18n (1.8.10) concurrent-ruby (~> 1.0) + json (2.8.2) + language_server-protocol (3.17.0.3) + lint_roller (1.1.0) method_source (1.0.0) minitest (5.14.4) mry (0.52.0.0) rubocop (>= 0.41.0) - parallel (1.21.0) - parser (3.0.3.1) + parallel (1.26.3) + parser (3.3.6.0) ast (~> 2.4.1) + racc pry (0.14.1) coderay (~> 1.1) method_source (~> 1.0) - rainbow (3.0.0) + racc (1.8.1) + rainbow (3.1.1) rake (13.0.6) - regexp_parser (2.1.1) - rexml (3.2.5) + regexp_parser (2.9.2) + rexml (3.3.9) rspec (3.10.0) rspec-core (~> 3.10.0) rspec-expectations (~> 3.10.0) @@ -40,28 +45,39 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.10.0) rspec-support (3.10.2) - rubocop (1.22.3) + rubocop (1.64.1) + json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.0.0.0) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.12.0, < 2.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.13.0) - parser (>= 3.0.1.1) - rubocop-performance (1.11.5) - rubocop (>= 1.7.0, < 2.0) - rubocop-ast (>= 0.4.0) - ruby-progressbar (1.11.0) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.36.1) + parser (>= 3.3.1.0) + rubocop-performance (1.21.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + ruby-progressbar (1.13.0) safe_yaml (1.0.5) - standard (1.4.0) - rubocop (= 1.22.3) - rubocop-performance (= 1.11.5) + standard (1.37.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.64.0) + standard-custom (~> 1.0.0) + standard-performance (~> 1.4) + standard-custom (1.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.50) + standard-performance (1.4.0) + lint_roller (~> 1.1) + rubocop-performance (~> 1.21.0) tzinfo (2.0.4) concurrent-ruby (~> 1.0) - unicode-display_width (2.1.0) + unicode-display_width (2.6.0) zeitwerk (2.4.2) PLATFORMS @@ -70,12 +86,12 @@ PLATFORMS DEPENDENCIES activesupport mry (~> 0.52.0) - parser (~> 3.0.2) + parser (~> 3.3.0) pry rake rspec safe_yaml - standard (~> 1.4) + standard (= 1.37.0) BUNDLED WITH 2.1.4 From 65e2693b325cce51ab48fd971bc76206a64fd489 Mon Sep 17 00:00:00 2001 From: Miles Stanfield Date: Sat, 23 Nov 2024 06:25:38 -0500 Subject: [PATCH 2/8] added RuboCop::Cop::Style::BlockDelimiters to list of currently_undocumented_cops --- spec/support/currently_undocumented_cops.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/support/currently_undocumented_cops.txt b/spec/support/currently_undocumented_cops.txt index 2d40325a..b9b15e2b 100644 --- a/spec/support/currently_undocumented_cops.txt +++ b/spec/support/currently_undocumented_cops.txt @@ -3,3 +3,4 @@ RuboCop::Cop::Lint::Syntax RuboCop::Cop::Migration::DepartmentName RuboCop::Cop::Style::ConditionalAssignment RuboCop::Cop::Style::DoubleCopDisableDirective +RuboCop::Cop::Style::BlockDelimiters From 9fccafbaa0b3e5a01eda707a784234ec0d024ad3 Mon Sep 17 00:00:00 2001 From: Miles Stanfield Date: Sat, 23 Nov 2024 06:26:06 -0500 Subject: [PATCH 3/8] fixed broken spec for content change of Style/TrailingComma cop --- spec/rubocop/config_patch_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/rubocop/config_patch_spec.rb b/spec/rubocop/config_patch_spec.rb index 7e37d85a..be03163d 100644 --- a/spec/rubocop/config_patch_spec.rb +++ b/spec/rubocop/config_patch_spec.rb @@ -30,7 +30,7 @@ module CC::Engine expect { config.validate }.to output(<<~TXT).to_stderr The `Style/TrailingComma` cop has been removed. Please use `Style/TrailingCommaInArguments`, `Style/TrailingCommaInArrayLiteral` and/or `Style/TrailingCommaInHashLiteral` instead. (obsolete configuration found in .rubocop.yml, please update it) - unrecognized cop Style/TrailingComma found in .rubocop.yml + unrecognized cop or department Style/TrailingComma found in .rubocop.yml Did you mean `Style/TrailingCommaInArguments`? TXT end From 31117dbae98fd7a217d3113d97901ffb032710f9 Mon Sep 17 00:00:00 2001 From: Miles Stanfield Date: Sat, 23 Nov 2024 06:27:30 -0500 Subject: [PATCH 4/8] added "require \"ostruct\" in two specs to fix them from failing --- spec/cc/engine/issue_spec.rb | 1 + spec/cc/engine/standard_spec.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/cc/engine/issue_spec.rb b/spec/cc/engine/issue_spec.rb index f47c26ab..a071c232 100644 --- a/spec/cc/engine/issue_spec.rb +++ b/spec/cc/engine/issue_spec.rb @@ -1,5 +1,6 @@ require "spec_helper" require "cc/engine/issue" +require "ostruct" module CC::Engine describe Issue do diff --git a/spec/cc/engine/standard_spec.rb b/spec/cc/engine/standard_spec.rb index c03b124e..ae4bc8c3 100644 --- a/spec/cc/engine/standard_spec.rb +++ b/spec/cc/engine/standard_spec.rb @@ -1,6 +1,7 @@ require "spec_helper" require "cc/engine/standard" require "tmpdir" +require "ostruct" module CC::Engine describe Standard do From 90fbd1362432fedd9fdad0762323e61a088aa919 Mon Sep 17 00:00:00 2001 From: Miles Stanfield Date: Sat, 23 Nov 2024 06:49:55 -0500 Subject: [PATCH 5/8] fixed undefined issue running specs described in rubocop/rubocop#11169 issue. borrowed #registry code from rubocop cop_helper --- spec/support/standard_runner.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/spec/support/standard_runner.rb b/spec/support/standard_runner.rb index c65c182c..0e0e5bdd 100644 --- a/spec/support/standard_runner.rb +++ b/spec/support/standard_runner.rb @@ -4,6 +4,9 @@ module StandardRunner def self.included(example_group) example_group.include FilesystemHelpers + example_group.before do + allow_any_instance_of(RuboCop::AST::ProcessedSource).to receive(:registry).and_return(registry) + end example_group.around do |example| Dir.mktmpdir do |code| @code = code @@ -21,10 +24,22 @@ def issues(output = @engine_output) end def run_engine(config = nil) + @config = config io = StringIO.new - standard = CC::Engine::Standard.new(@code, config, io) + standard = CC::Engine::Standard.new(@code, @config, io) standard.run @engine_output = io.string end + + def registry + # https://github.com/rubocop/rubocop/blob/master/lib/rubocop/rspec/cop_helper.rb + @registry ||= begin + keys = RuboCop::Config.new(@config || {}, "#{Dir.pwd}/.rubocop.yml").keys + cops = keys.map { |directive| RuboCop::Cop::Registry.global.find_cops_by_directive(directive) }.flatten + cops << cop_class if defined?(cop_class) && !cops.include?(cop_class) + cops.compact! + RuboCop::Cop::Registry.new(cops) + end + end end From 35db2194e50f9f8114402372bbaba83b7a63b0ca Mon Sep 17 00:00:00 2001 From: Miles Stanfield Date: Wed, 4 Dec 2024 06:55:45 -0500 Subject: [PATCH 6/8] fixed docker image issue stating "The last version of bundler (>= 0) to support your Ruby & RubyGems was 2.4.22. Try installing it with `gem install bundler -v 2.4.22" --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c7def02c..f58f3962 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN adduser -u 9000 -g 9000 -D app COPY Gemfile Gemfile.lock /usr/src/app/ RUN apk add --update build-base && \ - gem install bundler && \ + gem install bundler -v 2.4.22 && \ bundle install --quiet -j 4 --without=test && \ chown -R app:app /usr/local/bundle && \ rm -fr ~/.gem ~/.bundle ~/.wh..gem && \ From 05d66bf39c8fca3dab9a19c161176c5442d351d7 Mon Sep 17 00:00:00 2001 From: Miles Stanfield Date: Wed, 4 Dec 2024 07:02:21 -0500 Subject: [PATCH 7/8] automated changes from "rake docs:scrape" --- config/contents/bundler/duplicated_gem.md | 1 + config/contents/bundler/duplicated_group.md | 51 +++++++ config/contents/bundler/gem_filename.md | 22 +++ .../bundler/insecure_protocol_source.md | 34 +++-- config/contents/bundler/ordered_gems.md | 10 +- config/contents/gemspec/date_assignment.md | 15 -- config/contents/gemspec/dependency_version.md | 46 +++++++ .../deprecated_attribute_assignment.md | 21 +++ .../gemspec/development_dependencies.md | 63 +++++++++ .../contents/gemspec/ordered_dependencies.md | 10 +- config/contents/gemspec/require_mfa.md | 56 ++++++++ .../contents/gemspec/required_ruby_version.md | 16 ++- .../gemspec/ruby_version_globals_usage.md | 2 +- .../contents/layout/assignment_indentation.md | 2 +- config/contents/layout/begin_end_alignment.md | 2 +- config/contents/layout/block_alignment.md | 29 ++-- config/contents/layout/block_end_newline.md | 2 +- config/contents/layout/case_indentation.md | 2 +- config/contents/layout/class_structure.md | 9 +- .../layout/closing_heredoc_indentation.md | 1 - .../layout/closing_parenthesis_indentation.md | 2 +- config/contents/layout/comment_indentation.md | 16 ++- config/contents/layout/condition_position.md | 2 +- config/contents/layout/def_end_alignment.md | 2 +- config/contents/layout/dot_position.md | 2 +- config/contents/layout/else_alignment.md | 2 +- config/contents/layout/empty_comment.md | 2 +- .../layout/empty_line_after_guard_clause.md | 18 ++- .../empty_line_after_multiline_condition.md | 2 +- .../layout/empty_line_between_defs.md | 25 +++- config/contents/layout/empty_lines.md | 2 +- .../layout/empty_lines_around_arguments.md | 2 +- .../layout/empty_lines_around_begin_body.md | 2 +- .../layout/empty_lines_around_block_body.md | 10 +- .../layout/empty_lines_around_class_body.md | 20 +-- ...ines_around_exception_handling_keywords.md | 2 +- .../layout/empty_lines_around_method_body.md | 2 +- .../layout/empty_lines_around_module_body.md | 20 +-- config/contents/layout/end_alignment.md | 6 +- config/contents/layout/end_of_line.md | 10 +- config/contents/layout/extra_spacing.md | 2 +- .../layout/first_argument_indentation.md | 56 ++++---- .../layout/first_array_element_indentation.md | 19 +-- .../layout/first_array_element_line_break.md | 39 ++++-- .../layout/first_hash_element_indentation.md | 37 ++++- .../layout/first_hash_element_line_break.md | 30 +++- .../first_method_argument_line_break.md | 60 ++++++-- .../first_method_parameter_line_break.md | 64 ++++++--- .../layout/first_parameter_indentation.md | 2 +- .../heredoc_argument_closing_parenthesis.md | 2 +- config/contents/layout/heredoc_indentation.md | 4 +- .../layout/indentation_consistency.md | 2 +- config/contents/layout/indentation_style.md | 2 +- config/contents/layout/indentation_width.md | 4 +- config/contents/layout/initial_indentation.md | 2 +- .../contents/layout/leading_comment_space.md | 2 +- config/contents/layout/leading_empty_lines.md | 2 +- .../layout/line_continuation_leading_space.md | 37 +++++ .../layout/line_continuation_spacing.md | 24 ++++ ...ne_end_string_concatenation_indentation.md | 30 ++-- config/contents/layout/line_length.md | 4 +- .../layout/multiline_array_brace_layout.md | 2 +- .../layout/multiline_array_line_breaks.md | 27 +++- .../layout/multiline_assignment_layout.md | 2 +- .../contents/layout/multiline_block_layout.md | 2 +- .../layout/multiline_hash_brace_layout.md | 2 +- .../layout/multiline_hash_key_line_breaks.md | 26 +++- .../multiline_method_argument_line_breaks.md | 37 ++++- .../multiline_method_call_brace_layout.md | 2 +- .../multiline_method_call_indentation.md | 2 +- ...ultiline_method_definition_brace_layout.md | 2 +- .../multiline_method_parameter_line_breaks.md | 50 +++++++ .../layout/multiline_operation_indentation.md | 15 +- .../contents/layout/redundant_line_break.md | 2 +- .../layout/rescue_ensure_alignment.md | 2 +- .../layout/single_line_block_chain.md | 2 +- config/contents/layout/space_after_not.md | 2 +- .../space_around_method_call_operator.md | 4 +- .../contents/layout/space_around_operators.md | 16 ++- .../contents/layout/space_before_comment.md | 2 +- .../layout/space_in_lambda_literal.md | 2 +- .../space_inside_array_literal_brackets.md | 20 +-- .../space_inside_array_percent_literal.md | 3 + .../space_inside_hash_literal_braces.md | 8 +- config/contents/layout/space_inside_parens.md | 21 +++ ...space_inside_percent_literal_delimiters.md | 19 ++- .../layout/space_inside_reference_brackets.md | 4 + .../space_inside_string_interpolation.md | 2 +- .../contents/layout/trailing_empty_lines.md | 16 +-- config/contents/layout/trailing_whitespace.md | 2 +- config/contents/lint/ambiguous_assignment.md | 2 +- .../lint/ambiguous_block_association.md | 25 +++- config/contents/lint/ambiguous_operator.md | 2 +- .../lint/ambiguous_operator_precedence.md | 24 ++++ config/contents/lint/ambiguous_range.md | 53 ++++++++ .../contents/lint/ambiguous_regexp_literal.md | 2 +- .../contents/lint/assignment_in_condition.md | 14 +- ...binary_operator_with_identical_operands.md | 29 ++-- config/contents/lint/boolean_symbol.md | 7 +- .../lint/circular_argument_reference.md | 2 +- .../lint/constant_overwritten_in_rescue.md | 19 +++ config/contents/lint/constant_resolution.md | 4 + config/contents/lint/debugger.md | 31 ++++- .../contents/lint/deprecated_class_methods.md | 16 ++- config/contents/lint/deprecated_constants.md | 11 +- .../disjunctive_assignment_in_constructor.md | 25 +++- config/contents/lint/duplicate_branch.md | 4 +- .../contents/lint/duplicate_case_condition.md | 2 +- .../lint/duplicate_elsif_condition.md | 2 +- config/contents/lint/duplicate_hash_key.md | 3 +- .../contents/lint/duplicate_magic_comment.md | 21 +++ .../contents/lint/duplicate_match_pattern.md | 83 ++++++++++++ config/contents/lint/duplicate_methods.md | 2 +- ...uplicate_regexp_character_class_element.md | 2 +- config/contents/lint/duplicate_require.md | 6 +- .../lint/duplicate_rescue_exception.md | 2 +- .../lint/each_with_object_argument.md | 2 +- config/contents/lint/else_layout.md | 6 +- config/contents/lint/empty_block.md | 4 +- config/contents/lint/empty_class.md | 2 +- .../contents/lint/empty_conditional_body.md | 10 +- config/contents/lint/empty_ensure.md | 2 +- config/contents/lint/empty_expression.md | 2 +- config/contents/lint/empty_file.md | 2 +- config/contents/lint/empty_in_pattern.md | 2 +- config/contents/lint/empty_interpolation.md | 2 +- config/contents/lint/empty_when.md | 2 +- config/contents/lint/ensure_return.md | 2 +- config/contents/lint/erb_new_arguments.md | 25 ++-- config/contents/lint/flip_flop.md | 2 +- config/contents/lint/float_comparison.md | 6 +- config/contents/lint/float_out_of_range.md | 2 +- .../contents/lint/hash_compare_by_identity.md | 15 +- .../lint/heredoc_method_call_position.md | 34 +++-- config/contents/lint/identity_comparison.md | 1 - .../lint/implicit_string_concatenation.md | 2 +- ...mpatible_io_select_with_fiber_scheduler.md | 27 ++++ .../lint/ineffective_access_modifier.md | 2 +- config/contents/lint/inherit_exception.md | 24 ++-- config/contents/lint/interpolation_check.md | 8 +- .../lint/it_without_arguments_in_block.md | 20 +++ .../lint/lambda_without_literal_block.md | 6 +- config/contents/lint/literal_as_condition.md | 5 +- .../lint/literal_assignment_in_condition.md | 28 ++++ .../contents/lint/literal_in_interpolation.md | 2 +- config/contents/lint/loop.md | 9 +- config/contents/lint/missing_super.md | 42 +++++- config/contents/lint/mixed_case_range.md | 22 +++ .../lint/mixed_regexp_capture_types.md | 1 + .../contents/lint/nested_method_definition.md | 43 +++++- .../contents/lint/nested_percent_literal.md | 2 +- .../lint/non_atomic_file_operation.md | 37 +++++ .../lint/non_deterministic_require_order.md | 6 +- .../lint/non_local_exit_from_iterator.md | 2 +- config/contents/lint/number_conversion.md | 31 ++++- .../lint/numbered_parameter_assignment.md | 8 +- .../lint/or_assignment_to_constant.md | 7 +- .../contents/lint/ordered_magic_comments.md | 4 +- .../contents/lint/out_of_range_regexp_ref.md | 19 ++- config/contents/lint/percent_string_array.md | 12 +- config/contents/lint/percent_symbol_array.md | 2 +- config/contents/lint/raise_exception.md | 6 +- config/contents/lint/rand_one.md | 2 +- .../contents/lint/redundant_dir_glob_sort.md | 5 + .../lint/redundant_regexp_quantifiers.md | 28 ++++ .../lint/redundant_require_statement.md | 18 ++- .../lint/redundant_safe_navigation.md | 53 +++++++- .../lint/redundant_splat_expansion.md | 2 +- .../lint/redundant_string_coercion.md | 10 +- config/contents/lint/redundant_with_index.md | 2 +- config/contents/lint/redundant_with_object.md | 2 +- .../lint/refinement_import_methods.md | 27 ++++ config/contents/lint/regexp_as_condition.md | 2 +- config/contents/lint/require_parentheses.md | 2 +- .../lint/require_range_parentheses.md | 33 +++++ .../lint/require_relative_self_path.md | 14 ++ config/contents/lint/rescue_exception.md | 2 +- .../contents/lint/return_in_void_context.md | 2 +- .../lint/safe_navigation_consistency.md | 2 +- .../lint/safe_navigation_with_empty.md | 2 +- config/contents/lint/script_permission.md | 2 +- config/contents/lint/self_assignment.md | 9 +- .../contents/lint/send_with_mixin_argument.md | 3 +- config/contents/lint/shadowed_argument.md | 2 +- config/contents/lint/shadowed_exception.md | 17 ++- .../lint/shadowing_outer_local_variable.md | 7 +- config/contents/lint/struct_new_override.md | 2 +- config/contents/lint/suppressed_exception.md | 2 +- config/contents/lint/symbol_conversion.md | 4 +- config/contents/lint/to_enum_arguments.md | 10 +- config/contents/lint/to_json.md | 2 +- .../lint/top_level_return_with_argument.md | 8 +- ...trailing_comma_in_attribute_declaration.md | 2 +- config/contents/lint/triple_quotes.md | 2 +- .../lint/underscore_prefixed_variable_name.md | 2 +- .../contents/lint/unexpected_block_arity.md | 13 +- config/contents/lint/unified_integer.md | 2 +- config/contents/lint/unreachable_code.md | 2 +- config/contents/lint/unreachable_loop.md | 8 +- config/contents/lint/unused_block_argument.md | 2 +- .../contents/lint/unused_method_argument.md | 2 +- config/contents/lint/uri_escape_unescape.md | 2 +- config/contents/lint/uri_regexp.md | 2 +- .../contents/lint/useless_access_modifier.md | 6 +- config/contents/lint/useless_assignment.md | 16 ++- .../lint/useless_else_without_rescue.md | 5 +- .../lint/useless_method_definition.md | 7 +- config/contents/lint/useless_rescue.md | 42 ++++++ .../contents/lint/useless_ruby2_keywords.md | 59 ++++++++ config/contents/lint/useless_setter_call.md | 13 +- config/contents/lint/useless_times.md | 9 +- config/contents/lint/void.md | 12 +- .../contents/naming/accessor_method_name.md | 2 +- config/contents/naming/ascii_identifiers.md | 2 +- .../naming/binary_operator_parameter_name.md | 2 +- config/contents/naming/block_forwarding.md | 33 +++++ .../contents/naming/block_parameter_name.md | 4 +- .../naming/class_and_module_camel_case.md | 2 +- config/contents/naming/constant_name.md | 2 +- config/contents/naming/file_name.md | 14 +- .../contents/naming/heredoc_delimiter_case.md | 2 +- .../naming/heredoc_delimiter_naming.md | 2 +- config/contents/naming/inclusive_language.md | 18 ++- .../naming/memoized_instance_variable_name.md | 14 +- config/contents/naming/method_name.md | 10 +- .../contents/naming/method_parameter_name.md | 4 +- config/contents/naming/predicate_name.md | 32 ++++- .../rescued_exceptions_variable_name.md | 2 +- config/contents/naming/variable_name.md | 12 +- config/contents/naming/variable_number.md | 40 +++--- .../contents/performance/ancestors_include.md | 7 +- .../array_semi_infinite_range_slice.md | 6 +- .../big_decimal_with_numeric_argument.md | 6 +- .../block_given_with_explicit_block.md | 2 +- config/contents/performance/caller.md | 3 +- .../contents/performance/case_when_splat.md | 12 +- config/contents/performance/casecmp.md | 14 +- .../performance/chain_array_allocation.md | 12 +- .../performance/collection_literal_in_loop.md | 4 +- .../performance/compare_with_block.md | 16 ++- .../performance/concurrent_monotonic_time.md | 10 ++ .../contents/performance/constant_regexp.md | 2 +- config/contents/performance/count.md | 38 ++++-- config/contents/performance/delete_prefix.md | 4 +- config/contents/performance/delete_suffix.md | 4 +- config/contents/performance/detect.md | 12 +- .../performance/double_start_end_with.md | 24 +++- config/contents/performance/end_with.md | 7 +- config/contents/performance/flat_map.md | 2 +- .../performance/inefficient_hash_search.md | 5 +- config/contents/performance/io_readlines.md | 2 +- config/contents/performance/map_compact.md | 7 +- .../contents/performance/map_method_chain.md | 36 +++++ .../performance/method_object_as_block.md | 2 +- config/contents/performance/open_struct.md | 6 +- config/contents/performance/range_include.md | 20 +-- .../performance/redundant_block_call.md | 2 +- .../redundant_equality_comparison_block.md | 30 +++- .../contents/performance/redundant_match.md | 2 +- .../contents/performance/redundant_merge.md | 8 +- .../performance/redundant_sort_block.md | 3 +- .../redundant_split_regexp_argument.md | 2 +- .../performance/redundant_string_chars.md | 7 +- config/contents/performance/reverse_each.md | 3 +- config/contents/performance/reverse_first.md | 2 +- config/contents/performance/size.md | 3 +- config/contents/performance/sort_reverse.md | 2 +- config/contents/performance/squeeze.md | 2 +- config/contents/performance/start_with.md | 7 +- .../performance/string_identifier_argument.md | 26 ++++ config/contents/performance/string_include.md | 21 +-- .../performance/string_replacement.md | 3 +- config/contents/performance/sum.md | 68 ++++++---- config/contents/performance/times_map.md | 14 +- .../contents/performance/unfreeze_string.md | 14 +- .../performance/uri_default_parser.md | 3 +- config/contents/security/compound_hash.md | 24 ++++ config/contents/security/eval.md | 2 +- config/contents/security/io_methods.md | 23 ++++ config/contents/security/json_load.md | 17 +-- config/contents/security/marshal_load.md | 2 +- config/contents/security/open.md | 18 ++- config/contents/security/yaml_load.md | 16 ++- .../standard/block_single_line_braces.md | 9 -- .../style/access_modifier_declarations.md | 44 ++++++ config/contents/style/accessor_grouping.md | 21 ++- config/contents/style/alias.md | 9 +- config/contents/style/and_or.md | 21 +-- config/contents/style/arguments_forwarding.md | 91 ++++++++++++- config/contents/style/array_coercion.md | 26 +++- config/contents/style/array_first_last.md | 21 +++ config/contents/style/array_intersect.md | 43 ++++++ config/contents/style/array_join.md | 2 +- config/contents/style/ascii_comments.md | 2 +- config/contents/style/attr.md | 2 +- .../contents/style/auto_resource_cleanup.md | 10 +- .../contents/style/bare_percent_literals.md | 2 +- config/contents/style/begin_block.md | 3 +- .../contents/style/bisected_attr_accessor.md | 2 +- config/contents/style/block_comments.md | 2 +- config/contents/style/block_delimiters.md | 128 ------------------ config/contents/style/case_equality.md | 27 ++-- config/contents/style/case_like_if.md | 25 +++- config/contents/style/character_literal.md | 11 +- .../style/class_and_module_children.md | 11 +- config/contents/style/class_check.md | 2 +- .../style/class_equality_comparison.md | 35 ++++- config/contents/style/class_methods.md | 2 +- .../style/class_methods_definitions.md | 2 +- config/contents/style/class_vars.md | 2 +- config/contents/style/collection_compact.md | 26 +++- config/contents/style/collection_methods.md | 15 +- config/contents/style/colon_method_call.md | 4 +- .../contents/style/colon_method_definition.md | 2 +- config/contents/style/combinable_loops.md | 7 +- config/contents/style/command_literal.md | 2 +- config/contents/style/comment_annotation.md | 5 +- config/contents/style/commented_keyword.md | 8 +- config/contents/style/comparable_clamp.md | 28 ++++ .../contents/style/concat_array_literals.md | 18 +++ config/contents/style/constant_visibility.md | 2 +- config/contents/style/copyright.md | 7 +- config/contents/style/data_inheritance.md | 20 +++ config/contents/style/date_time.md | 7 +- config/contents/style/def_with_parentheses.md | 20 ++- config/contents/style/dir.md | 2 +- config/contents/style/dir_empty.md | 11 ++ config/contents/style/documentation.md | 52 +++---- config/contents/style/documentation_method.md | 17 ++- config/contents/style/double_negation.md | 36 ++++- config/contents/style/each_for_simple_loop.md | 2 +- config/contents/style/each_with_object.md | 2 +- .../contents/style/empty_block_parameter.md | 2 +- config/contents/style/empty_case_condition.md | 2 +- config/contents/style/empty_else.md | 42 +++++- config/contents/style/empty_heredoc.md | 29 ++++ .../contents/style/empty_lambda_parameter.md | 2 +- config/contents/style/empty_literal.md | 2 +- config/contents/style/empty_method.md | 8 +- config/contents/style/encoding.md | 2 +- config/contents/style/end_block.md | 2 +- config/contents/style/endless_method.md | 4 +- config/contents/style/env_home.md | 24 ++++ config/contents/style/eval_with_location.md | 10 +- config/contents/style/even_odd.md | 2 +- config/contents/style/exact_regexp_match.md | 18 +++ .../contents/style/expand_path_arguments.md | 2 +- .../contents/style/explicit_block_argument.md | 2 +- config/contents/style/exponential_notation.md | 2 +- config/contents/style/fetch_env_var.md | 18 +++ config/contents/style/file_empty.md | 20 +++ config/contents/style/file_read.md | 31 +++++ config/contents/style/file_write.md | 34 +++++ config/contents/style/float_division.md | 14 +- config/contents/style/for.md | 6 +- config/contents/style/format_string.md | 36 +++-- config/contents/style/format_string_token.md | 20 ++- .../style/frozen_string_literal_comment.md | 11 +- config/contents/style/global_std_stream.md | 6 +- config/contents/style/global_vars.md | 2 +- config/contents/style/guard_clause.md | 65 ++++++++- config/contents/style/hash_conversion.md | 12 +- config/contents/style/hash_each_methods.md | 15 +- config/contents/style/hash_except.md | 9 +- config/contents/style/hash_like_case.md | 2 +- config/contents/style/hash_syntax.md | 78 ++++++++++- config/contents/style/hash_transform_keys.md | 16 +-- .../contents/style/hash_transform_values.md | 14 +- .../style/identical_conditional_branches.md | 20 ++- config/contents/style/if_unless_modifier.md | 26 ++++ .../style/if_with_boolean_literal_branches.md | 42 +++++- .../contents/style/implicit_runtime_error.md | 2 +- config/contents/style/in_pattern_then.md | 2 +- config/contents/style/infinite_loop.md | 7 +- config/contents/style/inline_comment.md | 2 +- config/contents/style/inverse_methods.md | 13 +- .../style/invertible_unless_condition.md | 46 +++++++ config/contents/style/ip_addresses.md | 2 +- .../style/keyword_parameters_order.md | 2 +- config/contents/style/lambda.md | 2 +- config/contents/style/lambda_call.md | 2 +- .../contents/style/line_end_concatenation.md | 15 +- config/contents/style/magic_comment_format.md | 90 ++++++++++++ .../map_compact_with_conditional_block.md | 33 +++++ config/contents/style/map_into_array.md | 43 ++++++ config/contents/style/map_to_hash.md | 23 ++++ config/contents/style/map_to_set.md | 19 +++ .../method_call_with_args_parentheses.md | 89 ++++++------ .../method_call_without_args_parentheses.md | 18 ++- .../style/method_called_on_do_end_block.md | 2 +- .../contents/style/method_def_parentheses.md | 13 +- config/contents/style/min_max.md | 2 +- config/contents/style/min_max_comparison.md | 30 ++++ config/contents/style/missing_else.md | 51 +++---- .../style/missing_respond_to_missing.md | 6 +- config/contents/style/mixin_grouping.md | 2 +- config/contents/style/mixin_usage.md | 2 +- config/contents/style/module_function.md | 41 ++++-- .../contents/style/multiline_block_chain.md | 2 +- .../style/multiline_in_pattern_then.md | 2 +- .../contents/style/multiline_memoization.md | 2 +- .../style/multiline_method_signature.md | 2 +- .../style/multiline_ternary_operator.md | 13 +- config/contents/style/multiline_when_then.md | 2 +- config/contents/style/multiple_comparison.md | 12 +- config/contents/style/mutable_constant.md | 31 ++++- .../style/negated_if_else_condition.md | 2 +- config/contents/style/nested_file_dirname.md | 10 ++ config/contents/style/nested_modifier.md | 2 +- .../style/nested_parenthesized_calls.md | 12 +- .../contents/style/nested_ternary_operator.md | 2 +- config/contents/style/nil_comparison.md | 2 +- config/contents/style/nil_lambda.md | 2 +- config/contents/style/non_nil_check.md | 2 +- config/contents/style/not.md | 2 +- config/contents/style/numbered_parameters.md | 20 +++ .../style/numbered_parameters_limit.md | 14 ++ .../contents/style/numeric_literal_prefix.md | 2 +- config/contents/style/numeric_literals.md | 15 +- config/contents/style/numeric_predicate.md | 49 +++++-- config/contents/style/object_then.md | 18 +++ config/contents/style/one_line_conditional.md | 2 +- config/contents/style/open_struct_use.md | 37 +++++ config/contents/style/operator_method_call.md | 13 ++ config/contents/style/option_hash.md | 2 +- config/contents/style/optional_arguments.md | 6 +- .../style/optional_boolean_parameter.md | 6 +- config/contents/style/or_assignment.md | 2 +- .../style/parentheses_around_condition.md | 2 +- .../style/percent_literal_delimiters.md | 2 +- config/contents/style/percent_q_literals.md | 2 +- config/contents/style/perl_backrefs.md | 2 +- .../contents/style/preferred_hash_methods.md | 13 +- config/contents/style/proc.md | 2 +- config/contents/style/quoted_symbols.md | 3 +- config/contents/style/raise_args.md | 5 +- config/contents/style/random_with_offset.md | 2 +- config/contents/style/redundant_argument.md | 30 ++-- .../style/redundant_array_constructor.md | 18 +++ config/contents/style/redundant_assignment.md | 2 +- config/contents/style/redundant_begin.md | 3 +- config/contents/style/redundant_capital_w.md | 2 +- config/contents/style/redundant_condition.md | 2 +- .../contents/style/redundant_conditional.md | 2 +- .../contents/style/redundant_constant_base.md | 37 +++++ .../redundant_current_directory_in_path.md | 9 ++ .../redundant_double_splat_hash_braces.md | 15 ++ config/contents/style/redundant_each.md | 27 ++++ config/contents/style/redundant_exception.md | 19 +-- .../contents/style/redundant_fetch_block.md | 14 +- .../redundant_file_extension_in_require.md | 2 +- .../contents/style/redundant_filter_chain.md | 46 +++++++ config/contents/style/redundant_freeze.md | 5 +- .../redundant_heredoc_delimiter_quotes.md | 22 +++ config/contents/style/redundant_initialize.md | 90 ++++++++++++ .../contents/style/redundant_interpolation.md | 23 +++- .../style/redundant_line_continuation.md | 60 ++++++++ .../contents/style/redundant_parentheses.md | 2 +- config/contents/style/redundant_percent_q.md | 2 +- .../style/redundant_regexp_argument.md | 29 ++++ .../style/redundant_regexp_character_class.md | 2 +- .../style/redundant_regexp_constructor.md | 13 ++ .../contents/style/redundant_regexp_escape.md | 2 +- config/contents/style/redundant_return.md | 9 +- config/contents/style/redundant_self.md | 5 +- .../style/redundant_self_assignment.md | 9 +- .../style/redundant_self_assignment_branch.md | 18 +++ config/contents/style/redundant_sort.md | 29 +++- config/contents/style/redundant_sort_by.md | 2 +- .../contents/style/redundant_string_escape.md | 31 +++++ config/contents/style/regexp_literal.md | 11 +- config/contents/style/require_order.md | 59 ++++++++ config/contents/style/rescue_modifier.md | 6 +- .../contents/style/rescue_standard_error.md | 22 +-- config/contents/style/return_nil.md | 8 +- ...turn_nil_in_predicate_method_definition.md | 43 ++++++ config/contents/style/safe_navigation.md | 29 +++- config/contents/style/sample.md | 2 +- config/contents/style/select_by_regexp.md | 39 ++++++ config/contents/style/self_assignment.md | 2 +- config/contents/style/semicolon.md | 2 +- config/contents/style/send.md | 10 +- .../style/send_with_literal_method_name.md | 33 +++++ config/contents/style/signal_exception.md | 2 +- config/contents/style/single_argument_dig.md | 12 +- .../style/single_line_block_params.md | 2 +- .../style/single_line_do_end_block.md | 21 +++ config/contents/style/single_line_methods.md | 4 +- config/contents/style/slicing_with_range.md | 38 +++++- .../contents/style/sole_nested_conditional.md | 15 ++ config/contents/style/special_global_vars.md | 37 ++++- config/contents/style/static_class.md | 9 +- config/contents/style/stderr_puts.md | 2 +- config/contents/style/string_chars.md | 6 +- config/contents/style/string_concatenation.md | 6 +- config/contents/style/string_hash_keys.md | 6 +- .../style/string_literals_in_interpolation.md | 30 +++- config/contents/style/string_methods.md | 2 +- config/contents/style/strip.md | 2 +- config/contents/style/struct_inheritance.md | 6 +- config/contents/style/super_arguments.md | 31 +++++ .../style/super_with_args_parentheses.md | 11 ++ config/contents/style/swap_values.md | 8 +- config/contents/style/symbol_array.md | 14 +- config/contents/style/symbol_literal.md | 2 +- config/contents/style/symbol_proc.md | 112 ++++++++++++++- config/contents/style/ternary_parentheses.md | 2 +- .../contents/style/trailing_body_on_class.md | 2 +- .../trailing_body_on_method_definition.md | 2 +- .../contents/style/trailing_body_on_module.md | 2 +- .../style/trailing_comma_in_arguments.md | 2 +- .../style/trailing_comma_in_array_literal.md | 4 +- .../style/trailing_comma_in_block_args.md | 21 ++- .../style/trailing_comma_in_hash_literal.md | 4 +- .../style/trailing_method_end_statement.md | 2 +- .../style/trailing_underscore_variable.md | 2 +- config/contents/style/trivial_accessors.md | 5 +- config/contents/style/unless_else.md | 2 +- .../style/unless_logical_operators.md | 3 +- config/contents/style/unpack_first.md | 2 +- .../contents/style/variable_interpolation.md | 2 +- config/contents/style/when_then.md | 2 +- config/contents/style/word_array.md | 44 +++++- config/contents/style/yaml_file_read.md | 20 +++ config/contents/style/yoda_condition.md | 24 +++- config/contents/style/yoda_expression.md | 33 +++++ .../contents/style/zero_length_predicate.md | 19 ++- 527 files changed, 5942 insertions(+), 1286 deletions(-) create mode 100644 config/contents/bundler/duplicated_group.md create mode 100644 config/contents/bundler/gem_filename.md delete mode 100644 config/contents/gemspec/date_assignment.md create mode 100644 config/contents/gemspec/dependency_version.md create mode 100644 config/contents/gemspec/deprecated_attribute_assignment.md create mode 100644 config/contents/gemspec/development_dependencies.md create mode 100644 config/contents/gemspec/require_mfa.md create mode 100644 config/contents/layout/line_continuation_leading_space.md create mode 100644 config/contents/layout/line_continuation_spacing.md create mode 100644 config/contents/layout/multiline_method_parameter_line_breaks.md create mode 100644 config/contents/lint/ambiguous_operator_precedence.md create mode 100644 config/contents/lint/ambiguous_range.md create mode 100644 config/contents/lint/constant_overwritten_in_rescue.md create mode 100644 config/contents/lint/duplicate_magic_comment.md create mode 100644 config/contents/lint/duplicate_match_pattern.md create mode 100644 config/contents/lint/incompatible_io_select_with_fiber_scheduler.md create mode 100644 config/contents/lint/it_without_arguments_in_block.md create mode 100644 config/contents/lint/literal_assignment_in_condition.md create mode 100644 config/contents/lint/mixed_case_range.md create mode 100644 config/contents/lint/non_atomic_file_operation.md create mode 100644 config/contents/lint/redundant_regexp_quantifiers.md create mode 100644 config/contents/lint/refinement_import_methods.md create mode 100644 config/contents/lint/require_range_parentheses.md create mode 100644 config/contents/lint/require_relative_self_path.md create mode 100644 config/contents/lint/useless_rescue.md create mode 100644 config/contents/lint/useless_ruby2_keywords.md create mode 100644 config/contents/naming/block_forwarding.md create mode 100644 config/contents/performance/concurrent_monotonic_time.md create mode 100644 config/contents/performance/map_method_chain.md create mode 100644 config/contents/performance/string_identifier_argument.md create mode 100644 config/contents/security/compound_hash.md create mode 100644 config/contents/security/io_methods.md delete mode 100644 config/contents/standard/block_single_line_braces.md create mode 100644 config/contents/style/array_first_last.md create mode 100644 config/contents/style/array_intersect.md delete mode 100644 config/contents/style/block_delimiters.md create mode 100644 config/contents/style/comparable_clamp.md create mode 100644 config/contents/style/concat_array_literals.md create mode 100644 config/contents/style/data_inheritance.md create mode 100644 config/contents/style/dir_empty.md create mode 100644 config/contents/style/empty_heredoc.md create mode 100644 config/contents/style/env_home.md create mode 100644 config/contents/style/exact_regexp_match.md create mode 100644 config/contents/style/fetch_env_var.md create mode 100644 config/contents/style/file_empty.md create mode 100644 config/contents/style/file_read.md create mode 100644 config/contents/style/file_write.md create mode 100644 config/contents/style/invertible_unless_condition.md create mode 100644 config/contents/style/magic_comment_format.md create mode 100644 config/contents/style/map_compact_with_conditional_block.md create mode 100644 config/contents/style/map_into_array.md create mode 100644 config/contents/style/map_to_hash.md create mode 100644 config/contents/style/map_to_set.md create mode 100644 config/contents/style/min_max_comparison.md create mode 100644 config/contents/style/nested_file_dirname.md create mode 100644 config/contents/style/numbered_parameters.md create mode 100644 config/contents/style/numbered_parameters_limit.md create mode 100644 config/contents/style/object_then.md create mode 100644 config/contents/style/open_struct_use.md create mode 100644 config/contents/style/operator_method_call.md create mode 100644 config/contents/style/redundant_array_constructor.md create mode 100644 config/contents/style/redundant_constant_base.md create mode 100644 config/contents/style/redundant_current_directory_in_path.md create mode 100644 config/contents/style/redundant_double_splat_hash_braces.md create mode 100644 config/contents/style/redundant_each.md create mode 100644 config/contents/style/redundant_filter_chain.md create mode 100644 config/contents/style/redundant_heredoc_delimiter_quotes.md create mode 100644 config/contents/style/redundant_initialize.md create mode 100644 config/contents/style/redundant_line_continuation.md create mode 100644 config/contents/style/redundant_regexp_argument.md create mode 100644 config/contents/style/redundant_regexp_constructor.md create mode 100644 config/contents/style/redundant_self_assignment_branch.md create mode 100644 config/contents/style/redundant_string_escape.md create mode 100644 config/contents/style/require_order.md create mode 100644 config/contents/style/return_nil_in_predicate_method_definition.md create mode 100644 config/contents/style/select_by_regexp.md create mode 100644 config/contents/style/send_with_literal_method_name.md create mode 100644 config/contents/style/single_line_do_end_block.md create mode 100644 config/contents/style/super_arguments.md create mode 100644 config/contents/style/super_with_args_parentheses.md create mode 100644 config/contents/style/yaml_file_read.md create mode 100644 config/contents/style/yoda_expression.md diff --git a/config/contents/bundler/duplicated_gem.md b/config/contents/bundler/duplicated_gem.md index 029c38e0..6f3f5aaa 100644 --- a/config/contents/bundler/duplicated_gem.md +++ b/config/contents/bundler/duplicated_gem.md @@ -1,4 +1,5 @@ A Gem's requirements should be listed only once in a Gemfile. + ### Example: # bad gem 'rubocop' diff --git a/config/contents/bundler/duplicated_group.md b/config/contents/bundler/duplicated_group.md new file mode 100644 index 00000000..cc403600 --- /dev/null +++ b/config/contents/bundler/duplicated_group.md @@ -0,0 +1,51 @@ +A Gem group, or a set of groups, should be listed only once in a Gemfile. + +For example, if the values of `source`, `git`, `platforms`, or `path` +surrounding `group` are different, no offense will be registered: + +[source,ruby] +----- +platforms :ruby do + group :default do + gem 'openssl' + end +end + +platforms :jruby do + group :default do + gem 'jruby-openssl' + end +end +----- + +### Example: + # bad + group :development do + gem 'rubocop' + end + + group :development do + gem 'rubocop-rails' + end + + # bad (same set of groups declared twice) + group :development, :test do + gem 'rubocop' + end + + group :test, :development do + gem 'rspec' + end + + # good + group :development do + gem 'rubocop' + end + + group :development, :test do + gem 'rspec' + end + + # good + gem 'rubocop', groups: [:development, :test] + gem 'rspec', groups: [:development, :test] diff --git a/config/contents/bundler/gem_filename.md b/config/contents/bundler/gem_filename.md new file mode 100644 index 00000000..f469f9f3 --- /dev/null +++ b/config/contents/bundler/gem_filename.md @@ -0,0 +1,22 @@ +Verifies that a project contains Gemfile or gems.rb file and correct +associated lock file based on the configuration. + +### Example: EnforcedStyle: Gemfile (default) + # bad + Project contains gems.rb and gems.locked files + + # bad + Project contains Gemfile and gems.locked file + + # good + Project contains Gemfile and Gemfile.lock + +### Example: EnforcedStyle: gems.rb + # bad + Project contains Gemfile and Gemfile.lock files + + # bad + Project contains gems.rb and Gemfile.lock file + + # good + Project contains gems.rb and gems.locked files \ No newline at end of file diff --git a/config/contents/bundler/insecure_protocol_source.md b/config/contents/bundler/insecure_protocol_source.md index 2218ee3c..1f624812 100644 --- a/config/contents/bundler/insecure_protocol_source.md +++ b/config/contents/bundler/insecure_protocol_source.md @@ -1,15 +1,18 @@ -The symbol argument `:gemcutter`, `:rubygems`, and `:rubyforge` -are deprecated. So please change your source to URL string that -'https://rubygems.org' if possible, or 'http://rubygems.org' if not. +Passing symbol arguments to `source` (e.g. `source :rubygems`) is +deprecated because they default to using HTTP requests. Instead, specify +`'https://rubygems.org'` if possible, or `'http://rubygems.org'` if not. -This autocorrect will replace these symbols with 'https://rubygems.org'. -Because it is secure, HTTPS request is strongly recommended. And in -most use cases HTTPS will be fine. +When autocorrecting, this cop will replace symbol arguments with +`'https://rubygems.org'`. -However, it don't replace all `sources` of `http://` with `https://`. -For example, when specifying an internal gem server using HTTP on the -intranet, a use case where HTTPS cannot be specified was considered. -Consider using HTTP only if you cannot use HTTPS. +This cop will not replace existing sources that use `http://`. This may +be necessary where HTTPS is not available. For example, where using an +internal gem server via an intranet, or where HTTPS is prohibited. +However, you should strongly prefer `https://` where possible, as it is +more secure. + +If you don't allow `http://`, please set `false` to `AllowHttpProtocol`. +This option is `true` by default for safe autocorrection. ### Example: # bad @@ -19,4 +22,13 @@ Consider using HTTP only if you cannot use HTTPS. # good source 'https://rubygems.org' # strongly recommended - source 'http://rubygems.org' \ No newline at end of file + +### Example: AllowHttpProtocol: true (default) + + # good + source 'http://rubygems.org' # use only if HTTPS is unavailable + +### Example: AllowHttpProtocol: false + + # bad + source 'http://rubygems.org' diff --git a/config/contents/bundler/ordered_gems.md b/config/contents/bundler/ordered_gems.md index 84d8f9a2..3540c390 100644 --- a/config/contents/bundler/ordered_gems.md +++ b/config/contents/bundler/ordered_gems.md @@ -14,7 +14,15 @@ Gems should be alphabetically sorted within groups. gem 'rspec' - # good only if TreatCommentsAsGroupSeparators is true +### Example: TreatCommentsAsGroupSeparators: true (default) + # good + # For code quality + gem 'rubocop' + # For tests + gem 'rspec' + +### Example: TreatCommentsAsGroupSeparators: false + # bad # For code quality gem 'rubocop' # For tests diff --git a/config/contents/gemspec/date_assignment.md b/config/contents/gemspec/date_assignment.md deleted file mode 100644 index d58bfd09..00000000 --- a/config/contents/gemspec/date_assignment.md +++ /dev/null @@ -1,15 +0,0 @@ -This cop checks that `date =` is not used in gemspec file. -It is set automatically when the gem is packaged. - -### Example: - - # bad - Gem::Specification.new do |spec| - s.name = 'your_cool_gem_name' - spec.date = Time.now.strftime('%Y-%m-%d') - end - - # good - Gem::Specification.new do |spec| - s.name = 'your_cool_gem_name' - end diff --git a/config/contents/gemspec/dependency_version.md b/config/contents/gemspec/dependency_version.md new file mode 100644 index 00000000..17093704 --- /dev/null +++ b/config/contents/gemspec/dependency_version.md @@ -0,0 +1,46 @@ +Enforce that gem dependency version specifications or a commit reference (branch, +ref, or tag) are either required or forbidden. + +### Example: EnforcedStyle: required (default) + + # bad + Gem::Specification.new do |spec| + spec.add_dependency 'parser' + end + + # bad + Gem::Specification.new do |spec| + spec.add_development_dependency 'parser' + end + + # good + Gem::Specification.new do |spec| + spec.add_dependency 'parser', '>= 2.3.3.1', '< 3.0' + end + + # good + Gem::Specification.new do |spec| + spec.add_development_dependency 'parser', '>= 2.3.3.1', '< 3.0' + end + +### Example: EnforcedStyle: forbidden + + # bad + Gem::Specification.new do |spec| + spec.add_dependency 'parser', '>= 2.3.3.1', '< 3.0' + end + + # bad + Gem::Specification.new do |spec| + spec.add_development_dependency 'parser', '>= 2.3.3.1', '< 3.0' + end + + # good + Gem::Specification.new do |spec| + spec.add_dependency 'parser' + end + + # good + Gem::Specification.new do |spec| + spec.add_development_dependency 'parser' + end diff --git a/config/contents/gemspec/deprecated_attribute_assignment.md b/config/contents/gemspec/deprecated_attribute_assignment.md new file mode 100644 index 00000000..468094d1 --- /dev/null +++ b/config/contents/gemspec/deprecated_attribute_assignment.md @@ -0,0 +1,21 @@ +Checks that deprecated attributes are not set in a gemspec file. +Removing deprecated attributes allows the user to receive smaller packed gems. + +### Example: + + # bad + Gem::Specification.new do |spec| + spec.name = 'your_cool_gem_name' + spec.test_files = Dir.glob('test/**/*') + end + + # bad + Gem::Specification.new do |spec| + spec.name = 'your_cool_gem_name' + spec.test_files += Dir.glob('test/**/*') + end + + # good + Gem::Specification.new do |spec| + spec.name = 'your_cool_gem_name' + end diff --git a/config/contents/gemspec/development_dependencies.md b/config/contents/gemspec/development_dependencies.md new file mode 100644 index 00000000..bf35a94d --- /dev/null +++ b/config/contents/gemspec/development_dependencies.md @@ -0,0 +1,63 @@ +Enforce that development dependencies for a gem are specified in +`Gemfile`, rather than in the `gemspec` using +`add_development_dependency`. Alternatively, using `EnforcedStyle: +gemspec`, enforce that all dependencies are specified in `gemspec`, +rather than in `Gemfile`. + +### Example: EnforcedStyle: Gemfile (default) + # Specify runtime dependencies in your gemspec, + # but all other dependencies in your Gemfile. + + # bad + # example.gemspec + s.add_development_dependency "foo" + + # good + # Gemfile + gem "foo" + + # good + # gems.rb + gem "foo" + + # good (with AllowedGems: ["bar"]) + # example.gemspec + s.add_development_dependency "bar" + +### Example: EnforcedStyle: gems.rb + # Specify runtime dependencies in your gemspec, + # but all other dependencies in your Gemfile. + # + # Identical to `EnforcedStyle: Gemfile`, but with a different error message. + # Rely on Bundler/GemFilename to enforce the use of `Gemfile` vs `gems.rb`. + + # bad + # example.gemspec + s.add_development_dependency "foo" + + # good + # Gemfile + gem "foo" + + # good + # gems.rb + gem "foo" + + # good (with AllowedGems: ["bar"]) + # example.gemspec + s.add_development_dependency "bar" + +### Example: EnforcedStyle: gemspec + # Specify all dependencies in your gemspec. + + # bad + # Gemfile + gem "foo" + + # good + # example.gemspec + s.add_development_dependency "foo" + + # good (with AllowedGems: ["bar"]) + # Gemfile + gem "bar" diff --git a/config/contents/gemspec/ordered_dependencies.md b/config/contents/gemspec/ordered_dependencies.md index 92e0c6f8..b57b76b9 100644 --- a/config/contents/gemspec/ordered_dependencies.md +++ b/config/contents/gemspec/ordered_dependencies.md @@ -40,7 +40,15 @@ Dependencies in the gemspec should be alphabetically sorted. spec.add_runtime_dependency 'rspec' - # good only if TreatCommentsAsGroupSeparators is true +### Example: TreatCommentsAsGroupSeparators: true (default) + # good + # For code quality + spec.add_dependency 'rubocop' + # For tests + spec.add_dependency 'rspec' + +### Example: TreatCommentsAsGroupSeparators: false + # bad # For code quality spec.add_dependency 'rubocop' # For tests diff --git a/config/contents/gemspec/require_mfa.md b/config/contents/gemspec/require_mfa.md new file mode 100644 index 00000000..6bc14388 --- /dev/null +++ b/config/contents/gemspec/require_mfa.md @@ -0,0 +1,56 @@ +Requires a gemspec to have `rubygems_mfa_required` metadata set. + +This setting tells RubyGems that MFA (Multi-Factor Authentication) is +required for accounts to be able perform privileged operations, such as +(see RubyGems' documentation for the full list of privileged +operations): + +* `gem push` +* `gem yank` +* `gem owner --add/remove` +* adding or removing owners using gem ownership page + +This helps make your gem more secure, as users can be more +confident that gem updates were pushed by maintainers. + +### Example: + # bad + Gem::Specification.new do |spec| + # no `rubygems_mfa_required` metadata specified + end + + # good + Gem::Specification.new do |spec| + spec.metadata = { + 'rubygems_mfa_required' => 'true' + } + end + + # good + Gem::Specification.new do |spec| + spec.metadata['rubygems_mfa_required'] = 'true' + end + + # bad + Gem::Specification.new do |spec| + spec.metadata = { + 'rubygems_mfa_required' => 'false' + } + end + + # good + Gem::Specification.new do |spec| + spec.metadata = { + 'rubygems_mfa_required' => 'true' + } + end + + # bad + Gem::Specification.new do |spec| + spec.metadata['rubygems_mfa_required'] = 'false' + end + + # good + Gem::Specification.new do |spec| + spec.metadata['rubygems_mfa_required'] = 'true' + end diff --git a/config/contents/gemspec/required_ruby_version.md b/config/contents/gemspec/required_ruby_version.md index d8941d27..6d25eba2 100644 --- a/config/contents/gemspec/required_ruby_version.md +++ b/config/contents/gemspec/required_ruby_version.md @@ -1,7 +1,8 @@ -Checks that `required_ruby_version` of gemspec is specified and -equal to `TargetRubyVersion` of .rubocop.yml. -Thereby, RuboCop to perform static analysis working on the version -required by gemspec. +Checks that `required_ruby_version` in a gemspec file is set to a valid +value (non-blank) and matches `TargetRubyVersion` as set in RuboCop's +configuration for the gem. + +This ensures that RuboCop is using the same Ruby version as the gem. ### Example: # When `TargetRubyVersion` of .rubocop.yml is `2.5`. @@ -21,6 +22,11 @@ required by gemspec. spec.required_ruby_version = '>= 2.6.0' end + # bad + Gem::Specification.new do |spec| + spec.required_ruby_version = '' + end + # good Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.5.0' @@ -37,7 +43,7 @@ required by gemspec. end # accepted but not recommended, since - # Ruby does not really follow semantic versionning + # Ruby does not really follow semantic versioning Gem::Specification.new do |spec| spec.required_ruby_version = '~> 2.5' end \ No newline at end of file diff --git a/config/contents/gemspec/ruby_version_globals_usage.md b/config/contents/gemspec/ruby_version_globals_usage.md index f570beb9..953f14f8 100644 --- a/config/contents/gemspec/ruby_version_globals_usage.md +++ b/config/contents/gemspec/ruby_version_globals_usage.md @@ -8,7 +8,7 @@ to execute `rake release` and not user's ruby version. # bad Gem::Specification.new do |spec| - if RUBY_VERSION >= '2.5' + if RUBY_VERSION >= '3.0' spec.add_runtime_dependency 'gem_a' else spec.add_runtime_dependency 'gem_b' diff --git a/config/contents/layout/assignment_indentation.md b/config/contents/layout/assignment_indentation.md index 0b5d5d42..dfe6f902 100644 --- a/config/contents/layout/assignment_indentation.md +++ b/config/contents/layout/assignment_indentation.md @@ -1,4 +1,4 @@ -This cop checks the indentation of the first line of the +Checks the indentation of the first line of the right-hand-side of a multi-line assignment. ### Example: diff --git a/config/contents/layout/begin_end_alignment.md b/config/contents/layout/begin_end_alignment.md index 75989b42..34076142 100644 --- a/config/contents/layout/begin_end_alignment.md +++ b/config/contents/layout/begin_end_alignment.md @@ -1,4 +1,4 @@ -This cop checks whether the end keyword of `begin` is aligned properly. +Checks whether the end keyword of `begin` is aligned properly. Two modes are supported through the `EnforcedStyleAlignWith` configuration parameter. If it's set to `start_of_line` (which is the default), the diff --git a/config/contents/layout/block_alignment.md b/config/contents/layout/block_alignment.md index e87adc1b..bc7e04f8 100644 --- a/config/contents/layout/block_alignment.md +++ b/config/contents/layout/block_alignment.md @@ -1,4 +1,4 @@ -This cop checks whether the end keywords are aligned properly for do +Checks whether the end keywords are aligned properly for do end blocks. Three modes are supported through the `EnforcedStyleAlignWith` @@ -17,23 +17,24 @@ location. The autofixer will default to `start_of_line`. # bad foo.bar - .each do - baz - end + .each do + baz + end # good - variable = lambda do |i| - i + foo.bar + .each do + baz end ### Example: EnforcedStyleAlignWith: start_of_block # bad foo.bar - .each do - baz - end + .each do + baz + end # good @@ -46,13 +47,13 @@ location. The autofixer will default to `start_of_line`. # bad foo.bar - .each do - baz - end + .each do + baz + end # good foo.bar .each do - baz - end \ No newline at end of file + baz + end diff --git a/config/contents/layout/block_end_newline.md b/config/contents/layout/block_end_newline.md index ef2285ca..8c0bb0b2 100644 --- a/config/contents/layout/block_end_newline.md +++ b/config/contents/layout/block_end_newline.md @@ -1,4 +1,4 @@ -This cop checks whether the end statement of a do..end block +Checks whether the end statement of a do..end block is on its own line. ### Example: diff --git a/config/contents/layout/case_indentation.md b/config/contents/layout/case_indentation.md index b2d7550b..f2e486fa 100644 --- a/config/contents/layout/case_indentation.md +++ b/config/contents/layout/case_indentation.md @@ -1,4 +1,4 @@ -This cop checks how the `when` and `in`s of a `case` expression +Checks how the `when` and ``in``s of a `case` expression are indented in relation to its `case` or `end` keyword. It will register a separate offense for each misaligned `when` and `in`. diff --git a/config/contents/layout/class_structure.md b/config/contents/layout/class_structure.md index 10773803..cffa19c7 100644 --- a/config/contents/layout/class_structure.md +++ b/config/contents/layout/class_structure.md @@ -63,6 +63,13 @@ automatically. - extend ---- +@safety + Autocorrection is unsafe because class methods and module inclusion + can behave differently, based on which methods or constants have + already been defined. + + Constants will only be moved when they are assigned with literals. + ### Example: # bad # Expect extend be before constant @@ -126,5 +133,3 @@ automatically. def some_private_method end end - -@see https://rubystyle.guide#consistent-classes \ No newline at end of file diff --git a/config/contents/layout/closing_heredoc_indentation.md b/config/contents/layout/closing_heredoc_indentation.md index 6a78ff4d..1ccd210e 100644 --- a/config/contents/layout/closing_heredoc_indentation.md +++ b/config/contents/layout/closing_heredoc_indentation.md @@ -1,4 +1,3 @@ - Checks the indentation of here document closings. ### Example: diff --git a/config/contents/layout/closing_parenthesis_indentation.md b/config/contents/layout/closing_parenthesis_indentation.md index ac4fbef4..9db7c2b5 100644 --- a/config/contents/layout/closing_parenthesis_indentation.md +++ b/config/contents/layout/closing_parenthesis_indentation.md @@ -1,4 +1,4 @@ -This cop checks the indentation of hanging closing parentheses in +Checks the indentation of hanging closing parentheses in method calls, method definitions, and grouped expressions. A hanging closing parenthesis means `)` preceded by a line break. diff --git a/config/contents/layout/comment_indentation.md b/config/contents/layout/comment_indentation.md index 3d2c7c1c..1dc39ecf 100644 --- a/config/contents/layout/comment_indentation.md +++ b/config/contents/layout/comment_indentation.md @@ -1,4 +1,4 @@ -This cop checks the indentation of comments. +Checks the indentation of comments. ### Example: # bad @@ -26,3 +26,17 @@ This cop checks the indentation of comments. if true true end + +### Example: AllowForAlignment: false (default) + # bad + a = 1 # A really long comment + # spanning two lines. + + # good + # A really long comment spanning one line. + a = 1 + +### Example: AllowForAlignment: true + # good + a = 1 # A really long comment + # spanning two lines. \ No newline at end of file diff --git a/config/contents/layout/condition_position.md b/config/contents/layout/condition_position.md index 5f4557fd..fd49e4b7 100644 --- a/config/contents/layout/condition_position.md +++ b/config/contents/layout/condition_position.md @@ -1,4 +1,4 @@ -This cop checks for conditions that are not on the same line as +Checks for conditions that are not on the same line as if/while/until. ### Example: diff --git a/config/contents/layout/def_end_alignment.md b/config/contents/layout/def_end_alignment.md index 05d6a6bc..ff00446b 100644 --- a/config/contents/layout/def_end_alignment.md +++ b/config/contents/layout/def_end_alignment.md @@ -1,4 +1,4 @@ -This cop checks whether the end keywords of method definitions are +Checks whether the end keywords of method definitions are aligned properly. Two modes are supported through the EnforcedStyleAlignWith configuration diff --git a/config/contents/layout/dot_position.md b/config/contents/layout/dot_position.md index 4f25b42f..b6f50cc7 100644 --- a/config/contents/layout/dot_position.md +++ b/config/contents/layout/dot_position.md @@ -1,4 +1,4 @@ -This cop checks the . position in multi-line method calls. +Checks the . position in multi-line method calls. ### Example: EnforcedStyle: leading (default) # bad diff --git a/config/contents/layout/else_alignment.md b/config/contents/layout/else_alignment.md index ea5c1996..be3cf89e 100644 --- a/config/contents/layout/else_alignment.md +++ b/config/contents/layout/else_alignment.md @@ -1,4 +1,4 @@ -This cop checks the alignment of else keywords. Normally they should +Checks the alignment of else keywords. Normally they should be aligned with an if/unless/while/until/begin/def/rescue keyword, but there are special cases when they should follow the same rules as the alignment of end. diff --git a/config/contents/layout/empty_comment.md b/config/contents/layout/empty_comment.md index 5c89b7b3..574cd64e 100644 --- a/config/contents/layout/empty_comment.md +++ b/config/contents/layout/empty_comment.md @@ -1,4 +1,4 @@ -This cop checks empty comment. +Checks empty comment. ### Example: # bad diff --git a/config/contents/layout/empty_line_after_guard_clause.md b/config/contents/layout/empty_line_after_guard_clause.md index cb271393..26c1491f 100644 --- a/config/contents/layout/empty_line_after_guard_clause.md +++ b/config/contents/layout/empty_line_after_guard_clause.md @@ -1,4 +1,20 @@ -This cop enforces empty line after guard clause +Enforces empty line after guard clause. + +This cop allows `# :nocov:` directive after guard clause because +SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`: + +[source,ruby] +---- +def foo + # :nocov: + return if condition + # :nocov: + bar +end +---- + +Refer to SimpleCov's documentation for more details: +https://github.com/simplecov-ruby/simplecov#ignoringskipping-code ### Example: diff --git a/config/contents/layout/empty_line_after_multiline_condition.md b/config/contents/layout/empty_line_after_multiline_condition.md index 7539b861..9f9b0c0d 100644 --- a/config/contents/layout/empty_line_after_multiline_condition.md +++ b/config/contents/layout/empty_line_after_multiline_condition.md @@ -1,4 +1,4 @@ -This cop enforces empty line after multiline condition. +Enforces empty line after multiline condition. ### Example: # bad diff --git a/config/contents/layout/empty_line_between_defs.md b/config/contents/layout/empty_line_between_defs.md index 100f67b8..6b88bd43 100644 --- a/config/contents/layout/empty_line_between_defs.md +++ b/config/contents/layout/empty_line_between_defs.md @@ -1,4 +1,4 @@ -This cop checks whether class/module/method definitions are +Checks whether class/module/method definitions are separated by one or more empty lines. `NumberOfEmptyLines` can be an integer (default is 1) or @@ -72,9 +72,30 @@ one-line definitions are considered an offense. def b end -### Example: AllowAdjacentOneLineDefs: true +### Example: AllowAdjacentOneLineDefs: true (default) # good class ErrorA < BaseError; end class ErrorB < BaseError; end class ErrorC < BaseError; end + + # good + class ErrorA < BaseError; end + + class ErrorB < BaseError; end + + class ErrorC < BaseError; end + +### Example: AllowAdjacentOneLineDefs: false + + # bad + class ErrorA < BaseError; end + class ErrorB < BaseError; end + class ErrorC < BaseError; end + + # good + class ErrorA < BaseError; end + + class ErrorB < BaseError; end + + class ErrorC < BaseError; end diff --git a/config/contents/layout/empty_lines.md b/config/contents/layout/empty_lines.md index 268015d8..a48d269c 100644 --- a/config/contents/layout/empty_lines.md +++ b/config/contents/layout/empty_lines.md @@ -1,4 +1,4 @@ -This cop checks for two or more consecutive blank lines. +Checks for two or more consecutive blank lines. ### Example: diff --git a/config/contents/layout/empty_lines_around_arguments.md b/config/contents/layout/empty_lines_around_arguments.md index 8ebdbcc4..a1167a75 100644 --- a/config/contents/layout/empty_lines_around_arguments.md +++ b/config/contents/layout/empty_lines_around_arguments.md @@ -1,4 +1,4 @@ -This cop checks if empty lines exist around the arguments +Checks if empty lines exist around the arguments of a method invocation. ### Example: diff --git a/config/contents/layout/empty_lines_around_begin_body.md b/config/contents/layout/empty_lines_around_begin_body.md index 31f8736b..3998bc19 100644 --- a/config/contents/layout/empty_lines_around_begin_body.md +++ b/config/contents/layout/empty_lines_around_begin_body.md @@ -1,4 +1,4 @@ -This cop checks if empty lines exist around the bodies of begin-end +Checks if empty lines exist around the bodies of begin-end blocks. ### Example: diff --git a/config/contents/layout/empty_lines_around_block_body.md b/config/contents/layout/empty_lines_around_block_body.md index 79120428..892c8b9d 100644 --- a/config/contents/layout/empty_lines_around_block_body.md +++ b/config/contents/layout/empty_lines_around_block_body.md @@ -1,18 +1,18 @@ -This cop checks if empty lines around the bodies of blocks match +Checks if empty lines around the bodies of blocks match the configuration. -### Example: EnforcedStyle: empty_lines +### Example: EnforcedStyle: no_empty_lines (default) # good foo do |bar| - # ... - end -### Example: EnforcedStyle: no_empty_lines (default) +### Example: EnforcedStyle: empty_lines # good foo do |bar| + # ... + end \ No newline at end of file diff --git a/config/contents/layout/empty_lines_around_class_body.md b/config/contents/layout/empty_lines_around_class_body.md index a0253690..8b64d771 100644 --- a/config/contents/layout/empty_lines_around_class_body.md +++ b/config/contents/layout/empty_lines_around_class_body.md @@ -1,6 +1,15 @@ -This cop checks if empty lines around the bodies of classes match +Checks if empty lines around the bodies of classes match the configuration. +### Example: EnforcedStyle: no_empty_lines (default) + # good + + class Foo + def bar + # ... + end + end + ### Example: EnforcedStyle: empty_lines # good @@ -49,13 +58,4 @@ the configuration. # ... end - end - -### Example: EnforcedStyle: no_empty_lines (default) - # good - - class Foo - def bar - # ... - end end \ No newline at end of file diff --git a/config/contents/layout/empty_lines_around_exception_handling_keywords.md b/config/contents/layout/empty_lines_around_exception_handling_keywords.md index 9933b3ba..097b2f00 100644 --- a/config/contents/layout/empty_lines_around_exception_handling_keywords.md +++ b/config/contents/layout/empty_lines_around_exception_handling_keywords.md @@ -1,4 +1,4 @@ -This cop checks if empty lines exist around the bodies of `begin` +Checks if empty lines exist around the bodies of `begin` sections. This cop doesn't check empty lines at `begin` body beginning/end and around method definition body. `Style/EmptyLinesAroundBeginBody` or `Style/EmptyLinesAroundMethodBody` diff --git a/config/contents/layout/empty_lines_around_method_body.md b/config/contents/layout/empty_lines_around_method_body.md index a096fd35..6dbcf033 100644 --- a/config/contents/layout/empty_lines_around_method_body.md +++ b/config/contents/layout/empty_lines_around_method_body.md @@ -1,4 +1,4 @@ -This cop checks if empty lines exist around the bodies of methods. +Checks if empty lines exist around the bodies of methods. ### Example: diff --git a/config/contents/layout/empty_lines_around_module_body.md b/config/contents/layout/empty_lines_around_module_body.md index 9da03d84..de6682ef 100644 --- a/config/contents/layout/empty_lines_around_module_body.md +++ b/config/contents/layout/empty_lines_around_module_body.md @@ -1,6 +1,15 @@ -This cop checks if empty lines around the bodies of modules match +Checks if empty lines around the bodies of modules match the configuration. +### Example: EnforcedStyle: no_empty_lines (default) + # good + + module Foo + def bar + # ... + end + end + ### Example: EnforcedStyle: empty_lines # good @@ -29,13 +38,4 @@ the configuration. def bar; end - end - -### Example: EnforcedStyle: no_empty_lines (default) - # good - - module Foo - def bar - # ... - end end \ No newline at end of file diff --git a/config/contents/layout/end_alignment.md b/config/contents/layout/end_alignment.md index 65d2cbfd..0d5ee48e 100644 --- a/config/contents/layout/end_alignment.md +++ b/config/contents/layout/end_alignment.md @@ -1,4 +1,4 @@ -This cop checks whether the end keywords are aligned properly. +Checks whether the end keywords are aligned properly. Three modes are supported through the `EnforcedStyleAlignWith` configuration parameter: @@ -15,7 +15,9 @@ start of the line where the matching keyword appears. This `Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`) by default. On the other hand, `Layout/BeginEndAlignment` cop aligns with `EnforcedStyleAlignWith: start_of_line` by default due to `||= begin` tends -to align with the start of the line. These style can be configured by each cop. +to align with the start of the line. `Layout/DefEndAlignment` cop also aligns with +`EnforcedStyleAlignWith: start_of_line` by default. +These style can be configured by each cop. ### Example: EnforcedStyleAlignWith: keyword (default) # bad diff --git a/config/contents/layout/end_of_line.md b/config/contents/layout/end_of_line.md index eb966a5e..8a6f4070 100644 --- a/config/contents/layout/end_of_line.md +++ b/config/contents/layout/end_of_line.md @@ -1,4 +1,4 @@ -This cop checks for Windows-style line endings in the source code. +Checks for Windows-style line endings in the source code. ### Example: EnforcedStyle: native (default) # The `native` style means that CR+LF (Carriage Return + Line Feed) is @@ -17,17 +17,17 @@ This cop checks for Windows-style line endings in the source code. # all platforms. # bad - puts 'Hello' # Return character is CR+LF on all platfoms. + puts 'Hello' # Return character is CR+LF on all platforms. # good - puts 'Hello' # Return character is LF on all platfoms. + puts 'Hello' # Return character is LF on all platforms. ### Example: EnforcedStyle: crlf # The `crlf` style means that CR+LF (Carriage Return + Line Feed) is # enforced on all platforms. # bad - puts 'Hello' # Return character is LF on all platfoms. + puts 'Hello' # Return character is LF on all platforms. # good - puts 'Hello' # Return character is CR+LF on all platfoms. + puts 'Hello' # Return character is CR+LF on all platforms. diff --git a/config/contents/layout/extra_spacing.md b/config/contents/layout/extra_spacing.md index bcb0f188..00aafc25 100644 --- a/config/contents/layout/extra_spacing.md +++ b/config/contents/layout/extra_spacing.md @@ -1,4 +1,4 @@ -This cop checks for extra/unnecessary whitespace. +Checks for extra/unnecessary whitespace. ### Example: diff --git a/config/contents/layout/first_argument_indentation.md b/config/contents/layout/first_argument_indentation.md index 19fd4bc2..4164f922 100644 --- a/config/contents/layout/first_argument_indentation.md +++ b/config/contents/layout/first_argument_indentation.md @@ -1,4 +1,4 @@ -This cop checks the indentation of the first argument in a method call. +Checks the indentation of the first argument in a method call. Arguments after the first one are checked by `Layout/ArgumentAlignment`, not by this cop. @@ -32,9 +32,10 @@ This cop will respect `Layout/ArgumentAlignment` and will not work when nested_first_param), second_param -### Example: EnforcedStyle: consistent - # The first argument should always be indented one step more than the - # preceding line. +### Example: EnforcedStyle: special_for_inner_method_call_in_parentheses (default) + # Same as `special_for_inner_method_call` except that the special rule + # only applies if the outer method call encloses its arguments in + # parentheses. # good some_method( @@ -46,7 +47,7 @@ This cop will respect `Layout/ArgumentAlignment` and will not work when second_param) foo = some_method(nested_call( - nested_first_param), + nested_first_param), second_param) foo = some_method( @@ -58,9 +59,9 @@ This cop will respect `Layout/ArgumentAlignment` and will not work when nested_first_param), second_param -### Example: EnforcedStyle: consistent_relative_to_receiver - # The first argument should always be indented one level relative to - # the parent that is receiving the argument +### Example: EnforcedStyle: consistent + # The first argument should always be indented one step more than the + # preceding line. # good some_method( @@ -68,27 +69,25 @@ This cop will respect `Layout/ArgumentAlignment` and will not work when second_param) foo = some_method( - first_param, + first_param, second_param) foo = some_method(nested_call( - nested_first_param), + nested_first_param), second_param) foo = some_method( - nested_call( - nested_first_param), + nested_call( + nested_first_param), second_param) some_method nested_call( - nested_first_param), - second_params + nested_first_param), + second_param -### Example: EnforcedStyle: special_for_inner_method_call - # The first argument should normally be indented one step more than - # the preceding line, but if it's a argument for a method call that - # is itself a argument in a method call, then the inner argument - # should be indented relative to the inner method. +### Example: EnforcedStyle: consistent_relative_to_receiver + # The first argument should always be indented one level relative to + # the parent that is receiving the argument # good some_method( @@ -96,7 +95,7 @@ This cop will respect `Layout/ArgumentAlignment` and will not work when second_param) foo = some_method( - first_param, + first_param, second_param) foo = some_method(nested_call( @@ -104,18 +103,19 @@ This cop will respect `Layout/ArgumentAlignment` and will not work when second_param) foo = some_method( - nested_call( - nested_first_param), + nested_call( + nested_first_param), second_param) some_method nested_call( nested_first_param), - second_param + second_params -### Example: EnforcedStyle: special_for_inner_method_call_in_parentheses (default) - # Same as `special_for_inner_method_call` except that the special rule - # only applies if the outer method call encloses its arguments in - # parentheses. +### Example: EnforcedStyle: special_for_inner_method_call + # The first argument should normally be indented one step more than + # the preceding line, but if it's a argument for a method call that + # is itself a argument in a method call, then the inner argument + # should be indented relative to the inner method. # good some_method( @@ -136,5 +136,5 @@ This cop will respect `Layout/ArgumentAlignment` and will not work when second_param) some_method nested_call( - nested_first_param), + nested_first_param), second_param diff --git a/config/contents/layout/first_array_element_indentation.md b/config/contents/layout/first_array_element_indentation.md index 8d729c29..0e031b98 100644 --- a/config/contents/layout/first_array_element_indentation.md +++ b/config/contents/layout/first_array_element_indentation.md @@ -1,6 +1,9 @@ -This cop checks the indentation of the first element in an array literal +Checks the indentation of the first element in an array literal where the opening bracket and the first element are on separate lines. -The other elements' indentations are handled by the ArrayAlignment cop. +The other elements' indentations are handled by `Layout/ArrayAlignment` cop. + +This cop will respect `Layout/ArrayAlignment` and will not work when +`EnforcedStyle: with_fixed_indentation` is specified for `Layout/ArrayAlignment`. By default, array literals that are arguments in a method call with parentheses, and where the opening square bracket of the array is on the @@ -20,7 +23,7 @@ styles are 'consistent' and 'align_brackets'. Here are examples: # element are on separate lines is indented one step (two spaces) more # than the position inside the opening parenthesis. - #bad + # bad array = [ :value ] @@ -28,7 +31,7 @@ styles are 'consistent' and 'align_brackets'. Here are examples: :no_difference ]) - #good + # good array = [ :value ] @@ -42,7 +45,7 @@ styles are 'consistent' and 'align_brackets'. Here are examples: # separate lines is indented the same as an array literal which is not # defined inside a method call. - #bad + # bad # consistent array = [ :value @@ -51,7 +54,7 @@ styles are 'consistent' and 'align_brackets'. Here are examples: :its_like_this ]) - #good + # good array = [ :value ] @@ -63,13 +66,13 @@ styles are 'consistent' and 'align_brackets'. Here are examples: # The `align_brackets` style enforces that the opening and closing # brackets are indented to the same position. - #bad + # bad # align_brackets and_now_for_something = [ :completely_different ] - #good + # good # align_brackets and_now_for_something = [ :completely_different diff --git a/config/contents/layout/first_array_element_line_break.md b/config/contents/layout/first_array_element_line_break.md index 93e82898..638283f5 100644 --- a/config/contents/layout/first_array_element_line_break.md +++ b/config/contents/layout/first_array_element_line_break.md @@ -1,13 +1,36 @@ -This cop checks for a line break before the first element in a +Checks for a line break before the first element in a multi-line array. ### Example: - # bad - [ :a, - :b] + # bad + [ :a, + :b] - # good - [ - :a, - :b] + # good + [ + :a, + :b] + + # good + [:a, :b] + +### Example: AllowMultilineFinalElement: false (default) + + # bad + [ :a, { + :b => :c + }] + + # good + [ + :a, { + :b => :c + }] + +### Example: AllowMultilineFinalElement: true + + # good + [:a, { + :b => :c + }] diff --git a/config/contents/layout/first_hash_element_indentation.md b/config/contents/layout/first_hash_element_indentation.md index c47b386b..907572d8 100644 --- a/config/contents/layout/first_hash_element_indentation.md +++ b/config/contents/layout/first_hash_element_indentation.md @@ -1,4 +1,4 @@ -This cop checks the indentation of the first key in a hash literal +Checks the indentation of the first key in a hash literal where the opening brace and the first key are on separate lines. The other keys' indentations are handled by the HashAlignment cop. @@ -27,6 +27,14 @@ styles are 'consistent' and 'align_braces'. Here are examples: and_in_a_method_call({ no: :difference }) + takes_multi_pairs_hash(x: { + a: 1, + b: 2 + }, + y: { + c: 1, + d: 2 + }) # good special_inside_parentheses @@ -36,6 +44,14 @@ styles are 'consistent' and 'align_braces'. Here are examples: but_in_a_method_call({ its_like: :this }) + takes_multi_pairs_hash(x: { + a: 1, + b: 2 + }, + y: { + c: 1, + d: 2 + }) ### Example: EnforcedStyle: consistent # The `consistent` style enforces that the first key in a hash @@ -59,6 +75,7 @@ styles are 'consistent' and 'align_braces'. Here are examples: no: :difference }) + ### Example: EnforcedStyle: align_braces # The `align_brackets` style enforces that the opening and closing # braces are indented to the same position. @@ -67,8 +84,24 @@ styles are 'consistent' and 'align_braces'. Here are examples: and_now_for_something = { completely: :different } + takes_multi_pairs_hash(x: { + a: 1, + b: 2 + }, + y: { + c: 1, + d: 2 + }) # good and_now_for_something = { completely: :different - } \ No newline at end of file + } + takes_multi_pairs_hash(x: { + a: 1, + b: 2 + }, + y: { + c: 1, + d: 2 + }) \ No newline at end of file diff --git a/config/contents/layout/first_hash_element_line_break.md b/config/contents/layout/first_hash_element_line_break.md index fa3fa2d4..baea2461 100644 --- a/config/contents/layout/first_hash_element_line_break.md +++ b/config/contents/layout/first_hash_element_line_break.md @@ -1,4 +1,4 @@ -This cop checks for a line break before the first element in a +Checks for a line break before the first element in a multi-line hash. ### Example: @@ -10,4 +10,30 @@ multi-line hash. # good { a: 1, - b: 2 } \ No newline at end of file + b: 2 } + + # good + { + a: 1, b: { + c: 3 + }} + +### Example: AllowMultilineFinalElement: false (default) + + # bad + { a: 1, b: { + c: 3 + }} + +### Example: AllowMultilineFinalElement: true + + # bad + { a: 1, + b: { + c: 3 + }} + + # good + { a: 1, b: { + c: 3 + }} diff --git a/config/contents/layout/first_method_argument_line_break.md b/config/contents/layout/first_method_argument_line_break.md index e79ede51..62a1936b 100644 --- a/config/contents/layout/first_method_argument_line_break.md +++ b/config/contents/layout/first_method_argument_line_break.md @@ -1,17 +1,59 @@ -This cop checks for a line break before the first argument in a +Checks for a line break before the first argument in a multi-line method call. ### Example: - # bad - method(foo, bar, - baz) + # bad + method(foo, bar, + baz) - # good - method( - foo, bar, - baz) + # good + method( + foo, bar, + baz) # ignored method foo, bar, - baz \ No newline at end of file + baz + +### Example: AllowMultilineFinalElement: false (default) + + # bad + method(foo, bar, { + baz: "a", + qux: "b", + }) + + # good + method( + foo, bar, { + baz: "a", + qux: "b", + }) + +### Example: AllowMultilineFinalElement: true + + # bad + method(foo, + bar, + { + baz: "a", + qux: "b", + } + ) + + # good + method(foo, bar, { + baz: "a", + qux: "b", + }) + + # good + method( + foo, + bar, + { + baz: "a", + qux: "b", + } + ) diff --git a/config/contents/layout/first_method_parameter_line_break.md b/config/contents/layout/first_method_parameter_line_break.md index 165623fd..dfa8f6aa 100644 --- a/config/contents/layout/first_method_parameter_line_break.md +++ b/config/contents/layout/first_method_parameter_line_break.md @@ -1,23 +1,49 @@ -This cop checks for a line break before the first parameter in a +Checks for a line break before the first parameter in a multi-line method parameter definition. ### Example: - # bad - def method(foo, bar, - baz) - do_something - end - - # good - def method( - foo, bar, - baz) - do_something - end - - # ignored - def method foo, - bar - do_something - end \ No newline at end of file + # bad + def method(foo, bar, + baz) + do_something + end + + # good + def method( + foo, bar, + baz) + do_something + end + + # ignored + def method foo, + bar + do_something + end + +### Example: AllowMultilineFinalElement: false (default) + + # bad + def method(foo, bar, baz = { + :a => "b", + }) + do_something + end + + # good + def method( + foo, bar, baz = { + :a => "b", + }) + do_something + end + +### Example: AllowMultilineFinalElement: true + + # good + def method(foo, bar, baz = { + :a => "b", + }) + do_something + end diff --git a/config/contents/layout/first_parameter_indentation.md b/config/contents/layout/first_parameter_indentation.md index 1c86def4..2aa518fb 100644 --- a/config/contents/layout/first_parameter_indentation.md +++ b/config/contents/layout/first_parameter_indentation.md @@ -1,4 +1,4 @@ -This cop checks the indentation of the first parameter in a method +Checks the indentation of the first parameter in a method definition. Parameters after the first one are checked by Layout/ParameterAlignment, not by this cop. diff --git a/config/contents/layout/heredoc_argument_closing_parenthesis.md b/config/contents/layout/heredoc_argument_closing_parenthesis.md index 1d03cdb0..2b79c57c 100644 --- a/config/contents/layout/heredoc_argument_closing_parenthesis.md +++ b/config/contents/layout/heredoc_argument_closing_parenthesis.md @@ -1,4 +1,4 @@ -This cop checks for the placement of the closing parenthesis +Checks for the placement of the closing parenthesis in a method call that passes a HEREDOC string as an argument. It should be placed at the end of the line containing the opening HEREDOC tag. diff --git a/config/contents/layout/heredoc_indentation.md b/config/contents/layout/heredoc_indentation.md index 8ba772be..fdb29f2e 100644 --- a/config/contents/layout/heredoc_indentation.md +++ b/config/contents/layout/heredoc_indentation.md @@ -1,9 +1,9 @@ -This cop checks the indentation of the here document bodies. The bodies +Checks the indentation of the here document bodies. The bodies are indented one step. Note: When ``Layout/LineLength``'s `AllowHeredoc` is false (not default), this cop does not add any offenses for long here documents to - avoid `Layout/LineLength`'s offenses. + avoid ``Layout/LineLength``'s offenses. ### Example: # bad diff --git a/config/contents/layout/indentation_consistency.md b/config/contents/layout/indentation_consistency.md index 8a2b98b5..04f213dc 100644 --- a/config/contents/layout/indentation_consistency.md +++ b/config/contents/layout/indentation_consistency.md @@ -1,4 +1,4 @@ -This cop checks for inconsistent indentation. +Checks for inconsistent indentation. The difference between `indented_internal_methods` and `normal` is that the `indented_internal_methods` style prescribes that in diff --git a/config/contents/layout/indentation_style.md b/config/contents/layout/indentation_style.md index 65b63f85..5013838c 100644 --- a/config/contents/layout/indentation_style.md +++ b/config/contents/layout/indentation_style.md @@ -1,4 +1,4 @@ -This cop checks that the indentation method is consistent. +Checks that the indentation method is consistent. Either tabs only or spaces only are used for indentation. ### Example: EnforcedStyle: spaces (default) diff --git a/config/contents/layout/indentation_width.md b/config/contents/layout/indentation_width.md index 0aadfc49..1787a56b 100644 --- a/config/contents/layout/indentation_width.md +++ b/config/contents/layout/indentation_width.md @@ -1,4 +1,4 @@ -This cop checks for indentation that doesn't use the specified number +Checks for indentation that doesn't use the specified number of spaces. See also the IndentationConsistency cop which is the companion to this @@ -19,7 +19,7 @@ one. end end -### Example: IgnoredPatterns: ['^\s*module'] +### Example: AllowedPatterns: ['^\s*module'] # bad module A class B diff --git a/config/contents/layout/initial_indentation.md b/config/contents/layout/initial_indentation.md index d74d08a2..62ca65a5 100644 --- a/config/contents/layout/initial_indentation.md +++ b/config/contents/layout/initial_indentation.md @@ -1,4 +1,4 @@ -This cop checks for indentation of the first non-blank non-comment +Checks for indentation of the first non-blank non-comment line in a file. ### Example: diff --git a/config/contents/layout/leading_comment_space.md b/config/contents/layout/leading_comment_space.md index 850de1f3..f9d9122a 100644 --- a/config/contents/layout/leading_comment_space.md +++ b/config/contents/layout/leading_comment_space.md @@ -1,4 +1,4 @@ -This cop checks whether comments have a leading space after the +Checks whether comments have a leading space after the `#` denoting the start of the comment. The leading space is not required for some RDoc special syntax, like `#++`, `#--`, `#:nodoc`, `=begin`- and `=end` comments, "shebang" directives, diff --git a/config/contents/layout/leading_empty_lines.md b/config/contents/layout/leading_empty_lines.md index 83b90ffc..95d4d6c1 100644 --- a/config/contents/layout/leading_empty_lines.md +++ b/config/contents/layout/leading_empty_lines.md @@ -1,4 +1,4 @@ -This cop checks for unnecessary leading blank lines at the beginning +Checks for unnecessary leading blank lines at the beginning of a file. ### Example: diff --git a/config/contents/layout/line_continuation_leading_space.md b/config/contents/layout/line_continuation_leading_space.md new file mode 100644 index 00000000..46502bec --- /dev/null +++ b/config/contents/layout/line_continuation_leading_space.md @@ -0,0 +1,37 @@ +Checks that strings broken over multiple lines (by a backslash) contain +trailing spaces instead of leading spaces (default) or leading spaces +instead of trailing spaces. + +### Example: EnforcedStyle: trailing (default) + # bad + 'this text contains a lot of' \ + ' spaces' + + # good + 'this text contains a lot of ' \ + 'spaces' + + # bad + 'this text is too' \ + ' long' + + # good + 'this text is too ' \ + 'long' + +### Example: EnforcedStyle: leading + # bad + 'this text contains a lot of ' \ + 'spaces' + + # good + 'this text contains a lot of' \ + ' spaces' + + # bad + 'this text is too ' \ + 'long' + + # good + 'this text is too' \ + ' long' \ No newline at end of file diff --git a/config/contents/layout/line_continuation_spacing.md b/config/contents/layout/line_continuation_spacing.md new file mode 100644 index 00000000..1ef9c293 --- /dev/null +++ b/config/contents/layout/line_continuation_spacing.md @@ -0,0 +1,24 @@ +Checks that the backslash of a line continuation is separated from +preceding text by exactly one space (default) or zero spaces. + +### Example: EnforcedStyle: space (default) + # bad + 'a'\ + 'b' \ + 'c' + + # good + 'a' \ + 'b' \ + 'c' + +### Example: EnforcedStyle: no_space + # bad + 'a' \ + 'b' \ + 'c' + + # good + 'a'\ + 'b'\ + 'c' \ No newline at end of file diff --git a/config/contents/layout/line_end_string_concatenation_indentation.md b/config/contents/layout/line_end_string_concatenation_indentation.md index f1394605..24f19d22 100644 --- a/config/contents/layout/line_end_string_concatenation_indentation.md +++ b/config/contents/layout/line_end_string_concatenation_indentation.md @@ -1,4 +1,4 @@ -This cop checks the indentation of the next line after a line that ends with a string +Checks the indentation of the next line after a line that ends with a string literal and a backslash. If `EnforcedStyle: aligned` is set, the concatenated string parts shall be aligned with the @@ -6,8 +6,7 @@ first part. There are some exceptions, such as implicit return values, where the concatenated string parts shall be indented regardless of `EnforcedStyle` configuration. If `EnforcedStyle: indented` is set, it's the second line that shall be indented one step -more than the first line. Lines 3 and forward shall be aligned with line 2. Here too there -are exceptions. Values in a hash literal are always aligned. +more than the first line. Lines 3 and forward shall be aligned with line 2. ### Example: # bad @@ -29,25 +28,40 @@ are exceptions. Values in a hash literal are always aligned. 'z' end - my_hash = { - first: 'a message' \ - 'in two parts' - } - ### Example: EnforcedStyle: aligned (default) # bad puts 'x' \ 'y' + my_hash = { + first: 'a message' \ + 'in two parts' + } + # good puts 'x' \ 'y' + my_hash = { + first: 'a message' \ + 'in two parts' + } + ### Example: EnforcedStyle: indented # bad result = 'x' \ 'y' + my_hash = { + first: 'a message' \ + 'in two parts' + } + # good result = 'x' \ 'y' + + my_hash = { + first: 'a message' \ + 'in two parts' + } diff --git a/config/contents/layout/line_length.md b/config/contents/layout/line_length.md index 2ffab3a5..e98004ee 100644 --- a/config/contents/layout/line_length.md +++ b/config/contents/layout/line_length.md @@ -1,4 +1,4 @@ -This cop checks the length of lines in the source code. +Checks the length of lines in the source code. The maximum length is configurable. The tab size is configured in the `IndentationWidth` of the `Layout/IndentationStyle` cop. @@ -15,6 +15,7 @@ are recommended to further format the broken lines. (Many of these are enabled by default.) * ArgumentAlignment +* ArrayAlignment * BlockAlignment * BlockDelimiters * BlockEndNewline @@ -30,6 +31,7 @@ are recommended to further format the broken lines. * MultilineHashBraceLayout * MultilineHashKeyLineBreaks * MultilineMethodArgumentLineBreaks +* MultilineMethodParameterLineBreaks * ParameterAlignment Together, these cops will pretty print hashes, arrays, diff --git a/config/contents/layout/multiline_array_brace_layout.md b/config/contents/layout/multiline_array_brace_layout.md index 8c0a1b94..93cbb938 100644 --- a/config/contents/layout/multiline_array_brace_layout.md +++ b/config/contents/layout/multiline_array_brace_layout.md @@ -1,4 +1,4 @@ -This cop checks that the closing brace in an array literal is either +Checks that the closing brace in an array literal is either on the same line as the last array element or on a new line. When using the `symmetrical` (default) style: diff --git a/config/contents/layout/multiline_array_line_breaks.md b/config/contents/layout/multiline_array_line_breaks.md index 4550b7c3..6d4720c4 100644 --- a/config/contents/layout/multiline_array_line_breaks.md +++ b/config/contents/layout/multiline_array_line_breaks.md @@ -1,4 +1,4 @@ -This cop ensures that each item in a multi-line array +Ensures that each item in a multi-line array starts on a separate line. ### Example: @@ -14,4 +14,27 @@ starts on a separate line. a, b, c - ] \ No newline at end of file + ] + + # good + [ + a, + b, + foo( + bar + ) + ] + +### Example: AllowMultilineFinalElement: false (default) + + # bad + [a, b, foo( + bar + )] + +### Example: AllowMultilineFinalElement: true + + # good + [a, b, foo( + bar + )] diff --git a/config/contents/layout/multiline_assignment_layout.md b/config/contents/layout/multiline_assignment_layout.md index 8d15855f..5e1b4004 100644 --- a/config/contents/layout/multiline_assignment_layout.md +++ b/config/contents/layout/multiline_assignment_layout.md @@ -1,4 +1,4 @@ -This cop checks whether the multiline assignments have a newline +Checks whether the multiline assignments have a newline after the assignment operator. ### Example: EnforcedStyle: new_line (default) diff --git a/config/contents/layout/multiline_block_layout.md b/config/contents/layout/multiline_block_layout.md index 77134167..fc207d58 100644 --- a/config/contents/layout/multiline_block_layout.md +++ b/config/contents/layout/multiline_block_layout.md @@ -1,4 +1,4 @@ -This cop checks whether the multiline do end blocks have a newline +Checks whether the multiline do end blocks have a newline after the start of the block. Additionally, it checks whether the block arguments, if any, are on the same line as the start of the block. Putting block arguments on separate lines, because the whole diff --git a/config/contents/layout/multiline_hash_brace_layout.md b/config/contents/layout/multiline_hash_brace_layout.md index eb8d1868..2947b3f4 100644 --- a/config/contents/layout/multiline_hash_brace_layout.md +++ b/config/contents/layout/multiline_hash_brace_layout.md @@ -1,4 +1,4 @@ -This cop checks that the closing brace in a hash literal is either +Checks that the closing brace in a hash literal is either on the same line as the last hash element, or a new line. When using the `symmetrical` (default) style: diff --git a/config/contents/layout/multiline_hash_key_line_breaks.md b/config/contents/layout/multiline_hash_key_line_breaks.md index 9da05489..c52e2e9a 100644 --- a/config/contents/layout/multiline_hash_key_line_breaks.md +++ b/config/contents/layout/multiline_hash_key_line_breaks.md @@ -1,4 +1,4 @@ -This cop ensures that each key in a multi-line hash +Ensures that each key in a multi-line hash starts on a separate line. ### Example: @@ -14,4 +14,26 @@ starts on a separate line. a: 1, b: 2, c: 3 - } \ No newline at end of file + } + + # good + { + a: 1, + b: { + c: 3, + } + } + +### Example: AllowMultilineFinalElement: false (default) + + # bad + { a: 1, b: { + c: 3, + }} + +### Example: AllowMultilineFinalElement: true + + # good + { a: 1, b: { + c: 3, + }} diff --git a/config/contents/layout/multiline_method_argument_line_breaks.md b/config/contents/layout/multiline_method_argument_line_breaks.md index b80dbb68..914c1fac 100644 --- a/config/contents/layout/multiline_method_argument_line_breaks.md +++ b/config/contents/layout/multiline_method_argument_line_breaks.md @@ -1,6 +1,9 @@ -This cop ensures that each argument in a multi-line method call +Ensures that each argument in a multi-line method call starts on a separate line. +NOTE: This cop does not move the first argument, if you want that to +be on a separate line, see `Layout/FirstMethodArgumentLineBreak`. + ### Example: # bad @@ -8,9 +11,39 @@ starts on a separate line. c ) + # bad + foo(a, b, { + foo: "bar", + }) + # good foo( a, b, c - ) \ No newline at end of file + ) + + # good + foo(a, b, c) + +### Example: AllowMultilineFinalElement: false (default) + + # good + foo( + a, + b, + { + foo: "bar", + } + ) + +### Example: AllowMultilineFinalElement: true + + # good + foo( + a, + b, + { + foo: "bar", + } + ) diff --git a/config/contents/layout/multiline_method_call_brace_layout.md b/config/contents/layout/multiline_method_call_brace_layout.md index 9f695398..57a611ab 100644 --- a/config/contents/layout/multiline_method_call_brace_layout.md +++ b/config/contents/layout/multiline_method_call_brace_layout.md @@ -1,4 +1,4 @@ -This cop checks that the closing brace in a method call is either +Checks that the closing brace in a method call is either on the same line as the last method argument, or a new line. When using the `symmetrical` (default) style: diff --git a/config/contents/layout/multiline_method_call_indentation.md b/config/contents/layout/multiline_method_call_indentation.md index cde63232..4c650aec 100644 --- a/config/contents/layout/multiline_method_call_indentation.md +++ b/config/contents/layout/multiline_method_call_indentation.md @@ -1,4 +1,4 @@ -This cop checks the indentation of the method name part in method calls +Checks the indentation of the method name part in method calls that span more than one line. ### Example: EnforcedStyle: aligned (default) diff --git a/config/contents/layout/multiline_method_definition_brace_layout.md b/config/contents/layout/multiline_method_definition_brace_layout.md index 3572739c..3e1dde6f 100644 --- a/config/contents/layout/multiline_method_definition_brace_layout.md +++ b/config/contents/layout/multiline_method_definition_brace_layout.md @@ -1,4 +1,4 @@ -This cop checks that the closing brace in a method definition is either +Checks that the closing brace in a method definition is either on the same line as the last method parameter, or a new line. When using the `symmetrical` (default) style: diff --git a/config/contents/layout/multiline_method_parameter_line_breaks.md b/config/contents/layout/multiline_method_parameter_line_breaks.md new file mode 100644 index 00000000..e67defa6 --- /dev/null +++ b/config/contents/layout/multiline_method_parameter_line_breaks.md @@ -0,0 +1,50 @@ +Ensures that each parameter in a multi-line method definition +starts on a separate line. + +NOTE: This cop does not move the first argument, if you want that to +be on a separate line, see `Layout/FirstMethodParameterLineBreak`. + +### Example: + + # bad + def foo(a, b, + c + ) + end + + # good + def foo( + a, + b, + c + ) + end + + # good + def foo( + a, + b = { + foo: "bar", + } + ) + end + + # good + def foo(a, b, c) + end + +### Example: AllowMultilineFinalElement: false (default) + + # bad + def foo(a, b = { + foo: "bar", + }) + end + +### Example: AllowMultilineFinalElement: true + + # good + def foo(a, b = { + foo: "bar", + }) + end diff --git a/config/contents/layout/multiline_operation_indentation.md b/config/contents/layout/multiline_operation_indentation.md index 54fbe17d..51e3b263 100644 --- a/config/contents/layout/multiline_operation_indentation.md +++ b/config/contents/layout/multiline_operation_indentation.md @@ -1,24 +1,23 @@ -This cop checks the indentation of the right hand side operand in -binary operations that span more than one line. +Checks the indentation of the right hand side operand in binary operations that +span more than one line. -The `aligned` style checks that operators are aligned if they are part -of an `if` or `while` condition, a `return` statement, etc. In other -contexts, the second operand should be indented regardless of enforced -style. +The `aligned` style checks that operators are aligned if they are part of an `if` or `while` +condition, an explicit `return` statement, etc. In other contexts, the second operand should +be indented regardless of enforced style. ### Example: EnforcedStyle: aligned (default) # bad if a + b something && - something_else + something_else end # good if a + b something && - something_else + something_else end ### Example: EnforcedStyle: indented diff --git a/config/contents/layout/redundant_line_break.md b/config/contents/layout/redundant_line_break.md index 87f7cd86..4cb540fa 100644 --- a/config/contents/layout/redundant_line_break.md +++ b/config/contents/layout/redundant_line_break.md @@ -1,4 +1,4 @@ -This cop checks whether certain expressions, e.g. method calls, that could fit +Checks whether certain expressions, e.g. method calls, that could fit completely on a single line, are broken up into multiple lines unnecessarily. ### Example: any configuration diff --git a/config/contents/layout/rescue_ensure_alignment.md b/config/contents/layout/rescue_ensure_alignment.md index 8f4b72e7..922d15a1 100644 --- a/config/contents/layout/rescue_ensure_alignment.md +++ b/config/contents/layout/rescue_ensure_alignment.md @@ -1,4 +1,4 @@ -This cop checks whether the rescue and ensure keywords are aligned +Checks whether the rescue and ensure keywords are aligned properly. ### Example: diff --git a/config/contents/layout/single_line_block_chain.md b/config/contents/layout/single_line_block_chain.md index efc475d0..da5db924 100644 --- a/config/contents/layout/single_line_block_chain.md +++ b/config/contents/layout/single_line_block_chain.md @@ -1,4 +1,4 @@ -This cop checks if method calls are chained onto single line blocks. It considers that a +Checks if method calls are chained onto single line blocks. It considers that a line break before the dot improves the readability of the code. ### Example: diff --git a/config/contents/layout/space_after_not.md b/config/contents/layout/space_after_not.md index 384d3b6e..8a34a8cf 100644 --- a/config/contents/layout/space_after_not.md +++ b/config/contents/layout/space_after_not.md @@ -1,4 +1,4 @@ -This cop checks for space after `!`. +Checks for space after `!`. ### Example: # bad diff --git a/config/contents/layout/space_around_method_call_operator.md b/config/contents/layout/space_around_method_call_operator.md index 37ef0ce6..b29cda5d 100644 --- a/config/contents/layout/space_around_method_call_operator.md +++ b/config/contents/layout/space_around_method_call_operator.md @@ -14,7 +14,7 @@ Checks method call operators to not have spaces around them. foo &. bar foo &. bar&. buzz RuboCop:: Cop - RuboCop:: Cop:: Cop + RuboCop:: Cop:: Base :: RuboCop::Cop # good @@ -26,5 +26,5 @@ Checks method call operators to not have spaces around them. foo&.bar foo&.bar&.buzz RuboCop::Cop - RuboCop::Cop::Cop + RuboCop::Cop::Base ::RuboCop::Cop diff --git a/config/contents/layout/space_around_operators.md b/config/contents/layout/space_around_operators.md index dea89ac5..092c9bd1 100644 --- a/config/contents/layout/space_around_operators.md +++ b/config/contents/layout/space_around_operators.md @@ -44,4 +44,18 @@ the previous or next line, not counting empty lines or comment lines. a**b # good - a ** b \ No newline at end of file + a ** b + +### Example: EnforcedStyleForRationalLiterals: no_space (default) + # bad + 1 / 48r + + # good + 1/48r + +### Example: EnforcedStyleForRationalLiterals: space + # bad + 1/48r + + # good + 1 / 48r \ No newline at end of file diff --git a/config/contents/layout/space_before_comment.md b/config/contents/layout/space_before_comment.md index 0729dfcd..ea66c5d7 100644 --- a/config/contents/layout/space_before_comment.md +++ b/config/contents/layout/space_before_comment.md @@ -1,4 +1,4 @@ -This cop checks for missing space between a token and a comment on the +Checks for missing space between a token and a comment on the same line. ### Example: diff --git a/config/contents/layout/space_in_lambda_literal.md b/config/contents/layout/space_in_lambda_literal.md index d420fac4..d964cb47 100644 --- a/config/contents/layout/space_in_lambda_literal.md +++ b/config/contents/layout/space_in_lambda_literal.md @@ -1,4 +1,4 @@ -This cop checks for spaces between `->` and opening parameter +Checks for spaces between `->` and opening parameter parenthesis (`(`) in lambda literals. ### Example: EnforcedStyle: require_no_space (default) diff --git a/config/contents/layout/space_inside_array_literal_brackets.md b/config/contents/layout/space_inside_array_literal_brackets.md index 618ed7fd..0f3225e2 100644 --- a/config/contents/layout/space_inside_array_literal_brackets.md +++ b/config/contents/layout/space_inside_array_literal_brackets.md @@ -1,16 +1,6 @@ Checks that brackets used for array literals have or don't have surrounding space depending on configuration. -### Example: EnforcedStyle: space - # The `space` style enforces that array literals have - # surrounding space. - - # bad - array = [a, b, c, d] - - # good - array = [ a, b, c, d ] - ### Example: EnforcedStyle: no_space (default) # The `no_space` style enforces that array literals have # no surrounding space. @@ -21,6 +11,16 @@ surrounding space depending on configuration. # good array = [a, b, c, d] +### Example: EnforcedStyle: space + # The `space` style enforces that array literals have + # surrounding space. + + # bad + array = [a, b, c, d] + + # good + array = [ a, b, c, d ] + ### Example: EnforcedStyle: compact # The `compact` style normally requires a space inside # array brackets, with the exception that successive left diff --git a/config/contents/layout/space_inside_array_percent_literal.md b/config/contents/layout/space_inside_array_percent_literal.md index aa8256c2..36d851e5 100644 --- a/config/contents/layout/space_inside_array_percent_literal.md +++ b/config/contents/layout/space_inside_array_percent_literal.md @@ -1,6 +1,9 @@ Checks for unnecessary additional spaces inside array percent literals (i.e. %i/%w). +Note that blank percent literals (e.g. `%i( )`) are checked by +`Layout/SpaceInsidePercentLiteralDelimiters`. + ### Example: # bad diff --git a/config/contents/layout/space_inside_hash_literal_braces.md b/config/contents/layout/space_inside_hash_literal_braces.md index d9e48b24..af63a47a 100644 --- a/config/contents/layout/space_inside_hash_literal_braces.md +++ b/config/contents/layout/space_inside_hash_literal_braces.md @@ -41,10 +41,13 @@ surrounding space depending on configuration. # bad foo = { } bar = { } + baz = { + } # good foo = {} bar = {} + baz = {} ### Example: EnforcedStyleForEmptyBraces: space # The `space` EnforcedStyleForEmptyBraces style enforces that @@ -55,5 +58,6 @@ surrounding space depending on configuration. # good foo = { } - foo = { } - foo = { } + foo = { } + foo = { + } diff --git a/config/contents/layout/space_inside_parens.md b/config/contents/layout/space_inside_parens.md index e6f96af2..19ff22e6 100644 --- a/config/contents/layout/space_inside_parens.md +++ b/config/contents/layout/space_inside_parens.md @@ -27,3 +27,24 @@ Checks for spaces inside ordinary round parentheses. f( 3 ) g = ( a + 3 ) y() + +### Example: EnforcedStyle: compact + # The `compact` style enforces that parentheses have a space at the + # beginning with the exception that successive parentheses are allowed. + # Note: Empty parentheses should not have spaces. + + # bad + f(3) + g = (a + 3) + y( ) + g( f( x ) ) + g( f( x( 3 ) ), 5 ) + g( ( ( 3 + 5 ) * f) ** x, 5 ) + + # good + f( 3 ) + g = ( a + 3 ) + y() + g( f( x )) + g( f( x( 3 )), 5 ) + g((( 3 + 5 ) * f ) ** x, 5 ) diff --git a/config/contents/layout/space_inside_percent_literal_delimiters.md b/config/contents/layout/space_inside_percent_literal_delimiters.md index 54bf6fd8..b4c9e83c 100644 --- a/config/contents/layout/space_inside_percent_literal_delimiters.md +++ b/config/contents/layout/space_inside_percent_literal_delimiters.md @@ -3,11 +3,28 @@ Checks for unnecessary additional spaces inside the delimiters of ### Example: + # bad + %i( foo bar baz ) + # good %i(foo bar baz) # bad %w( foo bar baz ) + # good + %w(foo bar baz) + + # bad + %x( ls -l ) + + # good + %x(ls -l) + # bad - %x( ls -l ) \ No newline at end of file + %w( ) + %w( + ) + + # good + %w() \ No newline at end of file diff --git a/config/contents/layout/space_inside_reference_brackets.md b/config/contents/layout/space_inside_reference_brackets.md index 8ee084ed..6e8e03df 100644 --- a/config/contents/layout/space_inside_reference_brackets.md +++ b/config/contents/layout/space_inside_reference_brackets.md @@ -33,6 +33,8 @@ surrounding space depending on configuration. # bad foo[ ] foo[ ] + foo[ + ] # good foo[] @@ -44,6 +46,8 @@ surrounding space depending on configuration. # bad foo[] foo[ ] + foo[ + ] # good foo[ ] diff --git a/config/contents/layout/space_inside_string_interpolation.md b/config/contents/layout/space_inside_string_interpolation.md index 5def53fe..98ae831c 100644 --- a/config/contents/layout/space_inside_string_interpolation.md +++ b/config/contents/layout/space_inside_string_interpolation.md @@ -1,4 +1,4 @@ -This cop checks for whitespace within string interpolations. +Checks for whitespace within string interpolations. ### Example: EnforcedStyle: no_space (default) # bad diff --git a/config/contents/layout/trailing_empty_lines.md b/config/contents/layout/trailing_empty_lines.md index 913590a2..55e1124f 100644 --- a/config/contents/layout/trailing_empty_lines.md +++ b/config/contents/layout/trailing_empty_lines.md @@ -1,12 +1,12 @@ -This cop looks for trailing blank lines and a final newline in the +Looks for trailing blank lines and a final newline in the source code. -### Example: EnforcedStyle: final_blank_line - # `final_blank_line` looks for one blank line followed by a new line - # at the end of files. +### Example: EnforcedStyle: final_newline (default) + # `final_newline` looks for one newline at the end of files. # bad class Foo; end + # EOF # bad @@ -14,15 +14,14 @@ source code. # good class Foo; end - # EOF -### Example: EnforcedStyle: final_newline (default) - # `final_newline` looks for one newline at the end of files. +### Example: EnforcedStyle: final_blank_line + # `final_blank_line` looks for one blank line followed by a new line + # at the end of files. # bad class Foo; end - # EOF # bad @@ -30,4 +29,5 @@ source code. # good class Foo; end + # EOF diff --git a/config/contents/layout/trailing_whitespace.md b/config/contents/layout/trailing_whitespace.md index f815bb2b..482d676b 100644 --- a/config/contents/layout/trailing_whitespace.md +++ b/config/contents/layout/trailing_whitespace.md @@ -1,4 +1,4 @@ -This cop looks for trailing whitespace in the source code. +Looks for trailing whitespace in the source code. ### Example: # The line in this example contains spaces after the 0. diff --git a/config/contents/lint/ambiguous_assignment.md b/config/contents/lint/ambiguous_assignment.md index f57b029e..a79abaab 100644 --- a/config/contents/lint/ambiguous_assignment.md +++ b/config/contents/lint/ambiguous_assignment.md @@ -1,4 +1,4 @@ -This cop checks for mistyped shorthand assignments. +Checks for mistyped shorthand assignments. ### Example: # bad diff --git a/config/contents/lint/ambiguous_block_association.md b/config/contents/lint/ambiguous_block_association.md index 37a392c9..f7baee73 100644 --- a/config/contents/lint/ambiguous_block_association.md +++ b/config/contents/lint/ambiguous_block_association.md @@ -1,7 +1,8 @@ -This cop checks for ambiguous block association with method +Checks for ambiguous block association with method when param passed without parentheses. -This cop can customize ignored methods with `IgnoredMethods`. +This cop can customize allowed methods with `AllowedMethods`. +By default, there are no methods to allowed. ### Example: @@ -24,7 +25,23 @@ This cop can customize ignored methods with `IgnoredMethods`. # Lambda arguments require no disambiguation foo = ->(bar) { bar.baz } -### Example: IgnoredMethods: [change] +### Example: AllowedMethods: [] (default) + + # bad + expect { do_something }.to change { object.attribute } + +### Example: AllowedMethods: [change] + + # good + expect { do_something }.to change { object.attribute } + +### Example: AllowedPatterns: [] (default) + + # bad + expect { do_something }.to change { object.attribute } + +### Example: AllowedPatterns: ['change'] # good - expect { do_something }.to change { object.attribute } \ No newline at end of file + expect { do_something }.to change { object.attribute } + expect { do_something }.to not_change { object.attribute } diff --git a/config/contents/lint/ambiguous_operator.md b/config/contents/lint/ambiguous_operator.md index 733a4a97..99b3b9e5 100644 --- a/config/contents/lint/ambiguous_operator.md +++ b/config/contents/lint/ambiguous_operator.md @@ -1,4 +1,4 @@ -This cop checks for ambiguous operators in the first argument of a +Checks for ambiguous operators in the first argument of a method invocation without parentheses. ### Example: diff --git a/config/contents/lint/ambiguous_operator_precedence.md b/config/contents/lint/ambiguous_operator_precedence.md new file mode 100644 index 00000000..b202fcb9 --- /dev/null +++ b/config/contents/lint/ambiguous_operator_precedence.md @@ -0,0 +1,24 @@ +Looks for expressions containing multiple binary operators +where precedence is ambiguous due to lack of parentheses. For example, +in `1 + 2 * 3`, the multiplication will happen before the addition, but +lexically it appears that the addition will happen first. + +The cop does not consider unary operators (ie. `!a` or `-b`) or comparison +operators (ie. `a =~ b`) because those are not ambiguous. + +NOTE: Ranges are handled by `Lint/AmbiguousRange`. + +### Example: + # bad + a + b * c + a || b && c + a ** b + c + + # good (different precedence) + a + (b * c) + a || (b && c) + (a ** b) + c + + # good (same precedence) + a + b + c + a * b / c % d \ No newline at end of file diff --git a/config/contents/lint/ambiguous_range.md b/config/contents/lint/ambiguous_range.md new file mode 100644 index 00000000..2f050c00 --- /dev/null +++ b/config/contents/lint/ambiguous_range.md @@ -0,0 +1,53 @@ +Checks for ambiguous ranges. + +Ranges have quite low precedence, which leads to unexpected behavior when +using a range with other operators. This cop avoids that by making ranges +explicit by requiring parenthesis around complex range boundaries (anything +that is not a literal: numerics, strings, symbols, etc.). + +This cop can be configured with `RequireParenthesesForMethodChains` in order to +specify whether method chains (including `self.foo`) should be wrapped in parens +by this cop. + +NOTE: Regardless of this configuration, if a method receiver is a basic literal +value, it will be wrapped in order to prevent the ambiguity of `1..2.to_a`. + +@safety + The cop autocorrects by wrapping the entire boundary in parentheses, which + makes the outcome more explicit but is possible to not be the intention of the + programmer. For this reason, this cop's autocorrect is unsafe (it will not + change the behavior of the code, but will not necessarily match the + intent of the program). + +### Example: + # bad + x || 1..2 + (x || 1..2) + 1..2.to_a + + # good, unambiguous + 1..2 + 'a'..'z' + :bar..:baz + MyClass::MIN..MyClass::MAX + @min..@max + a..b + -a..b + + # good, ambiguity removed + x || (1..2) + (x || 1)..2 + (x || 1)..(y || 2) + (1..2).to_a + +### Example: RequireParenthesesForMethodChains: false (default) + # good + a.foo..b.bar + (a.foo)..(b.bar) + +### Example: RequireParenthesesForMethodChains: true + # bad + a.foo..b.bar + + # good + (a.foo)..(b.bar) \ No newline at end of file diff --git a/config/contents/lint/ambiguous_regexp_literal.md b/config/contents/lint/ambiguous_regexp_literal.md index 2c5b232f..7ad32663 100644 --- a/config/contents/lint/ambiguous_regexp_literal.md +++ b/config/contents/lint/ambiguous_regexp_literal.md @@ -1,4 +1,4 @@ -This cop checks for ambiguous regexp literals in the first argument of +Checks for ambiguous regexp literals in the first argument of a method invocation without parentheses. ### Example: diff --git a/config/contents/lint/assignment_in_condition.md b/config/contents/lint/assignment_in_condition.md index b652212c..c8a9dee1 100644 --- a/config/contents/lint/assignment_in_condition.md +++ b/config/contents/lint/assignment_in_condition.md @@ -1,4 +1,4 @@ -This cop checks for assignments in the conditions of +Checks for assignments in the conditions of if/while/until. `AllowSafeAssignment` option for safe assignment. @@ -6,25 +6,29 @@ By safe assignment we mean putting parentheses around an assignment to indicate "I know I'm using an assignment as a condition. It's not a mistake." +@safety + This cop's autocorrection is unsafe because it assumes that + the author meant to use an assignment result as a condition. + ### Example: # bad - if some_var = true + if some_var = value do_something end # good - if some_var == true + if some_var == value do_something end ### Example: AllowSafeAssignment: true (default) # good - if (some_var = true) + if (some_var = value) do_something end ### Example: AllowSafeAssignment: false # bad - if (some_var = true) + if (some_var = value) do_something end diff --git a/config/contents/lint/binary_operator_with_identical_operands.md b/config/contents/lint/binary_operator_with_identical_operands.md index cc871f7f..b50627ae 100644 --- a/config/contents/lint/binary_operator_with_identical_operands.md +++ b/config/contents/lint/binary_operator_with_identical_operands.md @@ -1,14 +1,27 @@ -This cop checks for places where binary operator has identical operands. +Checks for places where binary operator has identical operands. -It covers arithmetic operators: `+`, `-`, `*`, `/`, `%`, `**`; -comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, `<=`; -bitwise operators: `|`, `^`, `&`, `<<`, `>>`; +It covers arithmetic operators: `-`, `/`, `%`; +comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, ``<=``; +bitwise operators: `|`, `^`, `&`; boolean operators: `&&`, `||` -and "spaceship" operator - `<=>`. +and "spaceship" operator - ``<=>``. -This cop is marked as unsafe as it does not consider side effects when calling methods -and thus can generate false positives: +Simple arithmetic operations are allowed by this cop: `+`, `*`, `**`, `<<` and `>>`. +Although these can be rewritten in a different way, it should not be necessary to +do so. This does not include operations such as `-` or `/` where the result will +always be the same (`x - x` will always be 0; `x / x` will always be 1), and +thus are legitimate offenses. + +@safety + This cop is unsafe as it does not consider side effects when calling methods + and thus can generate false positives, for example: + + [source,ruby] + ---- if wr.take_char == '\0' && wr.take_char == '\0' + # ... + end + ---- ### Example: # bad @@ -19,7 +32,7 @@ and thus can generate false positives: do_something end - def childs? + def child? left_child || left_child end diff --git a/config/contents/lint/boolean_symbol.md b/config/contents/lint/boolean_symbol.md index bb4fe218..a93e75ac 100644 --- a/config/contents/lint/boolean_symbol.md +++ b/config/contents/lint/boolean_symbol.md @@ -1,6 +1,11 @@ -This cop checks for `:true` and `:false` symbols. +Checks for `:true` and `:false` symbols. In most cases it would be a typo. +@safety + Autocorrection is unsafe for this cop because code relying + on `:true` or `:false` symbols will break when those are + changed to actual booleans. + ### Example: # bad diff --git a/config/contents/lint/circular_argument_reference.md b/config/contents/lint/circular_argument_reference.md index 628c4239..f8a70312 100644 --- a/config/contents/lint/circular_argument_reference.md +++ b/config/contents/lint/circular_argument_reference.md @@ -1,4 +1,4 @@ -This cop checks for circular argument references in optional keyword +Checks for circular argument references in optional keyword arguments and optional ordinal arguments. This cop mirrors a warning produced by MRI since 2.2. diff --git a/config/contents/lint/constant_overwritten_in_rescue.md b/config/contents/lint/constant_overwritten_in_rescue.md new file mode 100644 index 00000000..20b241bf --- /dev/null +++ b/config/contents/lint/constant_overwritten_in_rescue.md @@ -0,0 +1,19 @@ +Checks for overwriting an exception with an exception result by use ``rescue =>``. + +You intended to write as `rescue StandardError`. +However, you have written `rescue => StandardError`. +In that case, the result of `rescue` will overwrite `StandardError`. + +### Example: + + # bad + begin + something + rescue => StandardError + end + + # good + begin + something + rescue StandardError + end diff --git a/config/contents/lint/constant_resolution.md b/config/contents/lint/constant_resolution.md index efa3b31e..0499c4ed 100644 --- a/config/contents/lint/constant_resolution.md +++ b/config/contents/lint/constant_resolution.md @@ -11,6 +11,10 @@ are problematic because of a conflict with a library or just internally using the same name a namespace and a class. To avoid too many unnecessary offenses, Enable this cop with `Only: [The, Constant, Names, Causing, Issues]` +NOTE: `Style/RedundantConstantBase` cop is disabled if this cop is enabled to prevent +conflicting rules. Because it respects user configurations that want to enable +this cop which is disabled by default. + ### Example: # By default checks every constant diff --git a/config/contents/lint/debugger.md b/config/contents/lint/debugger.md index dad1bd13..49e16284 100644 --- a/config/contents/lint/debugger.md +++ b/config/contents/lint/debugger.md @@ -1,18 +1,33 @@ -This cop checks for debug calls (such as `debugger` or `binding.pry`) that should +Checks for debug calls (such as `debugger` or `binding.pry`) that should not be kept for production code. The cop can be configured using `DebuggerMethods`. By default, a number of gems -debug entrypoints are configured (`Kernel`, `Byebug`, `Capybara`, `Pry`, `Rails`, -and `WebConsole`). Additional methods can be added. +debug entrypoints are configured (`Kernel`, `Byebug`, `Capybara`, `debug.rb`, +`Pry`, `Rails`, `RubyJard`, and `WebConsole`). Additional methods can be added. Specific default groups can be disabled if necessary: [source,yaml] ---- Lint/Debugger: - WebConsole: ~ + DebuggerMethods: + WebConsole: ~ ---- +You can also add your own methods by adding a new category: + +[source,yaml] +---- +Lint/Debugger: + DebuggerMethods: + MyDebugger: + MyDebugger.debug_this +---- + +Some gems also ship files that will start a debugging session when required, +for example `require 'debug/start'` from `ruby/debug`. These requires can +be configured through `DebuggerRequires`. It has the same structure as +`DebuggerMethods`, which you can read about above. ### Example: @@ -48,4 +63,10 @@ Lint/Debugger: def some_method my_debugger - end \ No newline at end of file + end + +### Example: DebuggerRequires: [my_debugger/start] + + # bad (ok during development) + + require 'my_debugger/start' \ No newline at end of file diff --git a/config/contents/lint/deprecated_class_methods.md b/config/contents/lint/deprecated_class_methods.md index 5d57fb9c..20c6a027 100644 --- a/config/contents/lint/deprecated_class_methods.md +++ b/config/contents/lint/deprecated_class_methods.md @@ -1,21 +1,27 @@ -This cop checks for uses of the deprecated class method usages. +Checks for uses of the deprecated class method usages. ### Example: # bad - File.exists?(some_path) Dir.exists?(some_path) iterator? + attr :name, true + attr :name, false + ENV.freeze # Calling `Env.freeze` raises `TypeError` since Ruby 2.7. + ENV.clone + ENV.dup # Calling `Env.dup` raises `TypeError` since Ruby 3.1. Socket.gethostbyname(host) Socket.gethostbyaddr(host) -### Example: - # good - File.exist?(some_path) Dir.exist?(some_path) block_given? + attr_accessor :name + attr_reader :name + ENV # `ENV.freeze` cannot prohibit changes to environment variables. + ENV.to_h + ENV.to_h # `ENV.dup` cannot dup `ENV`, use `ENV.to_h` to get a copy of `ENV` as a hash. Addrinfo.getaddrinfo(nodename, service) Addrinfo.tcp(host, port).getnameinfo \ No newline at end of file diff --git a/config/contents/lint/deprecated_constants.md b/config/contents/lint/deprecated_constants.md index 2b389fc5..ad4afa87 100644 --- a/config/contents/lint/deprecated_constants.md +++ b/config/contents/lint/deprecated_constants.md @@ -1,4 +1,4 @@ -This cop checks for deprecated constants. +Checks for deprecated constants. It has `DeprecatedConstants` config. If there is an alternative method, you can set alternative value as `Alternative`. And you can set the deprecated version as @@ -9,7 +9,8 @@ alternative value as `Alternative`. And you can set the deprecated version as Alternative: 'alternative_value' DeprecatedVersion: 'deprecated_version' -By default, `NIL`, `TRUE`, `FALSE` and `Random::DEFAULT` are configured. +By default, `NIL`, `TRUE`, `FALSE`, `Net::HTTPServerException, `Random::DEFAULT`, +`Struct::Group`, and `Struct::Passwd` are configured. ### Example: @@ -17,10 +18,16 @@ By default, `NIL`, `TRUE`, `FALSE` and `Random::DEFAULT` are configured. NIL TRUE FALSE + Net::HTTPServerException Random::DEFAULT # Return value of Ruby 2 is `Random` instance, Ruby 3.0 is `Random` class. + Struct::Group + Struct::Passwd # good nil true false + Net::HTTPClientException Random.new # `::DEFAULT` has been deprecated in Ruby 3, `.new` is compatible with Ruby 2. + Etc::Group + Etc::Passwd diff --git a/config/contents/lint/disjunctive_assignment_in_constructor.md b/config/contents/lint/disjunctive_assignment_in_constructor.md index bc75f9a5..648977f7 100644 --- a/config/contents/lint/disjunctive_assignment_in_constructor.md +++ b/config/contents/lint/disjunctive_assignment_in_constructor.md @@ -1,4 +1,4 @@ -This cop checks constructors for disjunctive assignments that should +Checks constructors for disjunctive assignments (`||=`) that should be plain assignments. So far, this cop is only concerned with disjunctive assignment of @@ -7,6 +7,29 @@ instance variables. In ruby, an instance variable is nil until a value is assigned, so the disjunction is unnecessary. A plain assignment has the same effect. +@safety + This cop is unsafe because it can register a false positive when a + method is redefined in a subclass that calls super. For example: + + [source,ruby] + ---- + class Base + def initialize + @config ||= 'base' + end + end + + class Derived < Base + def initialize + @config = 'derived' + super + end + end + ---- + + Without the disjunctive assignment, `Derived` will be unable to override + the value for `@config`. + ### Example: # bad def initialize diff --git a/config/contents/lint/duplicate_branch.md b/config/contents/lint/duplicate_branch.md index c9f491fd..710c53d1 100644 --- a/config/contents/lint/duplicate_branch.md +++ b/config/contents/lint/duplicate_branch.md @@ -1,5 +1,5 @@ -This cop checks that there are no repeated bodies -within `if/unless`, `case-when` and `rescue` constructs. +Checks that there are no repeated bodies +within `if/unless`, `case-when`, `case-in` and `rescue` constructs. With `IgnoreLiteralBranches: true`, branches are not registered as offenses if they return a basic literal value (string, symbol, diff --git a/config/contents/lint/duplicate_case_condition.md b/config/contents/lint/duplicate_case_condition.md index 691ee2fe..c636f1af 100644 --- a/config/contents/lint/duplicate_case_condition.md +++ b/config/contents/lint/duplicate_case_condition.md @@ -1,4 +1,4 @@ -This cop checks that there are no repeated conditions +Checks that there are no repeated conditions used in case 'when' expressions. ### Example: diff --git a/config/contents/lint/duplicate_elsif_condition.md b/config/contents/lint/duplicate_elsif_condition.md index 7f9f68b3..bf9e4ef3 100644 --- a/config/contents/lint/duplicate_elsif_condition.md +++ b/config/contents/lint/duplicate_elsif_condition.md @@ -1,4 +1,4 @@ -This cop checks that there are no repeated conditions used in if 'elsif'. +Checks that there are no repeated conditions used in if 'elsif'. ### Example: # bad diff --git a/config/contents/lint/duplicate_hash_key.md b/config/contents/lint/duplicate_hash_key.md index 6bab0890..520de6d7 100644 --- a/config/contents/lint/duplicate_hash_key.md +++ b/config/contents/lint/duplicate_hash_key.md @@ -1,4 +1,5 @@ -This cop checks for duplicated keys in hash literals. +Checks for duplicated keys in hash literals. +This cop considers both primitive types and constants for the hash keys. This cop mirrors a warning in Ruby 2.2. diff --git a/config/contents/lint/duplicate_magic_comment.md b/config/contents/lint/duplicate_magic_comment.md new file mode 100644 index 00000000..b6122cca --- /dev/null +++ b/config/contents/lint/duplicate_magic_comment.md @@ -0,0 +1,21 @@ +Checks for duplicated magic comments. + +### Example: + + # bad + + # encoding: ascii + # encoding: ascii + + # good + + # encoding: ascii + + # bad + + # frozen_string_literal: true + # frozen_string_literal: true + + # good + + # frozen_string_literal: true diff --git a/config/contents/lint/duplicate_match_pattern.md b/config/contents/lint/duplicate_match_pattern.md new file mode 100644 index 00000000..981fd6af --- /dev/null +++ b/config/contents/lint/duplicate_match_pattern.md @@ -0,0 +1,83 @@ +Checks that there are no repeated patterns used in `in` keywords. + +### Example: + + # bad + case x + in 'first' + do_something + in 'first' + do_something_else + end + + # good + case x + in 'first' + do_something + in 'second' + do_something_else + end + + # bad - repeated alternate patterns with the same conditions don't depend on the order + case x + in foo | bar + first_method + in bar | foo + second_method + end + + # good + case x + in foo | bar + first_method + in bar | baz + second_method + end + + # bad - repeated hash patterns with the same conditions don't depend on the order + case x + in foo: a, bar: b + first_method + in bar: b, foo: a + second_method + end + + # good + case x + in foo: a, bar: b + first_method + in bar: b, baz: c + second_method + end + + # bad - repeated array patterns with elements in the same order + case x + in [foo, bar] + first_method + in [foo, bar] + second_method + end + + # good + case x + in [foo, bar] + first_method + in [bar, foo] + second_method + end + + # bad - repeated the same patterns and guard conditions + case x + in foo if bar + first_method + in foo if bar + second_method + end + + # good + case x + in foo if bar + first_method + in foo if baz + second_method + end diff --git a/config/contents/lint/duplicate_methods.md b/config/contents/lint/duplicate_methods.md index ae8c942f..ddff9c78 100644 --- a/config/contents/lint/duplicate_methods.md +++ b/config/contents/lint/duplicate_methods.md @@ -1,4 +1,4 @@ -This cop checks for duplicated instance (or singleton) method +Checks for duplicated instance (or singleton) method definitions. ### Example: diff --git a/config/contents/lint/duplicate_regexp_character_class_element.md b/config/contents/lint/duplicate_regexp_character_class_element.md index f20875a2..8036cd23 100644 --- a/config/contents/lint/duplicate_regexp_character_class_element.md +++ b/config/contents/lint/duplicate_regexp_character_class_element.md @@ -1,4 +1,4 @@ -This cop checks for duplicate elements in Regexp character classes. +Checks for duplicate elements in Regexp character classes. ### Example: diff --git a/config/contents/lint/duplicate_require.md b/config/contents/lint/duplicate_require.md index ff7dd3de..45f09c65 100644 --- a/config/contents/lint/duplicate_require.md +++ b/config/contents/lint/duplicate_require.md @@ -1,4 +1,8 @@ -This cop checks for duplicate `require`s and `require_relative`s. +Checks for duplicate ``require``s and ``require_relative``s. + +@safety + This cop's autocorrection is unsafe because it may break the dependency order + of `require`. ### Example: # bad diff --git a/config/contents/lint/duplicate_rescue_exception.md b/config/contents/lint/duplicate_rescue_exception.md index e430c4f6..ac3178c9 100644 --- a/config/contents/lint/duplicate_rescue_exception.md +++ b/config/contents/lint/duplicate_rescue_exception.md @@ -1,4 +1,4 @@ -This cop checks that there are no repeated exceptions +Checks that there are no repeated exceptions used in 'rescue' expressions. ### Example: diff --git a/config/contents/lint/each_with_object_argument.md b/config/contents/lint/each_with_object_argument.md index 2cbab47c..bbb1fd5d 100644 --- a/config/contents/lint/each_with_object_argument.md +++ b/config/contents/lint/each_with_object_argument.md @@ -1,4 +1,4 @@ -This cop checks if each_with_object is called with an immutable +Checks if each_with_object is called with an immutable argument. Since the argument is the object that the given block shall make calls on to build something based on the enumerable that each_with_object iterates over, an immutable argument makes no sense. diff --git a/config/contents/lint/else_layout.md b/config/contents/lint/else_layout.md index 9ed76256..c842bf77 100644 --- a/config/contents/lint/else_layout.md +++ b/config/contents/lint/else_layout.md @@ -1,8 +1,8 @@ -This cop checks for odd `else` block layout - like +Checks for odd `else` block layout - like having an expression on the same line as the `else` keyword, which is usually a mistake. -Its auto-correction tweaks layout to keep the syntax. So, this auto-correction +Its autocorrection tweaks layout to keep the syntax. So, this autocorrection is compatible correction for bad case syntax, but if your code makes a mistake with `elsif` and `else`, you will have to correct it manually. @@ -20,7 +20,7 @@ with `elsif` and `else`, you will have to correct it manually. # good - # This code is compatible with the bad case. It will be auto-corrected like this. + # This code is compatible with the bad case. It will be autocorrected like this. if something # ... else diff --git a/config/contents/lint/empty_block.md b/config/contents/lint/empty_block.md index dcd86cb2..76d73634 100644 --- a/config/contents/lint/empty_block.md +++ b/config/contents/lint/empty_block.md @@ -1,6 +1,6 @@ -This cop checks for blocks without a body. +Checks for blocks without a body. Such empty blocks are typically an oversight or we should provide a comment -be clearer what we're aiming for. +to clarify what we're aiming for. Empty lambdas and procs are ignored by default. diff --git a/config/contents/lint/empty_class.md b/config/contents/lint/empty_class.md index a4c86992..694c3540 100644 --- a/config/contents/lint/empty_class.md +++ b/config/contents/lint/empty_class.md @@ -1,4 +1,4 @@ -This cop checks for classes and metaclasses without a body. +Checks for classes and metaclasses without a body. Such empty classes and metaclasses are typically an oversight or we should provide a comment to be clearer what we're aiming for. diff --git a/config/contents/lint/empty_conditional_body.md b/config/contents/lint/empty_conditional_body.md index b3fc9e90..26ade68c 100644 --- a/config/contents/lint/empty_conditional_body.md +++ b/config/contents/lint/empty_conditional_body.md @@ -1,4 +1,12 @@ -This cop checks for the presence of `if`, `elsif` and `unless` branches without a body. +Checks for the presence of `if`, `elsif` and `unless` branches without a body. + +NOTE: empty `else` branches are handled by `Style/EmptyElse`. + +@safety + Autocorrection for this cop is not safe. The conditions for empty branches that + the autocorrection removes may have side effects, or the logic in subsequent + branches may change due to the removal of a previous condition. + ### Example: # bad if condition diff --git a/config/contents/lint/empty_ensure.md b/config/contents/lint/empty_ensure.md index af1a57a7..1876e431 100644 --- a/config/contents/lint/empty_ensure.md +++ b/config/contents/lint/empty_ensure.md @@ -1,4 +1,4 @@ -This cop checks for empty `ensure` blocks +Checks for empty `ensure` blocks ### Example: diff --git a/config/contents/lint/empty_expression.md b/config/contents/lint/empty_expression.md index 16f8d0ad..e3e65bc1 100644 --- a/config/contents/lint/empty_expression.md +++ b/config/contents/lint/empty_expression.md @@ -1,4 +1,4 @@ -This cop checks for the presence of empty expressions. +Checks for the presence of empty expressions. ### Example: diff --git a/config/contents/lint/empty_file.md b/config/contents/lint/empty_file.md index 166d266d..846e095f 100644 --- a/config/contents/lint/empty_file.md +++ b/config/contents/lint/empty_file.md @@ -1,4 +1,4 @@ -This cop enforces that Ruby source files are not empty. +Enforces that Ruby source files are not empty. ### Example: # bad diff --git a/config/contents/lint/empty_in_pattern.md b/config/contents/lint/empty_in_pattern.md index c6e97ddc..0be5259a 100644 --- a/config/contents/lint/empty_in_pattern.md +++ b/config/contents/lint/empty_in_pattern.md @@ -1,4 +1,4 @@ -This cop checks for the presence of `in` pattern branches without a body. +Checks for the presence of `in` pattern branches without a body. ### Example: diff --git a/config/contents/lint/empty_interpolation.md b/config/contents/lint/empty_interpolation.md index e6b9e1cd..8535638f 100644 --- a/config/contents/lint/empty_interpolation.md +++ b/config/contents/lint/empty_interpolation.md @@ -1,4 +1,4 @@ -This cop checks for empty interpolation. +Checks for empty interpolation. ### Example: diff --git a/config/contents/lint/empty_when.md b/config/contents/lint/empty_when.md index d4f104bb..b7ce9158 100644 --- a/config/contents/lint/empty_when.md +++ b/config/contents/lint/empty_when.md @@ -1,4 +1,4 @@ -This cop checks for the presence of `when` branches without a body. +Checks for the presence of `when` branches without a body. ### Example: diff --git a/config/contents/lint/ensure_return.md b/config/contents/lint/ensure_return.md index 7295a5d7..47097ecb 100644 --- a/config/contents/lint/ensure_return.md +++ b/config/contents/lint/ensure_return.md @@ -1,4 +1,4 @@ -This cop checks for `return` from an `ensure` block. +Checks for `return` from an `ensure` block. `return` from an ensure block is a dangerous code smell as it will take precedence over any exception being raised, and the exception will be silently thrown away as if it were rescued. diff --git a/config/contents/lint/erb_new_arguments.md b/config/contents/lint/erb_new_arguments.md index 12653336..7c4a1f64 100644 --- a/config/contents/lint/erb_new_arguments.md +++ b/config/contents/lint/erb_new_arguments.md @@ -1,18 +1,17 @@ +Emulates the following Ruby warnings in Ruby 2.6. -This cop emulates the following Ruby warnings in Ruby 2.6. - -% cat example.rb +[source,console] +---- +$ cat example.rb ERB.new('hi', nil, '-', '@output_buffer') -% ruby -rerb example.rb -example.rb:1: warning: Passing safe_level with the 2nd argument of -ERB.new is deprecated. Do not use it, and specify other arguments as -keyword arguments. -example.rb:1: warning: Passing trim_mode with the 3rd argument of -ERB.new is deprecated. Use keyword argument like -ERB.new(str, trim_mode:...) instead. -example.rb:1: warning: Passing eoutvar with the 4th argument of ERB.new -is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) -instead. +$ ruby -rerb example.rb +example.rb:1: warning: Passing safe_level with the 2nd argument of ERB.new is +deprecated. Do not use it, and specify other arguments as keyword arguments. +example.rb:1: warning: Passing trim_mode with the 3rd argument of ERB.new is +deprecated. Use keyword argument like ERB.new(str, trim_mode:...) instead. +example.rb:1: warning: Passing eoutvar with the 4th argument of ERB.new is +deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead. +---- Now non-keyword arguments other than first one are softly deprecated and will be removed when Ruby 2.5 becomes EOL. diff --git a/config/contents/lint/flip_flop.md b/config/contents/lint/flip_flop.md index 15b3174a..fd7115e5 100644 --- a/config/contents/lint/flip_flop.md +++ b/config/contents/lint/flip_flop.md @@ -1,4 +1,4 @@ -This cop looks for uses of flip-flop operator +Looks for uses of flip-flop operator based on the Ruby Style Guide. Here is the history of flip-flops in Ruby. diff --git a/config/contents/lint/float_comparison.md b/config/contents/lint/float_comparison.md index b9d7bc7f..aa8da4a9 100644 --- a/config/contents/lint/float_comparison.md +++ b/config/contents/lint/float_comparison.md @@ -1,4 +1,4 @@ -This cop checks for the presence of precise comparison of floating point numbers. +Checks for the presence of precise comparison of floating point numbers. Floating point values are inherently inaccurate, and comparing them for exact equality is almost never the desired semantics. Comparison via the `==/!=` operators checks @@ -13,6 +13,10 @@ if you perform any arithmetic operations involving precision loss. # good - using BigDecimal x.to_d == 0.1.to_d + # good - comparing against zero + x == 0.0 + x != 0.0 + # good (x - 0.1).abs < Float::EPSILON diff --git a/config/contents/lint/float_out_of_range.md b/config/contents/lint/float_out_of_range.md index c910b236..93c35275 100644 --- a/config/contents/lint/float_out_of_range.md +++ b/config/contents/lint/float_out_of_range.md @@ -1,4 +1,4 @@ -This cop identifies Float literals which are, like, really really really +Identifies Float literals which are, like, really really really really really really really really big. Too big. No-one needs Floats that big. If you need a float that big, something is wrong with you. diff --git a/config/contents/lint/hash_compare_by_identity.md b/config/contents/lint/hash_compare_by_identity.md index 99f6e2bd..28af53eb 100644 --- a/config/contents/lint/hash_compare_by_identity.md +++ b/config/contents/lint/hash_compare_by_identity.md @@ -1,7 +1,16 @@ -Prefer using `Hash#compare_by_identity` than using `object_id` for hash keys. +Prefer using `Hash#compare_by_identity` rather than using `object_id` +for hash keys. -This cop is marked as unsafe as a hash possibly can contain other keys -besides `object_id`s. +This cop looks for hashes being keyed by objects' `object_id`, using +one of these methods: `key?`, `has_key?`, `fetch`, `[]` and `[]=`. + +@safety + This cop is unsafe. Although unlikely, the hash could store both object + ids and other values that need be compared by value, and thus + could be a false positive. + + Furthermore, this cop cannot guarantee that the receiver of one of the + methods (`key?`, etc.) is actually a hash. ### Example: # bad diff --git a/config/contents/lint/heredoc_method_call_position.md b/config/contents/lint/heredoc_method_call_position.md index 2ad209ea..ffcc8736 100644 --- a/config/contents/lint/heredoc_method_call_position.md +++ b/config/contents/lint/heredoc_method_call_position.md @@ -1,26 +1,24 @@ -This cop checks for the ordering of a method call where +Checks for the ordering of a method call where the receiver of the call is a HEREDOC. ### Example: # bad + <<-SQL + bar + SQL + .strip_indent - <<-SQL - bar - SQL - .strip_indent - - <<-SQL - bar - SQL - .strip_indent - .trim + <<-SQL + bar + SQL + .strip_indent + .trim # good + <<~SQL + bar + SQL - <<~SQL - bar - SQL - - <<~SQL.trim - bar - SQL + <<~SQL.trim + bar + SQL diff --git a/config/contents/lint/identity_comparison.md b/config/contents/lint/identity_comparison.md index c52449e0..23f51dbb 100644 --- a/config/contents/lint/identity_comparison.md +++ b/config/contents/lint/identity_comparison.md @@ -1,4 +1,3 @@ - Prefer `equal?` over `==` when comparing `object_id`. `Object#equal?` is provided to compare objects for identity, and in contrast diff --git a/config/contents/lint/implicit_string_concatenation.md b/config/contents/lint/implicit_string_concatenation.md index e0ec682e..0db7d3f7 100644 --- a/config/contents/lint/implicit_string_concatenation.md +++ b/config/contents/lint/implicit_string_concatenation.md @@ -1,4 +1,4 @@ -This cop checks for implicit string concatenation of string literals +Checks for implicit string concatenation of string literals which are on the same line. ### Example: diff --git a/config/contents/lint/incompatible_io_select_with_fiber_scheduler.md b/config/contents/lint/incompatible_io_select_with_fiber_scheduler.md new file mode 100644 index 00000000..c0134126 --- /dev/null +++ b/config/contents/lint/incompatible_io_select_with_fiber_scheduler.md @@ -0,0 +1,27 @@ +Checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0. + +When an array of IO objects waiting for an exception (the third argument of `IO.select`) +is used as an argument, there is no alternative API, so offenses are not registered. + +NOTE: When the method is successful the return value of `IO.select` is `[[IO]]`, +and the return value of `io.wait_readable` and `io.wait_writable` are `self`. +They are not autocorrected when assigning a return value because these types are different. +It's up to user how to handle the return value. + +@safety + This cop's autocorrection is unsafe because `NoMethodError` occurs + if `require 'io/wait'` is not called. + +### Example: + + # bad + IO.select([io], [], [], timeout) + + # good + io.wait_readable(timeout) + + # bad + IO.select([], [io], [], timeout) + + # good + io.wait_writable(timeout) diff --git a/config/contents/lint/ineffective_access_modifier.md b/config/contents/lint/ineffective_access_modifier.md index 7ea298fd..b04033c1 100644 --- a/config/contents/lint/ineffective_access_modifier.md +++ b/config/contents/lint/ineffective_access_modifier.md @@ -1,4 +1,4 @@ -This cop checks for `private` or `protected` access modifiers which are +Checks for `private` or `protected` access modifiers which are applied to a singleton method. These access modifiers do not make singleton methods private/protected. `private_class_method` can be used for that. diff --git a/config/contents/lint/inherit_exception.md b/config/contents/lint/inherit_exception.md index cb7837bc..771c6f22 100644 --- a/config/contents/lint/inherit_exception.md +++ b/config/contents/lint/inherit_exception.md @@ -1,9 +1,13 @@ -This cop looks for error classes inheriting from `Exception` -and its standard library subclasses, excluding subclasses of -`StandardError`. It is configurable to suggest using either -`RuntimeError` (default) or `StandardError` instead. +Looks for error classes inheriting from `Exception`. +It is configurable to suggest using either `StandardError` (default) or +`RuntimeError` instead. -### Example: EnforcedStyle: runtime_error (default) +@safety + This cop's autocorrection is unsafe because `rescue` that omit + exception class handle `StandardError` and its subclasses, + but not `Exception` and its subclasses. + +### Example: EnforcedStyle: standard_error (default) # bad class C < Exception; end @@ -12,11 +16,11 @@ and its standard library subclasses, excluding subclasses of # good - class C < RuntimeError; end + class C < StandardError; end - C = Class.new(RuntimeError) + C = Class.new(StandardError) -### Example: EnforcedStyle: standard_error +### Example: EnforcedStyle: runtime_error # bad class C < Exception; end @@ -25,6 +29,6 @@ and its standard library subclasses, excluding subclasses of # good - class C < StandardError; end + class C < RuntimeError; end - C = Class.new(StandardError) \ No newline at end of file + C = Class.new(RuntimeError) \ No newline at end of file diff --git a/config/contents/lint/interpolation_check.md b/config/contents/lint/interpolation_check.md index c74e058f..a723e578 100644 --- a/config/contents/lint/interpolation_check.md +++ b/config/contents/lint/interpolation_check.md @@ -1,4 +1,10 @@ -This cop checks for interpolation in a single quoted string. +Checks for interpolation in a single quoted string. + +@safety + This cop's autocorrection is unsafe because although it always replaces single quotes as + if it were miswritten double quotes, it is not always the case. For example, + `'#{foo} bar'` would be replaced by `"#{foo} bar"`, so the replaced code would evaluate + the expression `foo`. ### Example: diff --git a/config/contents/lint/it_without_arguments_in_block.md b/config/contents/lint/it_without_arguments_in_block.md new file mode 100644 index 00000000..3fc8e990 --- /dev/null +++ b/config/contents/lint/it_without_arguments_in_block.md @@ -0,0 +1,20 @@ +Emulates the following Ruby warning in Ruby 3.3. + +[source,ruby] +---- +$ ruby -e '0.times { it }' +-e:1: warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; +use it() or self.it +---- + +`it` calls without arguments will refer to the first block param in Ruby 3.4. +So use `it()` or `self.it` to ensure compatibility. + +### Example: + + # bad + do_something { it } + + # good + do_something { it() } + do_something { self.it } diff --git a/config/contents/lint/lambda_without_literal_block.md b/config/contents/lint/lambda_without_literal_block.md index 0dd6abbc..6a82ea41 100644 --- a/config/contents/lint/lambda_without_literal_block.md +++ b/config/contents/lint/lambda_without_literal_block.md @@ -1,13 +1,13 @@ -This cop checks uses of lambda without a literal block. +Checks uses of lambda without a literal block. It emulates the following warning in Ruby 3.0: - % ruby -vwe 'lambda(&proc {})' + $ ruby -vwe 'lambda(&proc {})' ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19] -e:1: warning: lambda without a literal block is deprecated; use the proc without lambda instead This way, proc object is never converted to lambda. -Auto-correction replaces with compatible proc argument. +Autocorrection replaces with compatible proc argument. ### Example: diff --git a/config/contents/lint/literal_as_condition.md b/config/contents/lint/literal_as_condition.md index 5c78d984..3d22c1d6 100644 --- a/config/contents/lint/literal_as_condition.md +++ b/config/contents/lint/literal_as_condition.md @@ -1,7 +1,10 @@ -This cop checks for literals used as the conditions or as +Checks for literals used as the conditions or as operands in and/or expressions serving as the conditions of if/while/until/case-when/case-in. +NOTE: Literals in `case-in` condition where the match variable is used in +`in` are accepted as a pattern matching. + ### Example: # bad diff --git a/config/contents/lint/literal_assignment_in_condition.md b/config/contents/lint/literal_assignment_in_condition.md new file mode 100644 index 00000000..db6656c7 --- /dev/null +++ b/config/contents/lint/literal_assignment_in_condition.md @@ -0,0 +1,28 @@ +Checks for literal assignments in the conditions of `if`, `while`, and `until`. +It emulates the following Ruby warning: + +[source,console] +---- +$ ruby -we 'if x = true; end' +-e:1: warning: found `= literal' in conditional, should be == +---- + +As a lint cop, it cannot be determined if `==` is appropriate as intended, +therefore this cop does not provide autocorrection. + +### Example: + + # bad + if x = 42 + do_something + end + + # good + if x == 42 + do_something + end + + # good + if x = y + do_something + end diff --git a/config/contents/lint/literal_in_interpolation.md b/config/contents/lint/literal_in_interpolation.md index 859ee1d0..54395a23 100644 --- a/config/contents/lint/literal_in_interpolation.md +++ b/config/contents/lint/literal_in_interpolation.md @@ -1,4 +1,4 @@ -This cop checks for interpolated literals. +Checks for interpolated literals. ### Example: diff --git a/config/contents/lint/loop.md b/config/contents/lint/loop.md index dfea642e..36368b44 100644 --- a/config/contents/lint/loop.md +++ b/config/contents/lint/loop.md @@ -1,8 +1,9 @@ -This cop checks for uses of `begin...end while/until something`. +Checks for uses of `begin...end while/until something`. -The cop is marked as unsafe because behaviour can change in some cases, including -if a local variable inside the loop body is accessed outside of it, or if the -loop body raises a `StopIteration` exception (which `Kernel#loop` rescues). +@safety + The cop is unsafe because behavior can change in some cases, including + if a local variable inside the loop body is accessed outside of it, or if the + loop body raises a `StopIteration` exception (which `Kernel#loop` rescues). ### Example: diff --git a/config/contents/lint/missing_super.md b/config/contents/lint/missing_super.md index d305e8c3..8b9f0a0a 100644 --- a/config/contents/lint/missing_super.md +++ b/config/contents/lint/missing_super.md @@ -1,4 +1,4 @@ -This cop checks for the presence of constructors and lifecycle callbacks +Checks for the presence of constructors and lifecycle callbacks without calls to `super`. This cop does not consider `method_missing` (and `respond_to_missing?`) @@ -6,6 +6,16 @@ because in some cases it makes sense to overtake what is considered a missing method. In other cases, the theoretical ideal handling could be challenging or verbose for no actual gain. +Autocorrection is not supported because the position of `super` cannot be +determined automatically. + +`Object` and `BasicObject` are allowed by this cop because of their +stateless nature. However, sometimes you might want to allow other parent +classes from this cop, for example in the case of an abstract class that is +not meant to be called with `super`. In those cases, you can use the +`AllowedParentClasses` option to specify which classes should be allowed +*in addition to* `Object` and `BasicObject`. + ### Example: # bad class Employee < Person @@ -22,6 +32,21 @@ challenging or verbose for no actual gain. end end + # bad + Employee = Class.new(Person) do + def initialize(name, salary) + @salary = salary + end + end + + # good + Employee = Class.new(Person) do + def initialize(name, salary) + super(name) + @salary = salary + end + end + # bad class Parent def self.inherited(base) @@ -36,3 +61,18 @@ challenging or verbose for no actual gain. do_something end end + + # good + class ClassWithNoParent + def initialize + do_something + end + end + +### Example: AllowedParentClasses: [MyAbstractClass] + # good + class MyConcreteClass < MyAbstractClass + def initialize + do_something + end + end diff --git a/config/contents/lint/mixed_case_range.md b/config/contents/lint/mixed_case_range.md new file mode 100644 index 00000000..d680656e --- /dev/null +++ b/config/contents/lint/mixed_case_range.md @@ -0,0 +1,22 @@ +Checks for mixed-case character ranges since they include likely unintended characters. + +Offenses are registered for regexp character classes like `/[A-z]/` +as well as range objects like `('A'..'z')`. + +NOTE: Range objects cannot be autocorrected. + +@safety + The cop autocorrects regexp character classes + by replacing one character range with two: `A-z` becomes `A-Za-z`. + In most cases this is probably what was originally intended + but it changes the regexp to no longer match symbols it used to include. + For this reason, this cop's autocorrect is unsafe (it will + change the behavior of the code). + +### Example: + + # bad + r = /[A-z]/ + + # good + r = /[A-Za-z]/ \ No newline at end of file diff --git a/config/contents/lint/mixed_regexp_capture_types.md b/config/contents/lint/mixed_regexp_capture_types.md index f3e3653f..6e074a51 100644 --- a/config/contents/lint/mixed_regexp_capture_types.md +++ b/config/contents/lint/mixed_regexp_capture_types.md @@ -3,6 +3,7 @@ because numbered capture is ignored if they're mixed. Replace numbered captures with non-capturing groupings or named captures. +### Example: # bad /(?FOO)(BAR)/ diff --git a/config/contents/lint/nested_method_definition.md b/config/contents/lint/nested_method_definition.md index f60941d1..e69ae3de 100644 --- a/config/contents/lint/nested_method_definition.md +++ b/config/contents/lint/nested_method_definition.md @@ -1,4 +1,4 @@ -This cop checks for nested method definitions. +Checks for nested method definitions. ### Example: @@ -25,6 +25,9 @@ This cop checks for nested method definitions. # good + # `class_eval`, `instance_eval`, `module_eval`, `class_exec`, `instance_exec`, and + # `module_exec` blocks are allowed by default. + def foo self.class.class_eval do def bar @@ -48,4 +51,40 @@ This cop checks for nested method definitions. def bar end end - end \ No newline at end of file + end + +### Example: AllowedMethods: [] (default) + # bad + def do_something + has_many :articles do + def find_or_create_by_name(name) + end + end + end + +### Example: AllowedMethods: ['has_many'] + # bad + def do_something + has_many :articles do + def find_or_create_by_name(name) + end + end + end + +### Example: AllowedPatterns: [] (default) + # bad + def foo(obj) + obj.do_baz do + def bar + end + end + end + +### Example: AllowedPatterns: ['baz'] + # good + def foo(obj) + obj.do_baz do + def bar + end + end + end diff --git a/config/contents/lint/nested_percent_literal.md b/config/contents/lint/nested_percent_literal.md index b42a58de..469beaba 100644 --- a/config/contents/lint/nested_percent_literal.md +++ b/config/contents/lint/nested_percent_literal.md @@ -1,4 +1,4 @@ -This cop checks for nested percent literals. +Checks for nested percent literals. ### Example: diff --git a/config/contents/lint/non_atomic_file_operation.md b/config/contents/lint/non_atomic_file_operation.md new file mode 100644 index 00000000..77106d98 --- /dev/null +++ b/config/contents/lint/non_atomic_file_operation.md @@ -0,0 +1,37 @@ +Checks for non-atomic file operation. +And then replace it with a nearly equivalent and atomic method. + +These can cause problems that are difficult to reproduce, +especially in cases of frequent file operations in parallel, +such as test runs with parallel_rspec. + +For examples: creating a directory if there is none, has the following problems + +An exception occurs when the directory didn't exist at the time of `exist?`, +but someone else created it before `mkdir` was executed. + +Subsequent processes are executed without the directory that should be there +when the directory existed at the time of `exist?`, +but someone else deleted it shortly afterwards. + +@safety + This cop is unsafe, because autocorrection change to atomic processing. + The atomic processing of the replacement destination is not guaranteed + to be strictly equivalent to that before the replacement. + +### Example: + # bad - race condition with another process may result in an error in `mkdir` + unless Dir.exist?(path) + FileUtils.mkdir(path) + end + + # good - atomic and idempotent creation + FileUtils.mkdir_p(path) + + # bad - race condition with another process may result in an error in `remove` + if File.exist?(path) + FileUtils.remove(path) + end + + # good - atomic and idempotent removal + FileUtils.rm_f(path) diff --git a/config/contents/lint/non_deterministic_require_order.md b/config/contents/lint/non_deterministic_require_order.md index fbe37bbd..f0f8b776 100644 --- a/config/contents/lint/non_deterministic_require_order.md +++ b/config/contents/lint/non_deterministic_require_order.md @@ -9,7 +9,11 @@ always sort the list. `Dir.glob` and `Dir[]` sort globbed results by default in Ruby 3.0. So all bad cases are acceptable when Ruby 3.0 or higher are used. -This cop will be deprecated and removed when supporting only Ruby 3.0 and higher. +NOTE: This cop will be deprecated and removed when supporting only Ruby 3.0 and higher. + +@safety + This cop is unsafe in the case where sorting files changes existing + expected behavior. ### Example: diff --git a/config/contents/lint/non_local_exit_from_iterator.md b/config/contents/lint/non_local_exit_from_iterator.md index 0f61b5ee..666b1810 100644 --- a/config/contents/lint/non_local_exit_from_iterator.md +++ b/config/contents/lint/non_local_exit_from_iterator.md @@ -1,4 +1,4 @@ -This cop checks for non-local exits from iterators without a return +Checks for non-local exits from iterators without a return value. It registers an offense under these conditions: * No value is returned, diff --git a/config/contents/lint/number_conversion.md b/config/contents/lint/number_conversion.md index 83a81a00..7b2a2403 100644 --- a/config/contents/lint/number_conversion.md +++ b/config/contents/lint/number_conversion.md @@ -1,17 +1,23 @@ -This cop warns the usage of unsafe number conversions. Unsafe +Warns the usage of unsafe number conversions. Unsafe number conversion can cause unexpected error if auto type conversion fails. Cop prefer parsing with number class instead. Conversion with `Integer`, `Float`, etc. will raise an `ArgumentError` if given input that is not numeric (eg. an empty string), whereas -`to_i`, etc. will try to convert regardless of input (`''.to_i => 0`). +`to_i`, etc. will try to convert regardless of input (``''.to_i => 0``). As such, this cop is disabled by default because it's not necessarily always correct to raise if a value is not numeric. NOTE: Some values cannot be converted properly using one of the `Kernel` method (for instance, `Time` and `DateTime` values are allowed by this cop by default). Similarly, Rails' duration methods do not work well -with `Integer()` and can be ignored with `IgnoredMethods`. +with `Integer()` and can be allowed with `AllowedMethods`. By default, +there are no methods to allowed. + +@safety + Autocorrection is unsafe because it is not guaranteed that the + replacement `Kernel` methods are able to properly handle the + input if it is not a standard class. ### Example: @@ -20,6 +26,7 @@ with `Integer()` and can be ignored with `IgnoredMethods`. '10'.to_i '10.2'.to_f '10'.to_c + '1/3'.to_r ['1', '2', '3'].map(&:to_i) foo.try(:to_f) bar.send(:to_c) @@ -29,11 +36,27 @@ with `Integer()` and can be ignored with `IgnoredMethods`. Integer('10', 10) Float('10.2') Complex('10') + Rational('1/3') ['1', '2', '3'].map { |i| Integer(i, 10) } foo.try { |i| Float(i) } bar.send { |i| Complex(i) } -### Example: IgnoredMethods: [minutes] +### Example: AllowedMethods: [] (default) + + # bad + 10.minutes.to_i + +### Example: AllowedMethods: [minutes] + + # good + 10.minutes.to_i + +### Example: AllowedPatterns: [] (default) + + # bad + 10.minutes.to_i + +### Example: AllowedPatterns: ['min*'] # good 10.minutes.to_i diff --git a/config/contents/lint/numbered_parameter_assignment.md b/config/contents/lint/numbered_parameter_assignment.md index c0de98b9..32395532 100644 --- a/config/contents/lint/numbered_parameter_assignment.md +++ b/config/contents/lint/numbered_parameter_assignment.md @@ -1,13 +1,13 @@ -This cop checks for uses of numbered parameter assignment. +Checks for uses of numbered parameter assignment. It emulates the following warning in Ruby 2.7: - % ruby -ve '_1 = :value' + $ ruby -ve '_1 = :value' ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19] -e:1: warning: `_1' is reserved for numbered parameter; consider another name -Assiging to numbered parameter (from `_1` to `_9`) cause an error in Ruby 3.0. +Assigning to a numbered parameter (from `_1` to `_9`) causes an error in Ruby 3.0. - % ruby -ve '_1 = :value' + $ ruby -ve '_1 = :value' ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19] -e:1: _1 is reserved for numbered parameter diff --git a/config/contents/lint/or_assignment_to_constant.md b/config/contents/lint/or_assignment_to_constant.md index 72473956..381cff75 100644 --- a/config/contents/lint/or_assignment_to_constant.md +++ b/config/contents/lint/or_assignment_to_constant.md @@ -1,11 +1,12 @@ -This cop checks for unintended or-assignment to a constant. +Checks for unintended or-assignment to a constant. Constants should always be assigned in the same location. And its value should always be the same. If constants are assigned in multiple locations, the result may vary depending on the order of `require`. -Also, if you already have such an implementation, auto-correction may -change the result. +@safety + This cop is unsafe because code that is already conditionally + assigning a constant may have its behavior changed by autocorrection. ### Example: diff --git a/config/contents/lint/ordered_magic_comments.md b/config/contents/lint/ordered_magic_comments.md index c857fd41..2fe9547d 100644 --- a/config/contents/lint/ordered_magic_comments.md +++ b/config/contents/lint/ordered_magic_comments.md @@ -1,7 +1,9 @@ - Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang. +@safety + This cop's autocorrection is unsafe because file encoding may change. + ### Example: # bad diff --git a/config/contents/lint/out_of_range_regexp_ref.md b/config/contents/lint/out_of_range_regexp_ref.md index 83a647d9..02c7faba 100644 --- a/config/contents/lint/out_of_range_regexp_ref.md +++ b/config/contents/lint/out_of_range_regexp_ref.md @@ -1,6 +1,23 @@ -This cops looks for references of Regexp captures that are out of range +Looks for references of Regexp captures that are out of range and thus always returns nil. +@safety + This cop is unsafe because it is naive in how it determines what + references are available based on the last encountered regexp, but + it cannot handle some cases, such as conditional regexp matches, which + leads to false positives, such as: + + [source,ruby] + ---- + foo ? /(c)(b)/ =~ str : /(b)/ =~ str + do_something if $2 + # $2 is defined for the first condition but not the second, however + # the cop will mark this as an offense. + ---- + + This might be a good indication of code that should be refactored, + however. + ### Example: /(foo)bar/ =~ 'foobar' diff --git a/config/contents/lint/percent_string_array.md b/config/contents/lint/percent_string_array.md index 4f674b5a..10719c05 100644 --- a/config/contents/lint/percent_string_array.md +++ b/config/contents/lint/percent_string_array.md @@ -1,9 +1,19 @@ -This cop checks for quotes and commas in %w, e.g. `%w('foo', "bar")` +Checks for quotes and commas in %w, e.g. `%w('foo', "bar")` It is more likely that the additional characters are unintended (for example, mistranslating an array of literals to percent string notation) rather than meant to be part of the resulting strings. +@safety + The cop is unsafe because the correction changes the values in the array + and that might have been done purposely. + + [source,ruby] + ---- + %w('foo', "bar") #=> ["'foo',", '"bar"'] + %w(foo bar) #=> ['foo', 'bar'] + ---- + ### Example: # bad diff --git a/config/contents/lint/percent_symbol_array.md b/config/contents/lint/percent_symbol_array.md index bb4331de..2177bd37 100644 --- a/config/contents/lint/percent_symbol_array.md +++ b/config/contents/lint/percent_symbol_array.md @@ -1,4 +1,4 @@ -This cop checks for colons and commas in %i, e.g. `%i(:foo, :bar)` +Checks for colons and commas in %i, e.g. `%i(:foo, :bar)` It is more likely that the additional characters are unintended (for example, mistranslating an array of literals to percent string notation) diff --git a/config/contents/lint/raise_exception.md b/config/contents/lint/raise_exception.md index 59fc3833..bda8a7e6 100644 --- a/config/contents/lint/raise_exception.md +++ b/config/contents/lint/raise_exception.md @@ -1,4 +1,4 @@ -This cop checks for `raise` or `fail` statements which are +Checks for `raise` or `fail` statements which are raising `Exception` class. You can specify a module name that will be an implicit namespace @@ -8,6 +8,10 @@ prevent the false positive by specifying a namespace to be omitted for `Exception`. Alternatively, make `Exception` a fully qualified class name with an explicit namespace. +@safety + This cop is unsafe because it will change the exception class being + raised, which is a change in behavior. + ### Example: # bad raise Exception, 'Error message here' diff --git a/config/contents/lint/rand_one.md b/config/contents/lint/rand_one.md index ecd016d8..b729d9d9 100644 --- a/config/contents/lint/rand_one.md +++ b/config/contents/lint/rand_one.md @@ -1,4 +1,4 @@ -This cop checks for `rand(1)` calls. +Checks for `rand(1)` calls. Such calls always return `0`. ### Example: diff --git a/config/contents/lint/redundant_dir_glob_sort.md b/config/contents/lint/redundant_dir_glob_sort.md index bacd0c85..b9345a94 100644 --- a/config/contents/lint/redundant_dir_glob_sort.md +++ b/config/contents/lint/redundant_dir_glob_sort.md @@ -1,6 +1,11 @@ Sort globbed results by default in Ruby 3.0. This cop checks for redundant `sort` method to `Dir.glob` and `Dir[]`. +@safety + This cop is unsafe, in case of having a file and a directory with + identical names, since directory will be loaded before the file, which + will break `exe/files.rb` that rely on `exe.rb` file. + ### Example: # bad diff --git a/config/contents/lint/redundant_regexp_quantifiers.md b/config/contents/lint/redundant_regexp_quantifiers.md new file mode 100644 index 00000000..d3f7f396 --- /dev/null +++ b/config/contents/lint/redundant_regexp_quantifiers.md @@ -0,0 +1,28 @@ +Checks for redundant quantifiers inside Regexp literals. + +It is always allowed when interpolation is used in a regexp literal, +because it's unknown what kind of string will be expanded as a result: + +[source,ruby] +---- +/(?:a*#{interpolation})?/x +---- + +### Example: + # bad + /(?:x+)+/ + + # good + /(?:x)+/ + + # good + /(?:x+)/ + + # bad + /(?:x+)?/ + + # good + /(?:x)*/ + + # good + /(?:x*)/ \ No newline at end of file diff --git a/config/contents/lint/redundant_require_statement.md b/config/contents/lint/redundant_require_statement.md index 46ab7f0f..602dd18e 100644 --- a/config/contents/lint/redundant_require_statement.md +++ b/config/contents/lint/redundant_require_statement.md @@ -1,13 +1,27 @@ Checks for unnecessary `require` statement. The following features are unnecessary `require` statement because -they are already loaded. +they are already loaded. e.g. Ruby 2.2: ruby -ve 'p $LOADED_FEATURES.reject { |feature| %r|/| =~ feature }' ruby 2.2.8p477 (2017-09-14 revision 59906) [x86_64-darwin13] ["enumerator.so", "rational.so", "complex.so", "thread.rb"] -This cop targets Ruby 2.2 or higher containing these 4 features. +Below are the features that each `TargetRubyVersion` targets. + + * 2.0+ ... `enumerator` + * 2.1+ ... `thread` + * 2.2+ ... Add `rational` and `complex` above + * 2.5+ ... Add `pp` above + * 2.7+ ... Add `ruby2_keywords` above + * 3.1+ ... Add `fiber` above + * 3.2+ ... `set` + +This cop target those features. + +@safety + This cop's autocorrection is unsafe because if `require 'pp'` is removed from one file, + `NameError` can be encountered when another file uses `PP.pp`. ### Example: # bad diff --git a/config/contents/lint/redundant_safe_navigation.md b/config/contents/lint/redundant_safe_navigation.md index f23497af..06b84787 100644 --- a/config/contents/lint/redundant_safe_navigation.md +++ b/config/contents/lint/redundant_safe_navigation.md @@ -1,15 +1,29 @@ -This cop checks for redundant safe navigation calls. -`instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods -are checked by default. These are customizable with `AllowedMethods` option. +Checks for redundant safe navigation calls. +Use cases where a constant, named in camel case for classes and modules is `nil` are rare, +and an offense is not detected when the receiver is a constant. The detection also applies +to literal receivers, except for `nil`. -This cop is marked as unsafe, because auto-correction can change the -return type of the expression. An offending expression that previously -could return `nil` will be auto-corrected to never return `nil`. +For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, +and `equal?` methods are checked by default. +These are customizable with `AllowedMethods` option. + +The `AllowedMethods` option specifies nil-safe methods, +in other words, it is a method that is allowed to skip safe navigation. +Note that the `AllowedMethod` option is not an option that specifies methods +for which to suppress (allow) this cop's check. In the example below, the safe navigation operator (`&.`) is unnecessary because `NilClass` has methods like `respond_to?` and `is_a?`. +@safety + This cop is unsafe, because autocorrection can change the return type of + the expression. An offending expression that previously could return `nil` + will be autocorrected to never return `nil`. + ### Example: + # bad + CamelCaseConst&.do_something + # bad do_something if attrs&.respond_to?(:[]) @@ -21,6 +35,9 @@ because `NilClass` has methods like `respond_to?` and `is_a?`. node = node.parent end + # good + CamelCaseConst.do_something + # good while node.is_a?(BeginNode) node = node.parent @@ -28,3 +45,27 @@ because `NilClass` has methods like `respond_to?` and `is_a?`. # good - without `&.` this will always return `true` foo&.respond_to?(:to_a) + + # bad - for `nil`s conversion methods return default values for the type + foo&.to_h || {} + foo&.to_h { |k, v| [k, v] } || {} + foo&.to_a || [] + foo&.to_i || 0 + foo&.to_f || 0.0 + foo&.to_s || '' + + # good + foo.to_h + foo.to_h { |k, v| [k, v] } + foo.to_a + foo.to_i + foo.to_f + foo.to_s + +### Example: AllowedMethods: [nil_safe_method] + # bad + do_something if attrs&.nil_safe_method(:[]) + + # good + do_something if attrs.nil_safe_method(:[]) + do_something if attrs&.not_nil_safe_method(:[]) diff --git a/config/contents/lint/redundant_splat_expansion.md b/config/contents/lint/redundant_splat_expansion.md index f4b447f9..5a610991 100644 --- a/config/contents/lint/redundant_splat_expansion.md +++ b/config/contents/lint/redundant_splat_expansion.md @@ -1,4 +1,4 @@ -This cop checks for unneeded usages of splat expansion +Checks for unneeded usages of splat expansion ### Example: diff --git a/config/contents/lint/redundant_string_coercion.md b/config/contents/lint/redundant_string_coercion.md index 49db53fa..793ab5ea 100644 --- a/config/contents/lint/redundant_string_coercion.md +++ b/config/contents/lint/redundant_string_coercion.md @@ -1,4 +1,4 @@ -This cop checks for string conversion in string interpolation, +Checks for string conversion in string interpolation, `print`, `puts`, and `warn` arguments, which is redundant. ### Example: @@ -6,9 +6,15 @@ which is redundant. # bad "result is #{something.to_s}" + print something.to_s + puts something.to_s + warn something.to_s ### Example: # good - "result is #{something}" \ No newline at end of file + "result is #{something}" + print something + puts something + warn something diff --git a/config/contents/lint/redundant_with_index.md b/config/contents/lint/redundant_with_index.md index 3dc86d07..ffe5c4ed 100644 --- a/config/contents/lint/redundant_with_index.md +++ b/config/contents/lint/redundant_with_index.md @@ -1,4 +1,4 @@ -This cop checks for redundant `with_index`. +Checks for redundant `with_index`. ### Example: # bad diff --git a/config/contents/lint/redundant_with_object.md b/config/contents/lint/redundant_with_object.md index 4a9ef4ae..8d8eab98 100644 --- a/config/contents/lint/redundant_with_object.md +++ b/config/contents/lint/redundant_with_object.md @@ -1,4 +1,4 @@ -This cop checks for redundant `with_object`. +Checks for redundant `with_object`. ### Example: # bad diff --git a/config/contents/lint/refinement_import_methods.md b/config/contents/lint/refinement_import_methods.md new file mode 100644 index 00000000..b4c7bae5 --- /dev/null +++ b/config/contents/lint/refinement_import_methods.md @@ -0,0 +1,27 @@ +Checks if `include` or `prepend` is called in `refine` block. +These methods are deprecated and should be replaced with `Refinement#import_methods`. + +It emulates deprecation warnings in Ruby 3.1. + +@safety + This cop's autocorrection is unsafe because `include M` will affect the included class + if any changes are made to module `M`. + On the other hand, `import_methods M` uses a snapshot of method definitions, + thus it will not be affected if module `M` changes. + +### Example: + + # bad + refine Foo do + include Bar + end + + # bad + refine Foo do + prepend Bar + end + + # good + refine Foo do + import_methods Bar + end diff --git a/config/contents/lint/regexp_as_condition.md b/config/contents/lint/regexp_as_condition.md index 7f74c7ea..7a4ea08f 100644 --- a/config/contents/lint/regexp_as_condition.md +++ b/config/contents/lint/regexp_as_condition.md @@ -1,4 +1,4 @@ -This cop checks for regexp literals used as `match-current-line`. +Checks for regexp literals used as `match-current-line`. If a regexp literal is in condition, the regexp matches `$_` implicitly. ### Example: diff --git a/config/contents/lint/require_parentheses.md b/config/contents/lint/require_parentheses.md index f529fc88..bf196364 100644 --- a/config/contents/lint/require_parentheses.md +++ b/config/contents/lint/require_parentheses.md @@ -1,4 +1,4 @@ -This cop checks for expressions where there is a call to a predicate +Checks for expressions where there is a call to a predicate method with at least one argument, where no parentheses are used around the parameter list, and a boolean operator, && or ||, is used in the last argument. diff --git a/config/contents/lint/require_range_parentheses.md b/config/contents/lint/require_range_parentheses.md new file mode 100644 index 00000000..bdd308e1 --- /dev/null +++ b/config/contents/lint/require_range_parentheses.md @@ -0,0 +1,33 @@ +Checks that a range literal is enclosed in parentheses when the end of the range is +at a line break. + +NOTE: The following is maybe intended for `(42..)`. But, compatible is `42..do_something`. +So, this cop does not provide autocorrection because it is left to user. + +[source,ruby] +---- +case condition +when 42.. + do_something +end +---- + +### Example: + + # bad - Represents `(1..42)`, not endless range. + 1.. + 42 + + # good - It's incompatible, but your intentions when using endless range may be: + (1..) + 42 + + # good + 1..42 + + # good + (1..42) + + # good + (1.. + 42) diff --git a/config/contents/lint/require_relative_self_path.md b/config/contents/lint/require_relative_self_path.md new file mode 100644 index 00000000..73b6f579 --- /dev/null +++ b/config/contents/lint/require_relative_self_path.md @@ -0,0 +1,14 @@ +Checks for uses a file requiring itself with `require_relative`. + +### Example: + + # bad + + # foo.rb + require_relative 'foo' + require_relative 'bar' + + # good + + # foo.rb + require_relative 'bar' diff --git a/config/contents/lint/rescue_exception.md b/config/contents/lint/rescue_exception.md index aa5ef0bb..ec975aff 100644 --- a/config/contents/lint/rescue_exception.md +++ b/config/contents/lint/rescue_exception.md @@ -1,4 +1,4 @@ -This cop checks for `rescue` blocks targeting the Exception class. +Checks for `rescue` blocks targeting the Exception class. ### Example: diff --git a/config/contents/lint/return_in_void_context.md b/config/contents/lint/return_in_void_context.md index 3c378996..eb9fd809 100644 --- a/config/contents/lint/return_in_void_context.md +++ b/config/contents/lint/return_in_void_context.md @@ -1,4 +1,4 @@ -This cop checks for the use of a return with a value in a context +Checks for the use of a return with a value in a context where the value will be ignored. (initialize and setter methods) ### Example: diff --git a/config/contents/lint/safe_navigation_consistency.md b/config/contents/lint/safe_navigation_consistency.md index 754ef793..7d5e51bd 100644 --- a/config/contents/lint/safe_navigation_consistency.md +++ b/config/contents/lint/safe_navigation_consistency.md @@ -1,4 +1,4 @@ -This cop check to make sure that if safe navigation is used for a method +Check to make sure that if safe navigation is used for a method call in an `&&` or `||` condition that safe navigation is used for all method calls on that same object. diff --git a/config/contents/lint/safe_navigation_with_empty.md b/config/contents/lint/safe_navigation_with_empty.md index 9f53375f..dc00219d 100644 --- a/config/contents/lint/safe_navigation_with_empty.md +++ b/config/contents/lint/safe_navigation_with_empty.md @@ -1,4 +1,4 @@ -This cop checks to make sure safe navigation isn't used with `empty?` in +Checks to make sure safe navigation isn't used with `empty?` in a conditional. While the safe navigation operator is generally a good idea, when diff --git a/config/contents/lint/script_permission.md b/config/contents/lint/script_permission.md index afb90245..d3463a32 100644 --- a/config/contents/lint/script_permission.md +++ b/config/contents/lint/script_permission.md @@ -1,4 +1,4 @@ -This cop checks if a file which has a shebang line as +Checks if a file which has a shebang line as its first line is granted execute permission. ### Example: diff --git a/config/contents/lint/self_assignment.md b/config/contents/lint/self_assignment.md index 00ac3b6d..ab8bc3be 100644 --- a/config/contents/lint/self_assignment.md +++ b/config/contents/lint/self_assignment.md @@ -1,12 +1,19 @@ -This cop checks for self-assignments. +Checks for self-assignments. ### Example: # bad foo = foo foo, bar = foo, bar Foo = Foo + hash['foo'] = hash['foo'] + obj.attr = obj.attr # good foo = bar foo, bar = bar, foo Foo = Bar + hash['foo'] = hash['bar'] + obj.attr = obj.attr2 + + # good (method calls possibly can return different results) + hash[foo] = hash[foo] diff --git a/config/contents/lint/send_with_mixin_argument.md b/config/contents/lint/send_with_mixin_argument.md index 47547f7d..c0e59e69 100644 --- a/config/contents/lint/send_with_mixin_argument.md +++ b/config/contents/lint/send_with_mixin_argument.md @@ -1,5 +1,4 @@ - -This cop checks for `send`, `public_send`, and `__send__` methods +Checks for `send`, `public_send`, and `__send__` methods when using mix-in. `include` and `prepend` methods were private methods until Ruby 2.0, diff --git a/config/contents/lint/shadowed_argument.md b/config/contents/lint/shadowed_argument.md index 58e43a5d..b0332e8e 100644 --- a/config/contents/lint/shadowed_argument.md +++ b/config/contents/lint/shadowed_argument.md @@ -1,4 +1,4 @@ -This cop checks for shadowed arguments. +Checks for shadowed arguments. This cop has `IgnoreImplicitReferences` configuration option. It means argument shadowing is used in order to pass parameters diff --git a/config/contents/lint/shadowed_exception.md b/config/contents/lint/shadowed_exception.md index 83241b30..f2bae093 100644 --- a/config/contents/lint/shadowed_exception.md +++ b/config/contents/lint/shadowed_exception.md @@ -1,7 +1,15 @@ -This cop checks for a rescued exception that get shadowed by a +Checks for a rescued exception that get shadowed by a less specific exception being rescued before a more specific exception is rescued. +An exception is considered shadowed if it is rescued after its +ancestor is, or if it and its ancestor are both rescued in the +same `rescue` statement. In both cases, the more specific rescue is +unnecessary because it is covered by rescuing the less specific +exception. (ie. `rescue Exception, StandardError` has the same behavior +whether `StandardError` is included or not, because all ``StandardError``s +are rescued by `rescue Exception`). + ### Example: # bad @@ -14,6 +22,13 @@ exception is rescued. handle_standard_error end + # bad + begin + something + rescue Exception, StandardError + handle_error + end + # good begin diff --git a/config/contents/lint/shadowing_outer_local_variable.md b/config/contents/lint/shadowing_outer_local_variable.md index 6581f7f8..4417fa67 100644 --- a/config/contents/lint/shadowing_outer_local_variable.md +++ b/config/contents/lint/shadowing_outer_local_variable.md @@ -1,15 +1,18 @@ -This cop checks for the use of local variable names from an outer scope +Checks for the use of local variable names from an outer scope in block arguments or block-local variables. This mirrors the warning given by `ruby -cw` prior to Ruby 2.6: "shadowing outer local variable - foo". NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed because `Ractor` should not access outer variables. -eg. following syle is encouraged: +eg. following style is encouraged: + [source,ruby] + ---- worker_id, pipe = env Ractor.new(worker_id, pipe) do |worker_id, pipe| end + ---- ### Example: diff --git a/config/contents/lint/struct_new_override.md b/config/contents/lint/struct_new_override.md index ea464c1b..e529f05c 100644 --- a/config/contents/lint/struct_new_override.md +++ b/config/contents/lint/struct_new_override.md @@ -1,4 +1,4 @@ -This cop checks unexpected overrides of the `Struct` built-in methods +Checks unexpected overrides of the `Struct` built-in methods via `Struct.new`. ### Example: diff --git a/config/contents/lint/suppressed_exception.md b/config/contents/lint/suppressed_exception.md index 8ea6e003..8bbdf428 100644 --- a/config/contents/lint/suppressed_exception.md +++ b/config/contents/lint/suppressed_exception.md @@ -1,4 +1,4 @@ -This cop checks for `rescue` blocks with no body. +Checks for `rescue` blocks with no body. ### Example: diff --git a/config/contents/lint/symbol_conversion.md b/config/contents/lint/symbol_conversion.md index 60877e3c..1127f1ac 100644 --- a/config/contents/lint/symbol_conversion.md +++ b/config/contents/lint/symbol_conversion.md @@ -1,4 +1,4 @@ -This cop checks for uses of literal strings converted to +Checks for uses of literal strings converted to a symbol where a literal symbol could be used instead. There are two possible styles for this cop. @@ -14,6 +14,7 @@ all keys to be quoted). 'underscored_string'.to_sym :'underscored_symbol' 'hyphenated-string'.to_sym + "string_#{interpolation}".to_sym # good :string @@ -21,6 +22,7 @@ all keys to be quoted). :underscored_string :underscored_symbol :'hyphenated-string' + :"string_#{interpolation}" ### Example: EnforcedStyle: strict (default) diff --git a/config/contents/lint/to_enum_arguments.md b/config/contents/lint/to_enum_arguments.md index d647a9dc..394f4ffc 100644 --- a/config/contents/lint/to_enum_arguments.md +++ b/config/contents/lint/to_enum_arguments.md @@ -1,4 +1,4 @@ -This cop ensures that `to_enum`/`enum_for`, called for the current method, +Ensures that `to_enum`/`enum_for`, called for the current method, has correct arguments. ### Example: @@ -9,6 +9,12 @@ has correct arguments. # good def foo(x, y = 1) + # Alternatives to `__callee__` are `__method__` and `:foo`. return to_enum(__callee__, x, y) - # alternatives to `__callee__` are `__method__` and `:foo` + end + + # good + def foo(x, y = 1) + # It is also allowed if it is wrapped in some method like Sorbet. + return to_enum(T.must(__callee__), x, y) end diff --git a/config/contents/lint/to_json.md b/config/contents/lint/to_json.md index 5e5648d9..5c3b90d8 100644 --- a/config/contents/lint/to_json.md +++ b/config/contents/lint/to_json.md @@ -1,4 +1,4 @@ -This cop checks to make sure `#to_json` includes an optional argument. +Checks to make sure `#to_json` includes an optional argument. When overriding `#to_json`, callers may invoke JSON generation via `JSON.generate(your_obj)`. Since `JSON#generate` allows for an optional argument, your method should too. diff --git a/config/contents/lint/top_level_return_with_argument.md b/config/contents/lint/top_level_return_with_argument.md index 4e34576b..35f8ce5e 100644 --- a/config/contents/lint/top_level_return_with_argument.md +++ b/config/contents/lint/top_level_return_with_argument.md @@ -1,8 +1,10 @@ -This cop checks for top level return with arguments. If there is a +Checks for top level return with arguments. If there is a top-level return statement with an argument, then the argument is always ignored. This is detected automatically since Ruby 2.7. ### Example: + # bad + return 1 - # Detected since Ruby 2.7 - return 1 # 1 is always ignored. \ No newline at end of file + # good + return \ No newline at end of file diff --git a/config/contents/lint/trailing_comma_in_attribute_declaration.md b/config/contents/lint/trailing_comma_in_attribute_declaration.md index fef3f861..62a59d63 100644 --- a/config/contents/lint/trailing_comma_in_attribute_declaration.md +++ b/config/contents/lint/trailing_comma_in_attribute_declaration.md @@ -1,4 +1,4 @@ -This cop checks for trailing commas in attribute declarations, such as +Checks for trailing commas in attribute declarations, such as `#attr_reader`. Leaving a trailing comma will nullify the next method definition by overriding it with a getter method. diff --git a/config/contents/lint/triple_quotes.md b/config/contents/lint/triple_quotes.md index 239fbe17..750a5cde 100644 --- a/config/contents/lint/triple_quotes.md +++ b/config/contents/lint/triple_quotes.md @@ -1,4 +1,4 @@ -This cop checks for "triple quotes" (strings delimted by any odd number +Checks for "triple quotes" (strings delimited by any odd number of quotes greater than 1). Ruby allows multiple strings to be implicitly concatenated by just diff --git a/config/contents/lint/underscore_prefixed_variable_name.md b/config/contents/lint/underscore_prefixed_variable_name.md index f01785da..a7cba725 100644 --- a/config/contents/lint/underscore_prefixed_variable_name.md +++ b/config/contents/lint/underscore_prefixed_variable_name.md @@ -1,4 +1,4 @@ -This cop checks for underscore-prefixed variables that are actually +Checks for underscore-prefixed variables that are actually used. Since block keyword arguments cannot be arbitrarily named at call diff --git a/config/contents/lint/unexpected_block_arity.md b/config/contents/lint/unexpected_block_arity.md index 54552b7f..6f46514f 100644 --- a/config/contents/lint/unexpected_block_arity.md +++ b/config/contents/lint/unexpected_block_arity.md @@ -1,4 +1,4 @@ -This cop checks for a block that is known to need more positional +Checks for a block that is known to need more positional block arguments than are given (by default this is configured for `Enumerable` methods needing 2 arguments). Optional arguments are allowed, although they don't generally make sense as the default value will @@ -8,14 +8,19 @@ be used. Blocks that have no receiver, or take splatted arguments Keyword arguments (including `**kwargs`) do not get counted towards this, as they are not used by the methods in question. -NOTE: This cop matches for method names only and hence cannot tell apart -methods with same name in different classes. - Method names and their expected arity can be configured like this: +[source,yaml] +---- Methods: inject: 2 reduce: 2 +---- + +@safety + This cop matches for method names only and hence cannot tell apart + methods with same name in different classes, which may lead to a + false positive. ### Example: # bad diff --git a/config/contents/lint/unified_integer.md b/config/contents/lint/unified_integer.md index b8b2ac73..71005cd9 100644 --- a/config/contents/lint/unified_integer.md +++ b/config/contents/lint/unified_integer.md @@ -1,4 +1,4 @@ -This cop checks for using Fixnum or Bignum constant. +Checks for using Fixnum or Bignum constant. ### Example: diff --git a/config/contents/lint/unreachable_code.md b/config/contents/lint/unreachable_code.md index b212c62f..3af20b6b 100644 --- a/config/contents/lint/unreachable_code.md +++ b/config/contents/lint/unreachable_code.md @@ -1,4 +1,4 @@ -This cop checks for unreachable code. +Checks for unreachable code. The check are based on the presence of flow of control statement in non-final position in `begin` (implicit) blocks. diff --git a/config/contents/lint/unreachable_loop.md b/config/contents/lint/unreachable_loop.md index 5545d009..c635f9c5 100644 --- a/config/contents/lint/unreachable_loop.md +++ b/config/contents/lint/unreachable_loop.md @@ -1,12 +1,12 @@ -This cop checks for loops that will have at most one iteration. +Checks for loops that will have at most one iteration. A loop that can never reach the second iteration is a possible error in the code. In rare cases where only one iteration (or at most one iteration) is intended behavior, the code should be refactored to use `if` conditionals. -NOTE: Block methods that are used with `Enumerable`s are considered to be loops. +NOTE: Block methods that are used with ``Enumerable``s are considered to be loops. -`IgnoredPatterns` can be used to match against the block receiver in order to allow +`AllowedPatterns` can be used to match against the block receiver in order to allow code that would otherwise be registered as an offense (eg. `times` used not in an `Enumerable` context). @@ -74,7 +74,7 @@ code that would otherwise be registered as an offense (eg. `times` used not in a # bad 2.times { raise ArgumentError } -### Example: IgnoredPatterns: [/(exactly|at_least|at_most)\(\d+\)\.times/] (default) +### Example: AllowedPatterns: ['(exactly|at_least|at_most)\(\d+\)\.times'] (default) # good exactly(2).times { raise StandardError } \ No newline at end of file diff --git a/config/contents/lint/unused_block_argument.md b/config/contents/lint/unused_block_argument.md index d01856a9..62afb29e 100644 --- a/config/contents/lint/unused_block_argument.md +++ b/config/contents/lint/unused_block_argument.md @@ -1,4 +1,4 @@ -This cop checks for unused block arguments. +Checks for unused block arguments. ### Example: # bad diff --git a/config/contents/lint/unused_method_argument.md b/config/contents/lint/unused_method_argument.md index 25fdba55..473f2ca3 100644 --- a/config/contents/lint/unused_method_argument.md +++ b/config/contents/lint/unused_method_argument.md @@ -1,4 +1,4 @@ -This cop checks for unused method arguments. +Checks for unused method arguments. ### Example: # bad diff --git a/config/contents/lint/uri_escape_unescape.md b/config/contents/lint/uri_escape_unescape.md index a9550b51..aa140ac7 100644 --- a/config/contents/lint/uri_escape_unescape.md +++ b/config/contents/lint/uri_escape_unescape.md @@ -1,4 +1,4 @@ -This cop identifies places where `URI.escape` can be replaced by +Identifies places where `URI.escape` can be replaced by `CGI.escape`, `URI.encode_www_form`, or `URI.encode_www_form_component` depending on your specific use case. Also this cop identifies places where `URI.unescape` can be replaced by diff --git a/config/contents/lint/uri_regexp.md b/config/contents/lint/uri_regexp.md index 269f95eb..dfd29c3b 100644 --- a/config/contents/lint/uri_regexp.md +++ b/config/contents/lint/uri_regexp.md @@ -1,4 +1,4 @@ -This cop identifies places where `URI.regexp` is obsolete and should +Identifies places where `URI.regexp` is obsolete and should not be used. Instead, use `URI::DEFAULT_PARSER.make_regexp`. ### Example: diff --git a/config/contents/lint/useless_access_modifier.md b/config/contents/lint/useless_access_modifier.md index 0ffadaed..8d99d94e 100644 --- a/config/contents/lint/useless_access_modifier.md +++ b/config/contents/lint/useless_access_modifier.md @@ -1,4 +1,4 @@ -This cop checks for redundant access modifiers, including those with no +Checks for redundant access modifiers, including those with no code, those which are repeated, and leading `public` modifiers in a class or module body. Conditionally-defined methods are considered as always being defined, and thus access modifiers guarding such methods @@ -26,8 +26,8 @@ create other methods in the module's current access context. # bad class Foo # The following is redundant (methods defined on the class' - # singleton class are not affected by the public modifier) - public + # singleton class are not affected by the private modifier) + private def self.method3 end diff --git a/config/contents/lint/useless_assignment.md b/config/contents/lint/useless_assignment.md index 2ed8d7e2..74804774 100644 --- a/config/contents/lint/useless_assignment.md +++ b/config/contents/lint/useless_assignment.md @@ -1,13 +1,25 @@ -This cop checks for every useless assignment to local variable in every +Checks for every useless assignment to local variable in every scope. The basic idea for this cop was from the warning of `ruby -cw`: - assigned but unused variable - foo +[source,console] +---- +assigned but unused variable - foo +---- Currently this cop has advanced logic that detects unreferenced reassignments and properly handles varied cases such as branch, loop, rescue, ensure, etc. +NOTE: Given the assignment `foo = 1, bar = 2`, removing unused variables +can lead to a syntax error, so this case is not autocorrected. + +@safety + This cop's autocorrection is unsafe because removing assignment from + operator assignment can cause NameError if this assignment has been used to declare + local variable. For example, replacing `a ||= 1` to `a || 1` may cause + "undefined local variable or method `a' for main:Object (NameError)". + ### Example: # bad diff --git a/config/contents/lint/useless_else_without_rescue.md b/config/contents/lint/useless_else_without_rescue.md index 3601d103..12fdf021 100644 --- a/config/contents/lint/useless_else_without_rescue.md +++ b/config/contents/lint/useless_else_without_rescue.md @@ -1,7 +1,6 @@ -This cop checks for useless `else` in `begin..end` without `rescue`. +Checks for useless `else` in `begin..end` without `rescue`. -NOTE: This syntax is no longer valid on Ruby 2.6 or higher and -this cop is going to be removed at some point the future. +NOTE: This syntax is no longer valid on Ruby 2.6 or higher. ### Example: diff --git a/config/contents/lint/useless_method_definition.md b/config/contents/lint/useless_method_definition.md index 581023b6..f3724fa3 100644 --- a/config/contents/lint/useless_method_definition.md +++ b/config/contents/lint/useless_method_definition.md @@ -1,8 +1,9 @@ -This cop checks for useless method definitions, specifically: empty constructors +Checks for useless method definitions, specifically: empty constructors and methods just delegating to `super`. -This cop is marked as unsafe as it can trigger false positives for cases when -an empty constructor just overrides the parent constructor, which is bad anyway. +@safety + This cop is unsafe as it can register false positives for cases when an empty + constructor just overrides the parent constructor, which is bad anyway. ### Example: # bad diff --git a/config/contents/lint/useless_rescue.md b/config/contents/lint/useless_rescue.md new file mode 100644 index 00000000..acf46bec --- /dev/null +++ b/config/contents/lint/useless_rescue.md @@ -0,0 +1,42 @@ +Checks for useless `rescue`s, which only reraise rescued exceptions. + +### Example: + # bad + def foo + do_something + rescue + raise + end + + # bad + def foo + do_something + rescue => e + raise # or 'raise e', or 'raise $!', or 'raise $ERROR_INFO' + end + + # good + def foo + do_something + rescue + do_cleanup + raise + end + + # bad (latest rescue) + def foo + do_something + rescue ArgumentError + # noop + rescue + raise + end + + # good (not the latest rescue) + def foo + do_something + rescue ArgumentError + raise + rescue + # noop + end diff --git a/config/contents/lint/useless_ruby2_keywords.md b/config/contents/lint/useless_ruby2_keywords.md new file mode 100644 index 00000000..2da4e42a --- /dev/null +++ b/config/contents/lint/useless_ruby2_keywords.md @@ -0,0 +1,59 @@ +Looks for `ruby2_keywords` calls for methods that do not need it. + +`ruby2_keywords` should only be called on methods that accept an argument splat +(`\*args`) but do not explicit keyword arguments (`k:` or `k: true`) or +a keyword splat (`**kwargs`). + +### Example: + # good (splat argument without keyword arguments) + ruby2_keywords def foo(*args); end + + # bad (no arguments) + ruby2_keywords def foo; end + + # good + def foo; end + + # bad (positional argument) + ruby2_keywords def foo(arg); end + + # good + def foo(arg); end + + # bad (double splatted argument) + ruby2_keywords def foo(**args); end + + # good + def foo(**args); end + + # bad (keyword arguments) + ruby2_keywords def foo(i:, j:); end + + # good + def foo(i:, j:); end + + # bad (splat argument with keyword arguments) + ruby2_keywords def foo(*args, i:, j:); end + + # good + def foo(*args, i:, j:); end + + # bad (splat argument with double splat) + ruby2_keywords def foo(*args, **kwargs); end + + # good + def foo(*args, **kwargs); end + + # bad (ruby2_keywords given a symbol) + def foo; end + ruby2_keywords :foo + + # good + def foo; end + + # bad (ruby2_keywords with dynamic method) + define_method(:foo) { |arg| } + ruby2_keywords :foo + + # good + define_method(:foo) { |arg| } diff --git a/config/contents/lint/useless_setter_call.md b/config/contents/lint/useless_setter_call.md index e508a164..f21b7309 100644 --- a/config/contents/lint/useless_setter_call.md +++ b/config/contents/lint/useless_setter_call.md @@ -1,10 +1,13 @@ -This cop checks for setter call to local variable as the final +Checks for setter call to local variable as the final expression of a function definition. -Its auto-correction is marked as unsafe because return value will be changed. -NOTE: There are edge cases in which the local variable references a -value that is also accessible outside the local scope. This is not -detected by the cop, and it can yield a false positive. +@safety + There are edge cases in which the local variable references a + value that is also accessible outside the local scope. This is not + detected by the cop, and it can yield a false positive. + + As well, autocorrection is unsafe because the method's + return value will be changed. ### Example: diff --git a/config/contents/lint/useless_times.md b/config/contents/lint/useless_times.md index 85504660..f8c43c35 100644 --- a/config/contents/lint/useless_times.md +++ b/config/contents/lint/useless_times.md @@ -1,9 +1,10 @@ -This cop checks for uses of `Integer#times` that will never yield -(when the integer <= 0) or that will only ever yield once +Checks for uses of `Integer#times` that will never yield +(when the integer ``<= 0``) or that will only ever yield once (`1.times`). -This cop is marked as unsafe as `times` returns its receiver, which -is *usually* OK, but might change behavior. +@safety + This cop is unsafe as `times` returns its receiver, which is + *usually* OK, but might change behavior. ### Example: # bad diff --git a/config/contents/lint/void.md b/config/contents/lint/void.md index 26d17736..cf7c3402 100644 --- a/config/contents/lint/void.md +++ b/config/contents/lint/void.md @@ -1,6 +1,16 @@ -This cop checks for operators, variables, literals, and nonmutating +Checks for operators, variables, literals, lambda, proc and nonmutating methods used in void context. +`each` blocks are allowed to prevent false positives. +For example, the expression inside the `each` block below. +It's not void, especially when the receiver is an `Enumerator`: + +[source,ruby] +---- +enumerator = [1, 2, 3].filter +enumerator.each { |item| item >= 2 } #=> [2, 3] +---- + ### Example: CheckForMethodsWithNoSideEffects: false (default) # bad def some_method diff --git a/config/contents/naming/accessor_method_name.md b/config/contents/naming/accessor_method_name.md index 855ba74e..327cf230 100644 --- a/config/contents/naming/accessor_method_name.md +++ b/config/contents/naming/accessor_method_name.md @@ -1,4 +1,4 @@ -This cop makes sure that accessor methods are named properly. Applies +Makes sure that accessor methods are named properly. Applies to both instance and class methods. NOTE: Offenses are only registered for methods with the expected diff --git a/config/contents/naming/ascii_identifiers.md b/config/contents/naming/ascii_identifiers.md index 882a6e67..b134b522 100644 --- a/config/contents/naming/ascii_identifiers.md +++ b/config/contents/naming/ascii_identifiers.md @@ -1,4 +1,4 @@ -This cop checks for non-ascii characters in identifier and constant names. +Checks for non-ascii characters in identifier and constant names. Identifiers are always checked and whether constants are checked can be controlled using AsciiConstants config. diff --git a/config/contents/naming/binary_operator_parameter_name.md b/config/contents/naming/binary_operator_parameter_name.md index 9e79384a..c1cb79c9 100644 --- a/config/contents/naming/binary_operator_parameter_name.md +++ b/config/contents/naming/binary_operator_parameter_name.md @@ -1,4 +1,4 @@ -This cop makes sure that certain binary operator methods have their +Makes sure that certain binary operator methods have their sole parameter named `other`. ### Example: diff --git a/config/contents/naming/block_forwarding.md b/config/contents/naming/block_forwarding.md new file mode 100644 index 00000000..f50c0457 --- /dev/null +++ b/config/contents/naming/block_forwarding.md @@ -0,0 +1,33 @@ +In Ruby 3.1, anonymous block forwarding has been added. + +This cop identifies places where `do_something(&block)` can be replaced +by `do_something(&)`. + +It also supports the opposite style by alternative `explicit` option. +You can specify the block variable name for autocorrection with `BlockForwardingName`. +The default variable name is `block`. If the name is already in use, it will not be +autocorrected. + +### Example: EnforcedStyle: anonymous (default) + + # bad + def foo(&block) + bar(&block) + end + + # good + def foo(&) + bar(&) + end + +### Example: EnforcedStyle: explicit + + # bad + def foo(&) + bar(&) + end + + # good + def foo(&block) + bar(&block) + end diff --git a/config/contents/naming/block_parameter_name.md b/config/contents/naming/block_parameter_name.md index 83fdea44..7b4a2aa9 100644 --- a/config/contents/naming/block_parameter_name.md +++ b/config/contents/naming/block_parameter_name.md @@ -1,4 +1,4 @@ -This cop checks block parameter names for how descriptive they +Checks block parameter names for how descriptive they are. It is highly configurable. The `MinNameLength` config option takes an integer. It represents @@ -19,7 +19,7 @@ restricted names that will always register an offense. # With `AllowNamesEndingInNumbers` set to false foo { |num1, num2| num1 * num2 } - # With `MinParamNameLength` set to number greater than 1 + # With `MinNameLength` set to number greater than 1 baz { |a, b, c| do_stuff(a, b, c) } # good diff --git a/config/contents/naming/class_and_module_camel_case.md b/config/contents/naming/class_and_module_camel_case.md index 049451b0..a310fd99 100644 --- a/config/contents/naming/class_and_module_camel_case.md +++ b/config/contents/naming/class_and_module_camel_case.md @@ -1,4 +1,4 @@ -This cop checks for class and module names with +Checks for class and module names with an underscore in them. `AllowedNames` config takes an array of permitted names. diff --git a/config/contents/naming/constant_name.md b/config/contents/naming/constant_name.md index 8f3ed2a4..e00063ae 100644 --- a/config/contents/naming/constant_name.md +++ b/config/contents/naming/constant_name.md @@ -1,4 +1,4 @@ -This cop checks whether constant names are written using +Checks whether constant names are written using SCREAMING_SNAKE_CASE. To avoid false positives, it ignores cases in which we cannot know diff --git a/config/contents/naming/file_name.md b/config/contents/naming/file_name.md index b6b9e260..617a8860 100644 --- a/config/contents/naming/file_name.md +++ b/config/contents/naming/file_name.md @@ -1,4 +1,4 @@ -This cop makes sure that Ruby source files have snake_case +Makes sure that Ruby source files have snake_case names. Ruby scripts (i.e. source files with a shebang in the first line) are ignored. @@ -7,6 +7,18 @@ recommends using dashes to separate namespaces in nested gems (i.e. `bundler-console` becomes `Bundler::Console`). As such, the gemspec is supposed to be named `bundler-console.gemspec`. +When `ExpectMatchingDefinition` (default: `false`) is `true`, the cop requires +each file to have a class, module or `Struct` defined in it that matches +the filename. This can be further configured using +`CheckDefinitionPathHierarchy` (default: `true`) to determine whether the +path should match the namespace of the above definition. + +When `IgnoreExecutableScripts` (default: `true`) is `true`, files that start +with a shebang line are not considered by the cop. + +When `Regex` is set, the cop will flag any filename that does not match +the regular expression. + ### Example: # bad lib/layoutManager.rb diff --git a/config/contents/naming/heredoc_delimiter_case.md b/config/contents/naming/heredoc_delimiter_case.md index 666c35ec..03a0996a 100644 --- a/config/contents/naming/heredoc_delimiter_case.md +++ b/config/contents/naming/heredoc_delimiter_case.md @@ -1,4 +1,4 @@ -This cop checks that your heredocs are using the configured case. +Checks that your heredocs are using the configured case. By default it is configured to enforce uppercase heredocs. ### Example: EnforcedStyle: uppercase (default) diff --git a/config/contents/naming/heredoc_delimiter_naming.md b/config/contents/naming/heredoc_delimiter_naming.md index 1f4ae125..d5a84bea 100644 --- a/config/contents/naming/heredoc_delimiter_naming.md +++ b/config/contents/naming/heredoc_delimiter_naming.md @@ -1,4 +1,4 @@ -This cop checks that your heredocs are using meaningful delimiters. +Checks that your heredocs are using meaningful delimiters. By default it disallows `END` and `EO*`, and can be configured through forbidden listing additional delimiters. diff --git a/config/contents/naming/inclusive_language.md b/config/contents/naming/inclusive_language.md index e6fdf827..0f649ce4 100644 --- a/config/contents/naming/inclusive_language.md +++ b/config/contents/naming/inclusive_language.md @@ -1,5 +1,6 @@ -This cops recommends the use of inclusive language instead of problematic terms. +Recommends the use of inclusive language instead of problematic terms. The cop can check the following locations for offenses: + - identifiers - constants - variables @@ -7,6 +8,7 @@ The cop can check the following locations for offenses: - symbols - comments - file paths + Each of these locations can be individually enabled/disabled via configuration, for example CheckIdentifiers = true/false. @@ -14,6 +16,11 @@ Flagged terms are configurable for the cop. For each flagged term an optional Regex can be specified to identify offenses. Suggestions for replacing a flagged term can be configured and will be displayed as part of the offense message. An AllowedRegex can be specified for a flagged term to exempt allowed uses of the term. +`WholeWord: true` can be set on a flagged term to indicate the cop should only match when +a term matches the whole word (partial matches will not be offenses). + +The cop supports autocorrection when there is only one suggestion. When there are multiple +suggestions, the best suggestion cannot be identified and will not be autocorrected. ### Example: FlaggedTerms: { whitelist: { Suggestions: ['allowlist'] } } # Suggest replacing identifier whitelist with allowlist @@ -50,3 +57,12 @@ An AllowedRegex can be specified for a flagged term to exempt allowed uses of th # good # They had a master's degree + +### Example: FlaggedTerms: { slave: { WholeWord: true } } + # Specify that only terms that are full matches will be flagged. + + # bad + Slave + + # good (won't be flagged despite containing `slave`) + TeslaVehicle \ No newline at end of file diff --git a/config/contents/naming/memoized_instance_variable_name.md b/config/contents/naming/memoized_instance_variable_name.md index 33aeda87..b4f6116a 100644 --- a/config/contents/naming/memoized_instance_variable_name.md +++ b/config/contents/naming/memoized_instance_variable_name.md @@ -1,4 +1,4 @@ -This cop checks for memoized methods whose instance variable name +Checks for memoized methods whose instance variable name does not match the method name. Applies to both regular methods (defined with `def`) and dynamic methods (defined with `define_method` or `define_singleton_method`). @@ -9,6 +9,12 @@ prefixed with an underscore. Prefixing ivars with an underscore is a convention that is used to implicitly indicate that an ivar should not be set or referenced outside of the memoization method. +@safety + This cop relies on the pattern `@instance_var ||= ...`, + but this is sometimes used for other purposes than memoization + so this cop is considered unsafe. Also, its autocorrection is unsafe + because it may conflict with instance variable names already in use. + ### Example: EnforcedStyleForLeadingUnderscores: disallowed (default) # bad # Method foo is memoized using an instance variable that is @@ -133,8 +139,4 @@ be set or referenced outside of the memoization method. # good define_method(:foo) do @_foo ||= calculate_expensive_thing - end - -This cop relies on the pattern `@instance_var ||= ...`, -but this is sometimes used for other purposes than memoization -so this cop is considered unsafe. \ No newline at end of file + end \ No newline at end of file diff --git a/config/contents/naming/method_name.md b/config/contents/naming/method_name.md index 6180eff0..097746de 100644 --- a/config/contents/naming/method_name.md +++ b/config/contents/naming/method_name.md @@ -1,12 +1,12 @@ -This cop makes sure that all methods use the configured style, +Makes sure that all methods use the configured style, snake_case or camelCase, for their names. -This cop has `IgnoredPatterns` configuration option. +This cop has `AllowedPatterns` configuration option. Naming/MethodName: - IgnoredPatterns: - - '\A\s*onSelectionBulkChange\s*' - - '\A\s*onSelectionCleared\s*' + AllowedPatterns: + - '\AonSelectionBulkChange\z' + - '\AonSelectionCleared\z' Method names matching patterns are always allowed. diff --git a/config/contents/naming/method_parameter_name.md b/config/contents/naming/method_parameter_name.md index 7200c3c5..6ef7977c 100644 --- a/config/contents/naming/method_parameter_name.md +++ b/config/contents/naming/method_parameter_name.md @@ -1,4 +1,4 @@ -This cop checks method parameter names for how descriptive they +Checks method parameter names for how descriptive they are. It is highly configurable. The `MinNameLength` config option takes an integer. It represents @@ -21,7 +21,7 @@ restricted names that will always register an offense. num1 * num2 end - # With `MinArgNameLength` set to number greater than 1 + # With `MinNameLength` set to number greater than 1 def baz(a, b, c) do_stuff(a, b, c) end diff --git a/config/contents/naming/predicate_name.md b/config/contents/naming/predicate_name.md index 07a2d0cc..b3454b75 100644 --- a/config/contents/naming/predicate_name.md +++ b/config/contents/naming/predicate_name.md @@ -1,4 +1,27 @@ -This cop makes sure that predicates are named properly. +Checks that predicate methods names end with a question mark and +do not start with a forbidden prefix. + +A method is determined to be a predicate method if its name starts +with one of the prefixes defined in the `NamePrefix` configuration. +You can change what prefixes are considered by changing this option. +Any method name that starts with one of these prefixes is required by +the cop to end with a `?`. Other methods can be allowed by adding to +the `AllowedMethods` configuration. + +NOTE: The `is_a?` method is allowed by default. + +If `ForbiddenPrefixes` is set, methods that start with the configured +prefixes will not be allowed and will be removed by autocorrection. + +In other words, if `ForbiddenPrefixes` is empty, a method named `is_foo` +will register an offense only due to the lack of question mark (and will be +autocorrected to `is_foo?`). If `ForbiddenPrefixes` contains `is_`, +`is_foo` will register an offense both because the ? is missing and because of +the `is_` prefix, and will be corrected to `foo?`. + +NOTE: `ForbiddenPrefixes` is only applied to prefixes in `NamePrefix`; +a prefix in the former but not the latter will not be considered by +this cop. ### Example: # bad @@ -21,4 +44,9 @@ This cop makes sure that predicates are named properly. # good def value? - end \ No newline at end of file + end + +### Example: AllowedMethods: ['is_a?'] (default) + # good + def is_a?(value) + end diff --git a/config/contents/naming/rescued_exceptions_variable_name.md b/config/contents/naming/rescued_exceptions_variable_name.md index 843b24d0..caeb2343 100644 --- a/config/contents/naming/rescued_exceptions_variable_name.md +++ b/config/contents/naming/rescued_exceptions_variable_name.md @@ -1,4 +1,4 @@ -This cop makes sure that rescued exceptions variables are named as +Makes sure that rescued exceptions variables are named as expected. The `PreferredName` config option takes a `String`. It represents diff --git a/config/contents/naming/variable_name.md b/config/contents/naming/variable_name.md index c8c39224..01f16eaf 100644 --- a/config/contents/naming/variable_name.md +++ b/config/contents/naming/variable_name.md @@ -1,4 +1,4 @@ -This cop makes sure that all variables use the configured style, +Makes sure that all variables use the configured style, snake_case or camelCase, for their names. ### Example: EnforcedStyle: snake_case (default) @@ -13,4 +13,12 @@ snake_case or camelCase, for their names. foo_bar = 1 # good - fooBar = 1 \ No newline at end of file + fooBar = 1 + +### Example: AllowedIdentifiers: ['fooBar'] + # good (with EnforcedStyle: snake_case) + fooBar = 1 + +### Example: AllowedPatterns: ['_v\d+\z'] + # good (with EnforcedStyle: camelCase) + :release_v1 diff --git a/config/contents/naming/variable_number.md b/config/contents/naming/variable_number.md index f2ef0525..4e98b4ec 100644 --- a/config/contents/naming/variable_number.md +++ b/config/contents/naming/variable_number.md @@ -1,4 +1,4 @@ -This cop makes sure that all numbered variables use the +Makes sure that all numbered variables use the configured style, snake_case, normalcase, or non_integer, for their numbering. @@ -6,23 +6,6 @@ Additionally, `CheckMethodNames` and `CheckSymbols` configuration options can be used to specify whether method names and symbols should be checked. Both are enabled by default. -### Example: EnforcedStyle: snake_case - # bad - :some_sym1 - variable1 = 1 - - def some_method1; end - - def some_method_1(arg1); end - - # good - :some_sym_1 - variable_1 = 1 - - def some_method_1; end - - def some_method_1(arg_1); end - ### Example: EnforcedStyle: normalcase (default) # bad :some_sym_1 @@ -40,6 +23,23 @@ Both are enabled by default. def some_method1(arg1); end +### Example: EnforcedStyle: snake_case + # bad + :some_sym1 + variable1 = 1 + + def some_method1; end + + def some_method_1(arg1); end + + # good + :some_sym_1 + variable_1 = 1 + + def some_method_1; end + + def some_method_1(arg_1); end + ### Example: EnforcedStyle: non_integer # bad :some_sym1 @@ -90,3 +90,7 @@ Both are enabled by default. ### Example: AllowedIdentifiers: [capture3] # good expect(Open3).to receive(:capture3) + +### Example: AllowedPatterns: ['_v\d+\z'] + # good + :some_sym_v1 diff --git a/config/contents/performance/ancestors_include.md b/config/contents/performance/ancestors_include.md index 57624885..c86d20bf 100644 --- a/config/contents/performance/ancestors_include.md +++ b/config/contents/performance/ancestors_include.md @@ -1,5 +1,8 @@ -This cop is used to identify usages of `ancestors.include?` and -change them to use `<=` instead. +Identifies usages of `ancestors.include?` and change them to use `<=` instead. + +@safety + This cop is unsafe because it can't tell whether the receiver is a class or an object. + e.g. the false positive was for `Nokogiri::XML::Node#ancestors`. ### Example: # bad diff --git a/config/contents/performance/array_semi_infinite_range_slice.md b/config/contents/performance/array_semi_infinite_range_slice.md index 149eb4aa..7604a1d6 100644 --- a/config/contents/performance/array_semi_infinite_range_slice.md +++ b/config/contents/performance/array_semi_infinite_range_slice.md @@ -1,8 +1,10 @@ -This cop identifies places where slicing arrays with semi-infinite ranges +Identifies places where slicing arrays with semi-infinite ranges can be replaced by `Array#take` and `Array#drop`. This cop was created due to a mistake in microbenchmark and hence is disabled by default. Refer https://github.com/rubocop/rubocop-performance/pull/175#issuecomment-731892717 -This cop is also unsafe for string slices because strings do not have `#take` and `#drop` methods. + +@safety + This cop is unsafe for string slices because strings do not have `#take` and `#drop` methods. ### Example: # bad diff --git a/config/contents/performance/big_decimal_with_numeric_argument.md b/config/contents/performance/big_decimal_with_numeric_argument.md index 735507b3..957917a9 100644 --- a/config/contents/performance/big_decimal_with_numeric_argument.md +++ b/config/contents/performance/big_decimal_with_numeric_argument.md @@ -1,12 +1,16 @@ -This cop identifies places where numeric argument to BigDecimal should be +Identifies places where numeric argument to BigDecimal should be converted to string. Initializing from String is faster than from Numeric for BigDecimal. ### Example: # bad BigDecimal(1, 2) + 4.to_d(6) BigDecimal(1.2, 3, exception: true) + 4.5.to_d(6, exception: true) # good BigDecimal('1', 2) + BigDecimal('4', 6) BigDecimal('1.2', 3, exception: true) + BigDecimal('4.5', 6, exception: true) diff --git a/config/contents/performance/block_given_with_explicit_block.md b/config/contents/performance/block_given_with_explicit_block.md index 249983cb..bf52fcb1 100644 --- a/config/contents/performance/block_given_with_explicit_block.md +++ b/config/contents/performance/block_given_with_explicit_block.md @@ -1,4 +1,4 @@ -This cop identifies unnecessary use of a `block_given?` where explicit check +Identifies unnecessary use of a `block_given?` where explicit check of block argument would suffice. ### Example: diff --git a/config/contents/performance/caller.md b/config/contents/performance/caller.md index 618ecb1f..de7f0aa6 100644 --- a/config/contents/performance/caller.md +++ b/config/contents/performance/caller.md @@ -1,5 +1,4 @@ -This cop identifies places where `caller[n]` -can be replaced by `caller(n..n).first`. +Identifies places where `caller[n]` can be replaced by `caller(n..n).first`. ### Example: # bad diff --git a/config/contents/performance/case_when_splat.md b/config/contents/performance/case_when_splat.md index 17c565f2..f4b4b80d 100644 --- a/config/contents/performance/case_when_splat.md +++ b/config/contents/performance/case_when_splat.md @@ -12,11 +12,13 @@ conditions can be true for any given condition. A likely scenario for this defining a higher level when condition to override a condition that is inside of the splat expansion. -This is not a guaranteed performance improvement. If the data being -processed by the `case` condition is normalized in a manner that favors -hitting a condition in the splat expansion, it is possible that -moving the splat condition to the end will use more memory, -and run slightly slower. +@safety + This cop is not unsafe autocorrection because it is not a guaranteed + performance improvement. If the data being processed by the `case` condition is + normalized in a manner that favors hitting a condition in the splat expansion, + it is possible that moving the splat condition to the end will use more memory, + and run slightly slower. + See for more details: https://github.com/rubocop/rubocop/pull/6163 ### Example: # bad diff --git a/config/contents/performance/casecmp.md b/config/contents/performance/casecmp.md index 8bdadd42..c8d83889 100644 --- a/config/contents/performance/casecmp.md +++ b/config/contents/performance/casecmp.md @@ -1,7 +1,15 @@ -This cop identifies places where a case-insensitive string comparison +Identifies places where a case-insensitive string comparison can better be implemented using `casecmp`. -This cop is unsafe because `String#casecmp` and `String#casecmp?` behave -differently when using Non-ASCII characters. + +This cop is disabled by default because `String#casecmp` only works with +ASCII characters. See https://github.com/rubocop/rubocop/issues/9753. + +If you are working only with ASCII characters, then this cop can be +safely enabled. + +@safety + This cop is unsafe because `String#casecmp` and `String#casecmp?` behave + differently when using Non-ASCII characters. ### Example: # bad diff --git a/config/contents/performance/chain_array_allocation.md b/config/contents/performance/chain_array_allocation.md index 6f5fe137..3c2b3032 100644 --- a/config/contents/performance/chain_array_allocation.md +++ b/config/contents/performance/chain_array_allocation.md @@ -1,15 +1,13 @@ -This cop is used to identify usages of +Identifies usages of `array.compact.flatten.map { |x| x.downcase }`. +Each of these methods (`compact`, `flatten`, `map`) will generate a new intermediate array +that is promptly thrown away. Instead it is faster to mutate when we know it's safe. + ### Example: # bad array = ["a", "b", "c"] array.compact.flatten.map { |x| x.downcase } -Each of these methods (`compact`, `flatten`, `map`) will generate a -new intermediate array that is promptly thrown away. Instead it is -faster to mutate when we know it's safe. - -### Example: - # good. + # good array = ["a", "b", "c"] array.compact! array.flatten! diff --git a/config/contents/performance/collection_literal_in_loop.md b/config/contents/performance/collection_literal_in_loop.md index 369a3cb8..21f8d186 100644 --- a/config/contents/performance/collection_literal_in_loop.md +++ b/config/contents/performance/collection_literal_in_loop.md @@ -1,5 +1,5 @@ -This cop identifies places where Array and Hash literals are used -within loops. It is better to extract them into a local variable or constant +Identifies places where Array and Hash literals are used within loops. +It is better to extract them into a local variable or constant to avoid unnecessary allocations on each iteration. You can set the minimum number of elements to consider diff --git a/config/contents/performance/compare_with_block.md b/config/contents/performance/compare_with_block.md index 9cf8359f..43f812cb 100644 --- a/config/contents/performance/compare_with_block.md +++ b/config/contents/performance/compare_with_block.md @@ -1,20 +1,24 @@ -This cop identifies places where `sort { |a, b| a.foo <=> b.foo }` +Identifies places where `sort { |a, b| a.foo <=> b.foo }` can be replaced by `sort_by(&:foo)`. -This cop also checks `max` and `min` methods. +This cop also checks `sort!`, `min`, `max` and `minmax` methods. ### Example: # bad - array.sort { |a, b| a.foo <=> b.foo } - array.max { |a, b| a.foo <=> b.foo } - array.min { |a, b| a.foo <=> b.foo } - array.sort { |a, b| a[:foo] <=> b[:foo] } + array.sort { |a, b| a.foo <=> b.foo } + array.sort! { |a, b| a.foo <=> b.foo } + array.max { |a, b| a.foo <=> b.foo } + array.min { |a, b| a.foo <=> b.foo } + array.minmax { |a, b| a.foo <=> b.foo } + array.sort { |a, b| a[:foo] <=> b[:foo] } # good array.sort_by(&:foo) + array.sort_by!(&:foo) array.sort_by { |v| v.foo } array.sort_by do |var| var.foo end array.max_by(&:foo) array.min_by(&:foo) + array.minmax_by(&:foo) array.sort_by { |a| a[:foo] } \ No newline at end of file diff --git a/config/contents/performance/concurrent_monotonic_time.md b/config/contents/performance/concurrent_monotonic_time.md new file mode 100644 index 00000000..2879fbe3 --- /dev/null +++ b/config/contents/performance/concurrent_monotonic_time.md @@ -0,0 +1,10 @@ +Identifies places where `Concurrent.monotonic_time` +can be replaced by `Process.clock_gettime(Process::CLOCK_MONOTONIC)`. + +### Example: + + # bad + Concurrent.monotonic_time + + # good + Process.clock_gettime(Process::CLOCK_MONOTONIC) diff --git a/config/contents/performance/constant_regexp.md b/config/contents/performance/constant_regexp.md index 83964847..374a3197 100644 --- a/config/contents/performance/constant_regexp.md +++ b/config/contents/performance/constant_regexp.md @@ -1,4 +1,4 @@ -This cop finds regular expressions with dynamic components that are all constants. +Finds regular expressions with dynamic components that are all constants. Ruby allocates a new Regexp object every time it executes a code containing such a regular expression. It is more efficient to extract it into a constant, diff --git a/config/contents/performance/count.md b/config/contents/performance/count.md index ecafc977..f6adbae5 100644 --- a/config/contents/performance/count.md +++ b/config/contents/performance/count.md @@ -1,7 +1,28 @@ -This cop is used to identify usages of `count` on an `Enumerable` that +Identifies usages of `count` on an `Enumerable` that follow calls to `select`, `find_all`, `filter` or `reject`. Querying logic can instead be passed to the `count` call. +@safety + This cop is unsafe because it has known compatibility issues with `ActiveRecord` and other + frameworks. Before Rails 5.1, `ActiveRecord` will ignore the block that is passed to `count`. + Other methods, such as `select`, will convert the association to an + array and then run the block on the array. A simple work around to + make `count` work with a block is to call `to_a.count {...}`. + + For example: + + [source,ruby] + ---- + `Model.where(id: [1, 2, 3]).select { |m| m.method == true }.size` + ---- + + becomes: + + [source,ruby] + ---- + `Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }` + ---- + ### Example: # bad [1, 2, 3].select { |e| e > 2 }.size @@ -18,17 +39,4 @@ passed to the `count` call. [1, 2, 3].count { |e| e > 2 && e.odd? } [1, 2, 3].count { |e| e < 2 && e.even? } Model.select('field AS field_one').count - Model.select(:value).count - -`ActiveRecord` compatibility: -`ActiveRecord` will ignore the block that is passed to `count`. -Other methods, such as `select`, will convert the association to an -array and then run the block on the array. A simple work around to -make `count` work with a block is to call `to_a.count {...}`. - -Example: - `Model.where(id: [1, 2, 3]).select { |m| m.method == true }.size` - - becomes: - - `Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }` \ No newline at end of file + Model.select(:value).count \ No newline at end of file diff --git a/config/contents/performance/delete_prefix.md b/config/contents/performance/delete_prefix.md index 005f4bff..1823a762 100644 --- a/config/contents/performance/delete_prefix.md +++ b/config/contents/performance/delete_prefix.md @@ -2,7 +2,6 @@ In Ruby 2.5, `String#delete_prefix` has been added. This cop identifies places where `gsub(/\Aprefix/, '')` and `sub(/\Aprefix/, '')` can be replaced by `delete_prefix('prefix')`. -It is marked as unsafe by default because `Pathname` has `sub` but not `delete_prefix`. This cop has `SafeMultiline` configuration option that `true` by default because `^prefix` is unsafe as it will behave incompatible with `delete_prefix` @@ -10,6 +9,9 @@ for receiver is multiline string. The `delete_prefix('prefix')` method is faster than `gsub(/\Aprefix/, '')`. +@safety + This cop is unsafe because `Pathname` has `sub` but not `delete_prefix`. + ### Example: # bad diff --git a/config/contents/performance/delete_suffix.md b/config/contents/performance/delete_suffix.md index 61d1744b..803baea0 100644 --- a/config/contents/performance/delete_suffix.md +++ b/config/contents/performance/delete_suffix.md @@ -2,7 +2,6 @@ In Ruby 2.5, `String#delete_suffix` has been added. This cop identifies places where `gsub(/suffix\z/, '')` and `sub(/suffix\z/, '')` can be replaced by `delete_suffix('suffix')`. -It is marked as unsafe by default because `Pathname` has `sub` but not `delete_suffix`. This cop has `SafeMultiline` configuration option that `true` by default because `suffix$` is unsafe as it will behave incompatible with `delete_suffix?` @@ -10,6 +9,9 @@ for receiver is multiline string. The `delete_suffix('suffix')` method is faster than `gsub(/suffix\z/, '')`. +@safety + This cop is unsafe because `Pathname` has `sub` but not `delete_suffix`. + ### Example: # bad diff --git a/config/contents/performance/detect.md b/config/contents/performance/detect.md index 2020aca8..f00947d8 100644 --- a/config/contents/performance/detect.md +++ b/config/contents/performance/detect.md @@ -1,7 +1,12 @@ -This cop is used to identify usages of `first`, `last`, `[0]` or `[-1]` +Identifies usages of `first`, `last`, `[0]` or `[-1]` chained to `select`, `find_all` or `filter` and change them to use `detect` instead. +@safety + This cop is unsafe because it assumes that the receiver is an + `Array` or equivalent, but can't reliably detect it. For example, + if the receiver is a `Hash`, it may report a false positive. + ### Example: # bad [].select { |item| true }.first @@ -16,8 +21,3 @@ chained to `select`, `find_all` or `filter` and change them to use # good [].detect { |item| true } [].reverse.detect { |item| true } - -`ActiveRecord` compatibility: -`ActiveRecord` does not implement a `detect` method and `find` has its -own meaning. Correcting ActiveRecord methods with this cop should be -considered unsafe. \ No newline at end of file diff --git a/config/contents/performance/double_start_end_with.md b/config/contents/performance/double_start_end_with.md index 3d431378..f6c7e7e5 100644 --- a/config/contents/performance/double_start_end_with.md +++ b/config/contents/performance/double_start_end_with.md @@ -1,7 +1,10 @@ -This cop checks for double `#start_with?` or `#end_with?` calls +Checks for double `#start_with?` or `#end_with?` calls separated by `||`. In some cases such calls can be replaced with an single `#start_with?`/`#end_with?` call. +`IncludeActiveSupportAliases` configuration option is used to check for +`starts_with?` and `ends_with?`. These methods are defined by Active Support. + ### Example: # bad str.start_with?("a") || str.start_with?(Some::CONST) @@ -11,4 +14,21 @@ with an single `#start_with?`/`#end_with?` call. # good str.start_with?("a", Some::CONST) str.start_with?("a", "b", "c") - str.end_with?(var1, var2) \ No newline at end of file + str.end_with?(var1, var2) + +### Example: IncludeActiveSupportAliases: false (default) + # good + str.starts_with?("a", "b") || str.starts_with?("c") + str.ends_with?(var1) || str.ends_with?(var2) + + str.starts_with?("a", "b", "c") + str.ends_with?(var1, var2) + +### Example: IncludeActiveSupportAliases: true + # bad + str.starts_with?("a", "b") || str.starts_with?("c") + str.ends_with?(var1) || str.ends_with?(var2) + + # good + str.starts_with?("a", "b", "c") + str.ends_with?(var1, var2) diff --git a/config/contents/performance/end_with.md b/config/contents/performance/end_with.md index a9260b02..cdc2a6a9 100644 --- a/config/contents/performance/end_with.md +++ b/config/contents/performance/end_with.md @@ -1,9 +1,14 @@ -This cop identifies unnecessary use of a regex where `String#end_with?` would suffice. +Identifies unnecessary use of a regex where `String#end_with?` would suffice. This cop has `SafeMultiline` configuration option that `true` by default because `end$` is unsafe as it will behave incompatible with `end_with?` for receiver is multiline string. +@safety + This will change to a new method call which isn't guaranteed to be on the + object. Switching these methods has to be done with knowledge of the types + of the variables which rubocop doesn't have. + ### Example: # bad 'abc'.match?(/bc\Z/) diff --git a/config/contents/performance/flat_map.md b/config/contents/performance/flat_map.md index 3961b0d8..45d8a2d3 100644 --- a/config/contents/performance/flat_map.md +++ b/config/contents/performance/flat_map.md @@ -1,4 +1,4 @@ -This cop is used to identify usages of `map { ... }.flatten` and +Identifies usages of `map { ... }.flatten` and change them to use `flat_map { ... }` instead. ### Example: diff --git a/config/contents/performance/inefficient_hash_search.md b/config/contents/performance/inefficient_hash_search.md index 341b11e5..7723bd84 100644 --- a/config/contents/performance/inefficient_hash_search.md +++ b/config/contents/performance/inefficient_hash_search.md @@ -1,4 +1,4 @@ -This cop checks for inefficient searching of keys and values within +Checks for inefficient searching of keys and values within hashes. `Hash#keys.include?` is less efficient than `Hash#key?` because @@ -10,6 +10,9 @@ performs a faster O(1) search for the key. both perform an O(n) search through all of the values, calling `values` allocates a new array while using `value?` does not. +@safety + This cop is unsafe because it can't tell whether the receiver is a hash object. + ### Example: # bad { a: 1, b: 2 }.keys.include?(:a) diff --git a/config/contents/performance/io_readlines.md b/config/contents/performance/io_readlines.md index 6315e1af..bfa704aa 100644 --- a/config/contents/performance/io_readlines.md +++ b/config/contents/performance/io_readlines.md @@ -1,4 +1,4 @@ -This cop identifies places where inefficient `readlines` method +Identifies places where inefficient `readlines` method can be replaced by `each_line` to avoid fully loading file content into memory. ### Example: diff --git a/config/contents/performance/map_compact.md b/config/contents/performance/map_compact.md index 318f8923..e839ed12 100644 --- a/config/contents/performance/map_compact.md +++ b/config/contents/performance/map_compact.md @@ -1,8 +1,11 @@ In Ruby 2.7, `Enumerable#filter_map` has been added. This cop identifies places where `map { ... }.compact` can be replaced by `filter_map`. -It is marked as unsafe auto-correction by default because `map { ... }.compact` -that is not compatible with `filter_map`. + +@safety + This cop's autocorrection is unsafe because `map { ... }.compact` might yield + different results than `filter_map`. As illustrated in the example, `filter_map` + also filters out falsy values, while `compact` only gets rid of `nil`. [source,ruby] ---- diff --git a/config/contents/performance/map_method_chain.md b/config/contents/performance/map_method_chain.md new file mode 100644 index 00000000..4109f5ab --- /dev/null +++ b/config/contents/performance/map_method_chain.md @@ -0,0 +1,36 @@ +Checks if the map method is used in a chain. + +Autocorrection is not supported because an appropriate block variable name cannot be determined automatically. + +@safety + This cop is unsafe because false positives occur if the number of times the first method is executed + affects the return value of subsequent methods. + +[source,ruby] +---- +class X + def initialize + @@num = 0 + end + + def foo + @@num += 1 + self + end + + def bar + @@num * 2 + end +end + +[X.new, X.new].map(&:foo).map(&:bar) # => [4, 4] +[X.new, X.new].map { |x| x.foo.bar } # => [2, 4] +---- + +### Example: + + # bad + array.map(&:foo).map(&:bar) + + # good + array.map { |item| item.foo.bar } diff --git a/config/contents/performance/method_object_as_block.md b/config/contents/performance/method_object_as_block.md index 1aeee43c..36e36f90 100644 --- a/config/contents/performance/method_object_as_block.md +++ b/config/contents/performance/method_object_as_block.md @@ -1,4 +1,4 @@ -This cop identifies places where methods are converted to blocks, with the +Identifies places where methods are converted to blocks, with the use of `&method`, and passed as arguments to method calls. It is faster to replace those with explicit blocks, calling those methods inside. diff --git a/config/contents/performance/open_struct.md b/config/contents/performance/open_struct.md index 4d762d5c..e9120a2f 100644 --- a/config/contents/performance/open_struct.md +++ b/config/contents/performance/open_struct.md @@ -1,4 +1,4 @@ -This cop checks for `OpenStruct.new` calls. +Checks for `OpenStruct.new` calls. Instantiation of an `OpenStruct` invalidates Ruby global method cache as it causes dynamic method definition during program runtime. @@ -6,6 +6,10 @@ This could have an effect on performance, especially in case of single-threaded applications with multiple `OpenStruct` instantiations. +@safety + This cop is unsafe because `OpenStruct.new` and `Struct.new` + are not equivalent. + ### Example: # bad class MyClass diff --git a/config/contents/performance/range_include.md b/config/contents/performance/range_include.md index 280beede..d44c0821 100644 --- a/config/contents/performance/range_include.md +++ b/config/contents/performance/range_include.md @@ -1,11 +1,18 @@ -This cop identifies uses of `Range#include?` and `Range#member?`, which iterates over each +Identifies uses of `Range#include?` and `Range#member?`, which iterates over each item in a `Range` to see if a specified item is there. In contrast, `Range#cover?` simply compares the target item with the beginning and end points of the `Range`. In a great majority of cases, this is what is wanted. -This cop is `Safe: false` by default because `Range#include?` (or `Range#member?`) and -`Range#cover?` are not equivalent behaviour. +@safety + This cop is unsafe because `Range#include?` (or `Range#member?`) and `Range#cover?` + are not equivalent behavior. + Example of a case where `Range#cover?` may not provide the desired result: + + [source,ruby] + ---- + ('a'..'z').cover?('yellow') # => true + ---- ### Example: # bad @@ -13,9 +20,4 @@ This cop is `Safe: false` by default because `Range#include?` (or `Range#member? ('a'..'z').member?('b') # => true # good - ('a'..'z').cover?('b') # => true - - # Example of a case where `Range#cover?` may not provide - # the desired result: - - ('a'..'z').cover?('yellow') # => true \ No newline at end of file + ('a'..'z').cover?('b') # => true \ No newline at end of file diff --git a/config/contents/performance/redundant_block_call.md b/config/contents/performance/redundant_block_call.md index 8dae752c..ceba23d2 100644 --- a/config/contents/performance/redundant_block_call.md +++ b/config/contents/performance/redundant_block_call.md @@ -1,4 +1,4 @@ -This cop identifies the use of a `&block` parameter and `block.call` +Identifies the use of a `&block` parameter and `block.call` where `yield` would do just as well. ### Example: diff --git a/config/contents/performance/redundant_equality_comparison_block.md b/config/contents/performance/redundant_equality_comparison_block.md index eb909586..bce32028 100644 --- a/config/contents/performance/redundant_equality_comparison_block.md +++ b/config/contents/performance/redundant_equality_comparison_block.md @@ -1,11 +1,22 @@ -This cop checks for uses `Enumerable#all?`, `Enumerable#any?`, `Enumerable#one?`, +Checks for uses `Enumerable#all?`, `Enumerable#any?`, `Enumerable#one?`, and `Enumerable#none?` are compared with `===` or similar methods in block. By default, `Object#===` behaves the same as `Object#==`, but this behavior is appropriately overridden in subclass. For example, `Range#===` returns `true` when argument is within the range. -Therefore, It is marked as unsafe by default because `===` and `==` -do not always behave the same. + +This cop has `AllowRegexpMatch` option and it is true by default because +`regexp.match?('string')` often used in block changes to the opposite result: + +[source,ruby] +---- +[/pattern/].all? { |regexp| regexp.match?('pattern') } # => true +[/pattern/].all? { |regexp| regexp =~ 'pattern' } # => true +[/pattern/].all?('pattern') # => false +---- + +@safety + This cop is unsafe because `===` and `==` do not always behave the same. ### Example: # bad @@ -16,3 +27,16 @@ do not always behave the same. # good items.all?(pattern) + items.all?(Klass) + +### Example: AllowRegexpMatch: true (default) + + # good + items.all? { |item| item =~ pattern } + items.all? { |item| item.match?(pattern) } + +### Example: AllowRegexpMatch: false + + # bad + items.all? { |item| item =~ pattern } + items.all? { |item| item.match?(pattern) } diff --git a/config/contents/performance/redundant_match.md b/config/contents/performance/redundant_match.md index 420bb0dd..a50b40d4 100644 --- a/config/contents/performance/redundant_match.md +++ b/config/contents/performance/redundant_match.md @@ -1,4 +1,4 @@ -This cop identifies the use of `Regexp#match` or `String#match`, which +Identifies the use of `Regexp#match` or `String#match`, which returns `#`/`nil`. The return value of `=~` is an integral index/`nil` and is more performant. diff --git a/config/contents/performance/redundant_merge.md b/config/contents/performance/redundant_merge.md index 11f0bea3..3b889261 100644 --- a/config/contents/performance/redundant_merge.md +++ b/config/contents/performance/redundant_merge.md @@ -1,10 +1,10 @@ -This cop identifies places where `Hash#merge!` can be replaced by -`Hash#[]=`. +Identifies places where `Hash#merge!` can be replaced by `Hash#[]=`. You can set the maximum number of key-value pairs to consider an offense with `MaxKeyValuePairs`. -This cop is marked as unsafe because RuboCop cannot determine if the -receiver of `merge!` is actually a hash or not. +@safety + This cop is unsafe because RuboCop cannot determine if the + receiver of `merge!` is actually a hash or not. ### Example: # bad diff --git a/config/contents/performance/redundant_sort_block.md b/config/contents/performance/redundant_sort_block.md index fb4e0f7c..e6a9274b 100644 --- a/config/contents/performance/redundant_sort_block.md +++ b/config/contents/performance/redundant_sort_block.md @@ -1,5 +1,4 @@ -This cop identifies places where `sort { |a, b| a <=> b }` -can be replaced with `sort`. +Identifies places where `sort { |a, b| a <=> b }` can be replaced with `sort`. ### Example: # bad diff --git a/config/contents/performance/redundant_split_regexp_argument.md b/config/contents/performance/redundant_split_regexp_argument.md index 63499532..a1168e32 100644 --- a/config/contents/performance/redundant_split_regexp_argument.md +++ b/config/contents/performance/redundant_split_regexp_argument.md @@ -1,4 +1,4 @@ -This cop identifies places where `split` argument can be replaced from +Identifies places where `split` argument can be replaced from a deterministic regexp to a string. ### Example: diff --git a/config/contents/performance/redundant_string_chars.md b/config/contents/performance/redundant_string_chars.md index d1b3fd28..0725694f 100644 --- a/config/contents/performance/redundant_string_chars.md +++ b/config/contents/performance/redundant_string_chars.md @@ -1,9 +1,10 @@ -This cop checks for redundant `String#chars`. +Checks for redundant `String#chars`. ### Example: # bad str.chars[0..2] str.chars.slice(0..2) + str.chars.last # good str[0..2].chars @@ -15,6 +16,7 @@ This cop checks for redundant `String#chars`. # good str[0] str[0...2].chars + str[-1] # bad str.chars.take(2) @@ -28,8 +30,7 @@ This cop checks for redundant `String#chars`. str.size str.empty? - # For example, if the receiver is a blank string, it will be incompatible. + # For example, if the receiver is an empty string, it will be incompatible. # If a negative value is specified for the receiver, `nil` is returned. - str.chars.last # Incompatible with `str[-1]`. str.chars.last(2) # Incompatible with `str[-2..-1].chars`. str.chars.drop(2) # Incompatible with `str[2..-1].chars`. diff --git a/config/contents/performance/reverse_each.md b/config/contents/performance/reverse_each.md index 896e1ebd..711eb87a 100644 --- a/config/contents/performance/reverse_each.md +++ b/config/contents/performance/reverse_each.md @@ -1,5 +1,4 @@ -This cop is used to identify usages of `reverse.each` and -change them to use `reverse_each` instead. +Identifies usages of `reverse.each` and change them to use `reverse_each` instead. If the return value is used, it will not be detected because the result will be different. diff --git a/config/contents/performance/reverse_first.md b/config/contents/performance/reverse_first.md index 4bb65cc6..f623d4f8 100644 --- a/config/contents/performance/reverse_first.md +++ b/config/contents/performance/reverse_first.md @@ -1,4 +1,4 @@ -This cop identifies places where `reverse.first(n)` and `reverse.first` +Identifies places where `reverse.first(n)` and `reverse.first` can be replaced by `last(n).reverse` and `last`. ### Example: diff --git a/config/contents/performance/size.md b/config/contents/performance/size.md index 62f24f60..32e0e64f 100644 --- a/config/contents/performance/size.md +++ b/config/contents/performance/size.md @@ -1,5 +1,4 @@ -This cop is used to identify usages of `count` on an -`Array` and `Hash` and change them to `size`. +Identifies usages of `count` on an `Array` and `Hash` and change them to `size`. ### Example: # bad diff --git a/config/contents/performance/sort_reverse.md b/config/contents/performance/sort_reverse.md index 4dcb6080..84403db5 100644 --- a/config/contents/performance/sort_reverse.md +++ b/config/contents/performance/sort_reverse.md @@ -1,4 +1,4 @@ -This cop identifies places where `sort { |a, b| b <=> a }` +Identifies places where `sort { |a, b| b <=> a }` can be replaced by a faster `sort.reverse`. ### Example: diff --git a/config/contents/performance/squeeze.md b/config/contents/performance/squeeze.md index 5cb2eeb0..ad376422 100644 --- a/config/contents/performance/squeeze.md +++ b/config/contents/performance/squeeze.md @@ -1,4 +1,4 @@ -This cop identifies places where `gsub(/a+/, 'a')` and `gsub!(/a+/, 'a')` +Identifies places where `gsub(/a+/, 'a')` and `gsub!(/a+/, 'a')` can be replaced by `squeeze('a')` and `squeeze!('a')`. The `squeeze('a')` method is faster than `gsub(/a+/, 'a')`. diff --git a/config/contents/performance/start_with.md b/config/contents/performance/start_with.md index 23cbcca6..f9d3fc63 100644 --- a/config/contents/performance/start_with.md +++ b/config/contents/performance/start_with.md @@ -1,9 +1,14 @@ -This cop identifies unnecessary use of a regex where `String#start_with?` would suffice. +Identifies unnecessary use of a regex where `String#start_with?` would suffice. This cop has `SafeMultiline` configuration option that `true` by default because `^start` is unsafe as it will behave incompatible with `start_with?` for receiver is multiline string. +@safety + This will change to a new method call which isn't guaranteed to be on the + object. Switching these methods has to be done with knowledge of the types + of the variables which rubocop doesn't have. + ### Example: # bad 'abc'.match?(/\Aab/) diff --git a/config/contents/performance/string_identifier_argument.md b/config/contents/performance/string_identifier_argument.md new file mode 100644 index 00000000..60511cb1 --- /dev/null +++ b/config/contents/performance/string_identifier_argument.md @@ -0,0 +1,26 @@ +Identifies places where string identifier argument can be replaced +by symbol identifier argument. +It prevents the redundancy of the internal string-to-symbol conversion. + +This cop targets methods that take identifier (e.g. method name) argument +and the following examples are parts of it. + +### Example: + + # bad + send('do_something') + attr_accessor 'do_something' + instance_variable_get('@ivar') + respond_to?("string_#{interpolation}") + + # good + send(:do_something) + attr_accessor :do_something + instance_variable_get(:@ivar) + respond_to?(:"string_#{interpolation}") + + # good - these methods don't support namespaced symbols + const_get("#{module_path}::Base") + const_source_location("#{module_path}::Base") + const_defined?("#{module_path}::Base") + diff --git a/config/contents/performance/string_include.md b/config/contents/performance/string_include.md index b9c9d495..e81dd141 100644 --- a/config/contents/performance/string_include.md +++ b/config/contents/performance/string_include.md @@ -1,16 +1,17 @@ -This cop identifies unnecessary use of a regex where -`String#include?` would suffice. +Identifies unnecessary use of a regex where `String#include?` would suffice. -This cop's offenses are not safe to auto-correct if a receiver is nil. +@safety + This cop's offenses are not safe to autocorrect if a receiver is nil or a Symbol. ### Example: # bad - 'abc'.match?(/ab/) - /ab/.match?('abc') - 'abc' =~ /ab/ - /ab/ =~ 'abc' - 'abc'.match(/ab/) - /ab/.match('abc') + str.match?(/ab/) + /ab/.match?(str) + str =~ /ab/ + /ab/ =~ str + str.match(/ab/) + /ab/.match(str) + /ab/ === str # good - 'abc'.include?('ab') \ No newline at end of file + str.include?('ab') \ No newline at end of file diff --git a/config/contents/performance/string_replacement.md b/config/contents/performance/string_replacement.md index eed79736..8e3798ab 100644 --- a/config/contents/performance/string_replacement.md +++ b/config/contents/performance/string_replacement.md @@ -1,5 +1,4 @@ -This cop identifies places where `gsub` can be replaced by -`tr` or `delete`. +Identifies places where `gsub` can be replaced by `tr` or `delete`. ### Example: # bad diff --git a/config/contents/performance/sum.md b/config/contents/performance/sum.md index c0782978..758d0ec4 100644 --- a/config/contents/performance/sum.md +++ b/config/contents/performance/sum.md @@ -1,35 +1,46 @@ -This cop identifies places where custom code finding the sum of elements +Identifies places where custom code finding the sum of elements in some Enumerable object can be replaced by `Enumerable#sum` method. -This cop can change auto-correction scope depending on the value of -`SafeAutoCorrect`. -Its auto-correction is marked as safe by default (`SafeAutoCorrect: true`) -to prevent `TypeError` in auto-correced code when initial value is not -specified as shown below: +@safety + Autocorrections are unproblematic wherever an initial value is provided explicitly: -[source,ruby] ----- -['a', 'b'].sum # => (String can't be coerced into Integer) ----- + [source,ruby] + ---- + [1, 2, 3].reduce(4, :+) # => 10 + [1, 2, 3].sum(4) # => 10 -Therefore if initial value is not specified, unsafe auto-corrected will not occur. + [].reduce(4, :+) # => 4 + [].sum(4) # => 4 + ---- -If you always want to enable auto-correction, you can set `SafeAutoCorrect: false`. + This also holds true for non-numeric types which implement a `:+` method: -[source,yaml] ----- -Performance/Sum: - SafeAutoCorrect: false ----- + [source,ruby] + ---- + ['l', 'o'].reduce('Hel', :+) # => "Hello" + ['l', 'o'].sum('Hel') # => "Hello" + ---- -Please note that the auto-correction command line option will be changed from -`rubocop -a` to `rubocop -A`, which includes unsafe auto-correction. + When no initial value is provided though, `Enumerable#reduce` will pick the first enumerated value + as initial value and successively add all following values to it, whereas + `Enumerable#sum` will set an initial value of `0` (`Integer`) which can lead to a `TypeError`: -### Example: + [source,ruby] + ---- + [].reduce(:+) # => nil + [1, 2, 3].reduce(:+) # => 6 + ['H', 'e', 'l', 'l', 'o'].reduce(:+) # => "Hello" + + [].sum # => 0 + [1, 2, 3].sum # => 6 + ['H', 'e', 'l', 'l', 'o'].sum # => in `+': String can't be coerced into Integer (TypeError) + ---- + +### Example: OnlySumOrWithInitialValue: false (default) # bad - [1, 2, 3].inject(:+) # These bad cases with no initial value are unsafe and - [1, 2, 3].inject(&:+) # will not be auto-correced by default. If you want to - [1, 2, 3].reduce { |acc, elem| acc + elem } # auto-corrected, you can set `SafeAutoCorrect: false`. + [1, 2, 3].inject(:+) # Autocorrections for cases without initial value are unsafe + [1, 2, 3].inject(&:+) # and will only be performed when using the `-A` option. + [1, 2, 3].reduce { |acc, elem| acc + elem } # They can be prohibited completely using `SafeAutoCorrect: true`. [1, 2, 3].reduce(10, :+) [1, 2, 3].map { |elem| elem ** 2 }.sum [1, 2, 3].collect(&:count).sum(10) @@ -39,3 +50,14 @@ Please note that the auto-correction command line option will be changed from [1, 2, 3].sum(10) [1, 2, 3].sum { |elem| elem ** 2 } [1, 2, 3].sum(10, &:count) + +### Example: OnlySumOrWithInitialValue: true + # bad + [1, 2, 3].reduce(10, :+) + [1, 2, 3].map { |elem| elem ** 2 }.sum + [1, 2, 3].collect(&:count).sum(10) + + # good + [1, 2, 3].sum(10) + [1, 2, 3].sum { |elem| elem ** 2 } + [1, 2, 3].sum(10, &:count) diff --git a/config/contents/performance/times_map.md b/config/contents/performance/times_map.md index bcd0a717..1cbc9706 100644 --- a/config/contents/performance/times_map.md +++ b/config/contents/performance/times_map.md @@ -1,7 +1,19 @@ -This cop checks for .times.map calls. +Checks for .times.map calls. In most cases such calls can be replaced with an explicit array creation. +@safety + This cop's autocorrection is unsafe because `Integer#times` does nothing if receiver is 0 + or less. However, `Array.new` raises an error if argument is less than 0. + + For example: + + [source,ruby] + ---- + -1.times{} # does nothing + Array.new(-1) # ArgumentError: negative array size + ---- + ### Example: # bad 9.times.map do |i| diff --git a/config/contents/performance/unfreeze_string.md b/config/contents/performance/unfreeze_string.md index b52ceca9..c25beb81 100644 --- a/config/contents/performance/unfreeze_string.md +++ b/config/contents/performance/unfreeze_string.md @@ -2,16 +2,16 @@ In Ruby 2.3 or later, use unary plus operator to unfreeze a string literal instead of `String#dup` and `String.new`. Unary plus operator is faster than `String#dup`. -NOTE: `String.new` (without operator) is not exactly the same as `+''`. -These differ in encoding. `String.new.encoding` is always `ASCII-8BIT`. -However, `(+'').encoding` is the same as script encoding(e.g. `UTF-8`). -Therefore, auto-correction is unsafe. -So, if you expect `ASCII-8BIT` encoding, disable this cop. +@safety + This cop's autocorrection is unsafe because `String.new` (without operator) is not + exactly the same as `+''`. These differ in encoding. `String.new.encoding` is always + `ASCII-8BIT`. However, `(+'').encoding` is the same as script encoding(e.g. `UTF-8`). + if you expect `ASCII-8BIT` encoding, disable this cop. ### Example: # bad - ''.dup - "something".dup + ''.dup # when Ruby 3.2 or lower + "something".dup # when Ruby 3.2 or lower String.new String.new('') String.new('something') diff --git a/config/contents/performance/uri_default_parser.md b/config/contents/performance/uri_default_parser.md index aba62454..7fd14a54 100644 --- a/config/contents/performance/uri_default_parser.md +++ b/config/contents/performance/uri_default_parser.md @@ -1,5 +1,4 @@ -This cop identifies places where `URI::Parser.new` -can be replaced by `URI::DEFAULT_PARSER`. +Identifies places where `URI::Parser.new` can be replaced by `URI::DEFAULT_PARSER`. ### Example: # bad diff --git a/config/contents/security/compound_hash.md b/config/contents/security/compound_hash.md new file mode 100644 index 00000000..a9cec68d --- /dev/null +++ b/config/contents/security/compound_hash.md @@ -0,0 +1,24 @@ +Checks for implementations of the `hash` method which combine +values using custom logic instead of delegating to `Array#hash`. + +Manually combining hashes is error prone and hard to follow, especially +when there are many values. Poor implementations may also introduce +performance or security concerns if they are prone to collisions. +Delegating to `Array#hash` is clearer and safer, although it might be slower +depending on the use case. + +@safety + This cop may be unsafe if the application logic depends on the hash + value, however this is inadvisable anyway. + +### Example: + + # bad + def hash + @foo ^ @bar + end + + # good + def hash + [@foo, @bar].hash + end \ No newline at end of file diff --git a/config/contents/security/eval.md b/config/contents/security/eval.md index 5de6ce2b..a5a576ad 100644 --- a/config/contents/security/eval.md +++ b/config/contents/security/eval.md @@ -1,4 +1,4 @@ -This cop checks for the use of `Kernel#eval` and `Binding#eval`. +Checks for the use of `Kernel#eval` and `Binding#eval`. ### Example: diff --git a/config/contents/security/io_methods.md b/config/contents/security/io_methods.md new file mode 100644 index 00000000..e495a67d --- /dev/null +++ b/config/contents/security/io_methods.md @@ -0,0 +1,23 @@ +Checks for the first argument to `IO.read`, `IO.binread`, `IO.write`, `IO.binwrite`, +`IO.foreach`, and `IO.readlines`. + +If argument starts with a pipe character (`'|'`) and the receiver is the `IO` class, +a subprocess is created in the same way as `Kernel#open`, and its output is returned. +`Kernel#open` may allow unintentional command injection, which is the reason these +`IO` methods are a security risk. +Consider to use `File.read` to disable the behavior of subprocess invocation. + +@safety + This cop is unsafe because false positive will occur if the variable passed as + the first argument is a command that is not a file path. + +### Example: + + # bad + IO.read(path) + IO.read('path') + + # good + File.read(path) + File.read('path') + IO.read('| command') # Allow intentional command invocation. diff --git a/config/contents/security/json_load.md b/config/contents/security/json_load.md index a6cb8904..7468f614 100644 --- a/config/contents/security/json_load.md +++ b/config/contents/security/json_load.md @@ -1,13 +1,14 @@ -This cop checks for the use of JSON class methods which have potential +Checks for the use of JSON class methods which have potential security issues. -Autocorrect is disabled by default because it's potentially dangerous. -If using a stream, like `JSON.load(open('file'))`, it will need to call -`#read` manually, like `JSON.parse(open('file').read)`. -If reading single values (rather than proper JSON objects), like -`JSON.load('false')`, it will need to pass the `quirks_mode: true` -option, like `JSON.parse('false', quirks_mode: true)`. -Other similar issues may apply. +@safety + This cop's autocorrection is unsafe because it's potentially dangerous. + If using a stream, like `JSON.load(open('file'))`, it will need to call + `#read` manually, like `JSON.parse(open('file').read)`. + If reading single values (rather than proper JSON objects), like + `JSON.load('false')`, it will need to pass the `quirks_mode: true` + option, like `JSON.parse('false', quirks_mode: true)`. + Other similar issues may apply. ### Example: # bad diff --git a/config/contents/security/marshal_load.md b/config/contents/security/marshal_load.md index 66c2a6b1..474779b7 100644 --- a/config/contents/security/marshal_load.md +++ b/config/contents/security/marshal_load.md @@ -1,4 +1,4 @@ -This cop checks for the use of Marshal class methods which have +Checks for the use of Marshal class methods which have potential security issues leading to remote code execution when loading from an untrusted source. diff --git a/config/contents/security/open.md b/config/contents/security/open.md index b5f23f2b..52cf38fc 100644 --- a/config/contents/security/open.md +++ b/config/contents/security/open.md @@ -1,4 +1,5 @@ -This cop checks for the use of `Kernel#open` and `URI.open`. +Checks for the use of `Kernel#open` and `URI.open` with dynamic +data. `Kernel#open` and `URI.open` enable not only file access but also process invocation by prefixing a pipe symbol (e.g., `open("| ls")`). @@ -6,12 +7,25 @@ So, it may lead to a serious security risk by using variable input to the argument of `Kernel#open` and `URI.open`. It would be better to use `File.open`, `IO.popen` or `URI.parse#open` explicitly. +NOTE: `open` and `URI.open` with literal strings are not flagged by this +cop. + +@safety + This cop could register false positives if `open` is redefined + in a class and then used without a receiver in that class. + ### Example: # bad open(something) + open("| #{something}") + open("| foo") URI.open(something) # good File.open(something) IO.popen(something) - URI.parse(something).open \ No newline at end of file + URI.parse(something).open + + # good (literal strings) + open("foo.text") + URI.open("http://example.com") \ No newline at end of file diff --git a/config/contents/security/yaml_load.md b/config/contents/security/yaml_load.md index c428452c..5082d4f7 100644 --- a/config/contents/security/yaml_load.md +++ b/config/contents/security/yaml_load.md @@ -1,11 +1,19 @@ -This cop checks for the use of YAML class methods which have +Checks for the use of YAML class methods which have potential security issues leading to remote code execution when loading from an untrusted source. +NOTE: Ruby 3.1+ (Psych 4) uses `Psych.load` as `Psych.safe_load` by default. + +@safety + The behavior of the code might change depending on what was + in the YAML payload, since `YAML.safe_load` is more restrictive. + ### Example: # bad - YAML.load("--- foo") + YAML.load("--- !ruby/object:Foo {}") # Psych 3 is unsafe by default # good - YAML.safe_load("--- foo") - YAML.dump("foo") + YAML.safe_load("--- !ruby/object:Foo {}", [Foo]) # Ruby 2.5 (Psych 3) + YAML.safe_load("--- !ruby/object:Foo {}", permitted_classes: [Foo]) # Ruby 3.0- (Psych 3) + YAML.load("--- !ruby/object:Foo {}", permitted_classes: [Foo]) # Ruby 3.1+ (Psych 4) + YAML.dump(foo) diff --git a/config/contents/standard/block_single_line_braces.md b/config/contents/standard/block_single_line_braces.md deleted file mode 100644 index 1ed160f4..00000000 --- a/config/contents/standard/block_single_line_braces.md +++ /dev/null @@ -1,9 +0,0 @@ -Check for uses of braces around single line blocks, but allows either -braces or do/end for multi-line blocks. - -### Example: - # bad - single line block - items.each do |item| item / 5 end - - # good - single line block - items.each { |item| item / 5 } diff --git a/config/contents/style/access_modifier_declarations.md b/config/contents/style/access_modifier_declarations.md index 1ceb727c..c95e3519 100644 --- a/config/contents/style/access_modifier_declarations.md +++ b/config/contents/style/access_modifier_declarations.md @@ -3,6 +3,22 @@ or inline before each method, depending on configuration. EnforcedStyle config covers only method definitions. Applications of visibility methods to symbols can be controlled using AllowModifiersOnSymbols config. +Also, the visibility of `attr*` methods can be controlled using +AllowModifiersOnAttrs config. + +In Ruby 3.0, `attr*` methods now return an array of defined method names +as symbols. So we can write the modifier and `attr*` in inline style. +AllowModifiersOnAttrs config allows `attr*` methods to be written in +inline style without modifying applications that have been maintained +for a long time in group style. Furthermore, developers who are not very +familiar with Ruby may know that the modifier applies to `def`, but they +may not know that it also applies to `attr*` methods. It would be easier +to understand if we could write `attr*` methods in inline style. + +@safety + Autocorrection is not safe, because the visibility of dynamically + defined methods can vary depending on the state determined by + the group access modifier. ### Example: EnforcedStyle: group (default) # bad @@ -56,4 +72,32 @@ using AllowModifiersOnSymbols config. private :bar, :baz + end + +### Example: AllowModifiersOnAttrs: true (default) + # good + class Foo + + public attr_reader :bar + protected attr_writer :baz + private attr_accessor :qux + private attr :quux + + def public_method; end + + private + + def private_method; end + + end + +### Example: AllowModifiersOnAttrs: false + # bad + class Foo + + public attr_reader :bar + protected attr_writer :baz + private attr_accessor :qux + private attr :quux + end \ No newline at end of file diff --git a/config/contents/style/accessor_grouping.md b/config/contents/style/accessor_grouping.md index 7649752d..bb8c0c81 100644 --- a/config/contents/style/accessor_grouping.md +++ b/config/contents/style/accessor_grouping.md @@ -1,20 +1,33 @@ -This cop checks for grouping of accessors in `class` and `module` bodies. +Checks for grouping of accessors in `class` and `module` bodies. By default it enforces accessors to be placed in grouped declarations, but it can be configured to enforce separating them in multiple declarations. -NOTE: `Sorbet` is not compatible with "grouped" style. Consider "separated" style -or disabling this cop. +NOTE: If there is a method call before the accessor method it is always allowed +as it might be intended like Sorbet. ### Example: EnforcedStyle: grouped (default) # bad class Foo attr_reader :bar + attr_reader :bax attr_reader :baz end # good class Foo - attr_reader :bar, :baz + attr_reader :bar, :bax, :baz + end + + # good + class Foo + # may be intended comment for bar. + attr_reader :bar + + sig { returns(String) } + attr_reader :bax + + may_be_intended_annotation :baz + attr_reader :baz end ### Example: EnforcedStyle: separated diff --git a/config/contents/style/alias.md b/config/contents/style/alias.md index 8313fc4d..6f349339 100644 --- a/config/contents/style/alias.md +++ b/config/contents/style/alias.md @@ -1,7 +1,12 @@ -This cop enforces the use of either `#alias` or `#alias_method` +Enforces the use of either `#alias` or `#alias_method` depending on configuration. It also flags uses of `alias :symbol` rather than `alias bareword`. +However, it will always enforce `method_alias` when used `alias` +in an instance method definition and in a singleton method definition. +If used in a block, always enforce `alias_method` +unless it is an `instance_eval` block. + ### Example: EnforcedStyle: prefer_alias (default) # bad alias_method :bar, :foo @@ -16,4 +21,4 @@ It also flags uses of `alias :symbol` rather than `alias bareword`. alias bar foo # good - alias_method :bar, :foo \ No newline at end of file + alias_method :bar, :foo diff --git a/config/contents/style/and_or.md b/config/contents/style/and_or.md index b8cdfac7..ab519457 100644 --- a/config/contents/style/and_or.md +++ b/config/contents/style/and_or.md @@ -1,11 +1,13 @@ -This cop checks for uses of `and` and `or`, and suggests using `&&` and +Checks for uses of `and` and `or`, and suggests using `&&` and `||` instead. It can be configured to check only in conditions or in all contexts. -### Example: EnforcedStyle: always - # bad - foo.save and return +@safety + Autocorrection is unsafe because there is a different operator precedence + between logical operators (`&&` and `||`) and semantic operators (`and` and `or`), + and that might change the behavior. +### Example: EnforcedStyle: conditionals (default) # bad if foo and bar end @@ -13,11 +15,17 @@ all contexts. # good foo.save && return + # good + foo.save and return + # good if foo && bar end -### Example: EnforcedStyle: conditionals (default) +### Example: EnforcedStyle: always + # bad + foo.save and return + # bad if foo and bar end @@ -25,9 +33,6 @@ all contexts. # good foo.save && return - # good - foo.save and return - # good if foo && bar end \ No newline at end of file diff --git a/config/contents/style/arguments_forwarding.md b/config/contents/style/arguments_forwarding.md index 42481859..337c91cc 100644 --- a/config/contents/style/arguments_forwarding.md +++ b/config/contents/style/arguments_forwarding.md @@ -3,6 +3,29 @@ In Ruby 2.7, arguments forwarding has been added. This cop identifies places where `do_something(*args, &block)` can be replaced by `do_something(...)`. +In Ruby 3.1, anonymous block forwarding has been added. + +This cop identifies places where `do_something(&block)` can be replaced +by `do_something(&)`; if desired, this functionality can be disabled +by setting `UseAnonymousForwarding: false`. + +In Ruby 3.2, anonymous args/kwargs forwarding has been added. + +This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be +replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled +by setting `UseAnonymousForwarding: false`. + +And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`, +and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names +that are sufficient for anonymizing meaningless naming. + +Meaningless names that are commonly used can be anonymized by default: +e.g., `*args`, `**options`, `&block`, and so on. + +Names not on this list are likely to be meaningful and are allowed by default. + +This cop handles not only method forwarding but also forwarding to `super`. + ### Example: # bad def foo(*args, &block) @@ -19,16 +42,80 @@ can be replaced by `do_something(...)`. bar(...) end -### Example: AllowOnlyRestArgument: true (default) +### Example: UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2) + # bad + def foo(*args, **kwargs, &block) + args_only(*args) + kwargs_only(**kwargs) + block_only(&block) + end + + # good + def foo(*, **, &) + args_only(*) + kwargs_only(**) + block_only(&) + end + +### Example: UseAnonymousForwarding: false (only relevant for Ruby >= 3.2) + # good + def foo(*args, **kwargs, &block) + args_only(*args) + kwargs_only(**kwargs) + block_only(&block) + end + +### Example: AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2) # good def foo(*args) bar(*args) end -### Example: AllowOnlyRestArgument: false + def foo(**kwargs) + bar(**kwargs) + end + +### Example: AllowOnlyRestArgument: false (only relevant for Ruby < 3.2) # bad # The following code can replace the arguments with `...`, # but it will change the behavior. Because `...` forwards block also. def foo(*args) bar(*args) end + + def foo(**kwargs) + bar(**kwargs) + end + +### Example: RedundantRestArgumentNames: ['args', 'arguments'] (default) + # bad + def foo(*args) + bar(*args) + end + + # good + def foo(*) + bar(*) + end + +### Example: RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default) + # bad + def foo(**kwargs) + bar(**kwargs) + end + + # good + def foo(**) + bar(**) + end + +### Example: RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default) + # bad - But it is good with `EnforcedStyle: explicit` set for `Naming/BlockForwarding`. + def foo(&block) + bar(&block) + end + + # good + def foo(&) + bar(&) + end \ No newline at end of file diff --git a/config/contents/style/array_coercion.md b/config/contents/style/array_coercion.md index 56629f05..7a40f5fd 100644 --- a/config/contents/style/array_coercion.md +++ b/config/contents/style/array_coercion.md @@ -1,8 +1,26 @@ -This cop enforces the use of `Array()` instead of explicit `Array` check or `[*var]`. +Enforces the use of `Array()` instead of explicit `Array` check or `[*var]`. -This cop is disabled by default because false positive will occur if -the argument of `Array()` is not an array (e.g. Hash, Set), -an array will be returned as an incompatibility result. +The cop is disabled by default due to safety concerns. + +@safety + This cop is unsafe because a false positive may occur if + the argument of `Array()` is (or could be) nil or depending + on how the argument is handled by `Array()` (which can be + different than just wrapping the argument in an array). + + For example: + + [source,ruby] + ---- + [nil] #=> [nil] + Array(nil) #=> [] + + [{a: 'b'}] #= [{a: 'b'}] + Array({a: 'b'}) #=> [[:a, 'b']] + + [Time.now] #=> [#