From f1d007fd80c88f15a066a377b960f5755107819e Mon Sep 17 00:00:00 2001 From: Daniel Wright Date: Tue, 24 Nov 2020 11:19:07 -0800 Subject: [PATCH 1/5] Support for Rubocop 1.7.0 In order to support the 1.x versions of Rubocop, two dependencies have also been upgraded: - rubocop-sequel; - rubocop-i18n; The rubocop-migrations dependency has been eliminated, as it appears to be a dead project, and also appears to be superfluous. --- Gemfile | 5 ++-- Gemfile.lock | 31 +++++++++----------- lib/cc/engine/category_parser.rb | 3 +- spec/support/currently_undocumented_cops.txt | 2 +- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/Gemfile b/Gemfile index 9f2ee8db..9f322af2 100644 --- a/Gemfile +++ b/Gemfile @@ -6,15 +6,14 @@ gem "activesupport", require: false gem "mry", require: false gem "parser" gem "pry", require: false -gem "rubocop", "0.92.0", require: false +gem "rubocop", "1.7.0", require: false gem "rubocop-i18n", require: false -gem "rubocop-migrations", require: false gem "rubocop-minitest", require: false gem "rubocop-performance", require: false gem "rubocop-rails", require: false gem "rubocop-rake", require: false gem "rubocop-rspec", require: false -gem "rubocop-sequel", require: false +gem "rubocop-sequel", "0.1.0", require: false gem 'rubocop-sorbet', require: false gem "rubocop-thread_safety", require: false gem "safe_yaml" diff --git a/Gemfile.lock b/Gemfile.lock index e5e11d78..2ca8383d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,8 +17,8 @@ GEM minitest (5.14.1) mry (0.78.0.0) rubocop (>= 0.41.0) - parallel (1.19.2) - parser (2.7.1.5) + parallel (1.20.1) + parser (3.0.0.0) ast (~> 2.4.1) pry (0.13.1) coderay (~> 1.1) @@ -26,7 +26,7 @@ GEM rack (2.2.3) rainbow (3.0.0) rake (13.0.1) - regexp_parser (1.8.1) + regexp_parser (2.0.3) rexml (3.2.4) rspec (3.9.0) rspec-core (~> 3.9.0) @@ -41,21 +41,19 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.9.0) rspec-support (3.9.3) - rubocop (0.92.0) + rubocop (1.7.0) parallel (~> 1.10) parser (>= 2.7.1.5) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.7) + regexp_parser (>= 1.8, < 3.0) rexml - rubocop-ast (>= 0.5.0) + rubocop-ast (>= 1.2.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 2.0) - rubocop-ast (0.7.1) + rubocop-ast (1.4.0) parser (>= 2.7.1.5) - rubocop-i18n (2.0.2) - rubocop (~> 0.51) - rubocop-migrations (0.1.2) - rubocop (~> 0.41) + rubocop-i18n (3.0.0) + rubocop (~> 1.0) rubocop-minitest (0.9.0) rubocop (>= 0.74) rubocop-performance (1.7.0) @@ -68,13 +66,13 @@ GEM rubocop rubocop-rspec (1.41.0) rubocop (>= 0.68.1) - rubocop-sequel (0.0.6) - rubocop (~> 0.55, >= 0.55) + rubocop-sequel (0.1.0) + rubocop (~> 1.0) rubocop-sorbet (0.5.1) rubocop rubocop-thread_safety (0.4.1) rubocop (>= 0.51.0) - ruby-progressbar (1.10.1) + ruby-progressbar (1.11.0) safe_yaml (1.0.5) test-prof (0.11.3) thread_safe (0.3.6) @@ -93,15 +91,14 @@ DEPENDENCIES pry rake rspec - rubocop (= 0.92.0) + rubocop (= 1.7.0) rubocop-i18n - rubocop-migrations rubocop-minitest rubocop-performance rubocop-rails rubocop-rake rubocop-rspec - rubocop-sequel + rubocop-sequel (= 0.1.0) rubocop-sorbet rubocop-thread_safety safe_yaml diff --git a/lib/cc/engine/category_parser.rb b/lib/cc/engine/category_parser.rb index 3139ccab..533259d6 100644 --- a/lib/cc/engine/category_parser.rb +++ b/lib/cc/engine/category_parser.rb @@ -26,8 +26,7 @@ def category "Rails/HasAndBelongsToMany" => "Style", "Rails/TimeZone" => "Style", "Rails/Validation" => "Style", - "Style" => "Style", - "Migrations/RemoveIndex" => "Performance", + "Style" => "Style" }.freeze attr_reader :cop_name diff --git a/spec/support/currently_undocumented_cops.txt b/spec/support/currently_undocumented_cops.txt index 48c12199..4d4ff1a7 100644 --- a/spec/support/currently_undocumented_cops.txt +++ b/spec/support/currently_undocumented_cops.txt @@ -1,3 +1,3 @@ RuboCop::Cop::Lint::Syntax -RuboCop::Cop::Migration::DepartmentName RuboCop::Cop::Style::ConditionalAssignment +RuboCop::Cop::Migration::DepartmentName From 1c752213c22908fbefe6c38ab3c34169899778cd Mon Sep 17 00:00:00 2001 From: Daniel Wright Date: Tue, 24 Nov 2020 11:26:40 -0800 Subject: [PATCH 2/5] Updates Scraped Documentation --- config/contents/bundler/duplicated_gem.md | 11 ++- .../contents/gemspec/required_ruby_version.md | 5 +- config/contents/layout/else_alignment.md | 2 +- .../layout/empty_line_between_defs.md | 64 +++++++++++++-- .../contents/layout/space_around_operators.md | 2 + .../contents/layout/space_before_brackets.md | 14 ++++ config/contents/layout/space_inside_parens.md | 2 + config/contents/layout/trailing_whitespace.md | 15 +++- config/contents/lint/ambiguous_assignment.md | 14 ++++ .../lint/ambiguous_block_association.md | 2 + ...binary_operator_with_identical_operands.md | 5 ++ .../lint/constant_definition_in_block.md | 13 ++- config/contents/lint/debugger.md | 1 + config/contents/lint/duplicate_branch.md | 79 +++++++++++++++++++ ...uplicate_regexp_character_class_element.md | 15 ++++ config/contents/lint/else_layout.md | 17 +++- config/contents/lint/empty_block.md | 44 +++++++++++ config/contents/lint/empty_class.md | 65 +++++++++++++++ config/contents/lint/flip_flop.md | 10 ++- .../contents/lint/hash_compare_by_identity.md | 15 ++++ config/contents/lint/loop.md | 4 + config/contents/lint/missing_super.md | 5 ++ .../contents/lint/nested_percent_literal.md | 15 +++- .../lint/no_return_in_begin_end_blocks.md | 36 +++++++++ config/contents/lint/number_conversion.md | 23 +++++- .../lint/redundant_safe_navigation.md | 30 +++++++ .../lint/redundant_splat_expansion.md | 54 ++++++++----- .../lint/shadowing_outer_local_variable.md | 8 ++ config/contents/lint/to_enum_arguments.md | 14 ++++ .../contents/lint/unexpected_block_arity.md | 29 +++++++ .../lint/unmodified_reduce_accumulator.md | 59 ++++++++++++++ config/contents/lint/unreachable_loop.md | 14 ++++ config/contents/lint/useless_setter_call.md | 1 + config/contents/metrics/abc_size.md | 23 +++++- config/contents/metrics/block_length.md | 8 +- config/contents/metrics/class_length.md | 3 + config/contents/metrics/method_length.md | 3 + config/contents/metrics/parameter_lists.md | 45 ++++++++++- .../contents/naming/accessor_method_name.md | 16 +++- .../naming/memoized_instance_variable_name.md | 57 ++++++++++++- config/contents/naming/variable_number.md | 70 ++++++++++++++-- config/contents/security/open.md | 13 +-- config/contents/style/accessor_grouping.md | 3 + config/contents/style/arguments_forwarding.md | 34 ++++++++ .../style/class_equality_comparison.md | 12 +++ config/contents/style/collection_compact.md | 23 ++++++ config/contents/style/combinable_loops.md | 6 ++ config/contents/style/comment_annotation.md | 6 ++ config/contents/style/commented_keyword.md | 5 +- .../style/document_dynamic_eval_definition.md | 71 +++++++++++++++++ config/contents/style/documentation.md | 5 ++ config/contents/style/format_string_token.md | 25 +++++- config/contents/style/hash_except.md | 19 +++++ .../style/identical_conditional_branches.md | 9 ++- config/contents/style/if_unless_modifier.md | 10 ++- config/contents/style/infinite_loop.md | 4 + .../style/keyword_parameters_order.md | 10 +++ .../method_call_with_args_parentheses.md | 3 + .../contents/style/method_def_parentheses.md | 3 + config/contents/style/multiple_comparison.md | 30 ++++++- config/contents/style/mutable_constant.md | 2 + .../style/negated_if_else_condition.md | 23 ++++++ config/contents/style/nil_lambda.md | 18 +++++ config/contents/style/perl_backrefs.md | 3 +- config/contents/style/raise_args.md | 19 +++-- config/contents/style/redundant_argument.md | 37 +++++++++ config/contents/style/redundant_begin.md | 8 ++ config/contents/style/redundant_freeze.md | 4 +- .../style/redundant_regexp_character_class.md | 6 ++ config/contents/style/single_line_methods.md | 3 + config/contents/style/special_global_vars.md | 8 -- config/contents/style/static_class.md | 38 +++++++++ config/contents/style/string_concatenation.md | 8 ++ config/contents/style/swap_values.md | 12 +++ config/contents/style/symbol_proc.md | 1 + config/contents/style/while_until_modifier.md | 11 ++- 76 files changed, 1324 insertions(+), 80 deletions(-) create mode 100644 config/contents/layout/space_before_brackets.md create mode 100644 config/contents/lint/ambiguous_assignment.md create mode 100644 config/contents/lint/duplicate_branch.md create mode 100644 config/contents/lint/duplicate_regexp_character_class_element.md create mode 100644 config/contents/lint/empty_block.md create mode 100644 config/contents/lint/empty_class.md create mode 100644 config/contents/lint/hash_compare_by_identity.md create mode 100644 config/contents/lint/no_return_in_begin_end_blocks.md create mode 100644 config/contents/lint/redundant_safe_navigation.md create mode 100644 config/contents/lint/to_enum_arguments.md create mode 100644 config/contents/lint/unexpected_block_arity.md create mode 100644 config/contents/lint/unmodified_reduce_accumulator.md create mode 100644 config/contents/style/arguments_forwarding.md create mode 100644 config/contents/style/class_equality_comparison.md create mode 100644 config/contents/style/collection_compact.md create mode 100644 config/contents/style/document_dynamic_eval_definition.md create mode 100644 config/contents/style/hash_except.md create mode 100644 config/contents/style/negated_if_else_condition.md create mode 100644 config/contents/style/nil_lambda.md create mode 100644 config/contents/style/redundant_argument.md create mode 100644 config/contents/style/static_class.md create mode 100644 config/contents/style/swap_values.md diff --git a/config/contents/bundler/duplicated_gem.md b/config/contents/bundler/duplicated_gem.md index 48232730..a747716a 100644 --- a/config/contents/bundler/duplicated_gem.md +++ b/config/contents/bundler/duplicated_gem.md @@ -19,4 +19,13 @@ A Gem's requirements should be listed only once in a Gemfile. end # good - gem 'rubocop', groups: [:development, :test] \ No newline at end of file + gem 'rubocop', groups: [:development, :test] + + # good - conditional declaration + if Dir.exist?(local) + gem 'rubocop', path: local + elsif ENV['RUBOCOP_VERSION'] == 'master' + gem 'rubocop', git: 'https://github.com/rubocop-hq/rubocop.git' + else + gem 'rubocop', '~> 0.90.0' + end diff --git a/config/contents/gemspec/required_ruby_version.md b/config/contents/gemspec/required_ruby_version.md index 0acad2e6..d8941d27 100644 --- a/config/contents/gemspec/required_ruby_version.md +++ b/config/contents/gemspec/required_ruby_version.md @@ -31,12 +31,13 @@ required by gemspec. spec.required_ruby_version = '>= 2.5' end - # good + # accepted but not recommended Gem::Specification.new do |spec| spec.required_ruby_version = ['>= 2.5.0', '< 2.7.0'] end - # good + # accepted but not recommended, since + # Ruby does not really follow semantic versionning Gem::Specification.new do |spec| spec.required_ruby_version = '~> 2.5' end \ No newline at end of file diff --git a/config/contents/layout/else_alignment.md b/config/contents/layout/else_alignment.md index 6c577dd9..ea5c1996 100644 --- a/config/contents/layout/else_alignment.md +++ b/config/contents/layout/else_alignment.md @@ -1,5 +1,5 @@ This cop checks the alignment of else keywords. Normally they should -be aligned with an if/unless/while/until/begin/def keyword, but there +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_line_between_defs.md b/config/contents/layout/empty_line_between_defs.md index 7178e842..100f67b8 100644 --- a/config/contents/layout/empty_line_between_defs.md +++ b/config/contents/layout/empty_line_between_defs.md @@ -1,14 +1,15 @@ -This cop checks whether method definitions are -separated by one empty line. +This cop checks whether class/module/method definitions are +separated by one or more empty lines. `NumberOfEmptyLines` can be an integer (default is 1) or an array (e.g. [1, 2]) to specify a minimum and maximum number of empty lines permitted. `AllowAdjacentOneLineDefs` configures whether adjacent -one-line method definitions are considered an offense. +one-line definitions are considered an offense. -### Example: +### Example: EmptyLineBetweenMethodDefs: true (default) + # checks for empty lines between method definitions. # bad def a @@ -23,4 +24,57 @@ one-line method definitions are considered an offense. end def b - end \ No newline at end of file + end + +### Example: EmptyLineBetweenClassDefs: true (default) + # checks for empty lines between class definitions. + + # bad + class A + end + class B + end + def b + end + +### Example: + + # good + class A + end + + class B + end + + def b + end + +### Example: EmptyLineBetweenModuleDefs: true (default) + # checks for empty lines between module definitions. + + # bad + module A + end + module B + end + def b + end + +### Example: + + # good + module A + end + + module B + end + + def b + end + +### Example: AllowAdjacentOneLineDefs: true + + # good + class ErrorA < BaseError; end + class ErrorB < BaseError; end + class ErrorC < BaseError; end diff --git a/config/contents/layout/space_around_operators.md b/config/contents/layout/space_around_operators.md index f1262abb..dea89ac5 100644 --- a/config/contents/layout/space_around_operators.md +++ b/config/contents/layout/space_around_operators.md @@ -1,5 +1,7 @@ Checks that operators have space around them, except for ** which should or shouldn't have surrounding space depending on configuration. +It allows vertical alignment consisting of one or more whitespace +around operators. This cop has `AllowForAlignment` option. When `true`, allows most uses of extra spacing if the intent is to align with an operator on diff --git a/config/contents/layout/space_before_brackets.md b/config/contents/layout/space_before_brackets.md new file mode 100644 index 00000000..ab554e34 --- /dev/null +++ b/config/contents/layout/space_before_brackets.md @@ -0,0 +1,14 @@ +Checks for space between the name of a receiver and a left +brackets. + +This cop is marked as unsafe because it can occur false positives +for `do_something [this_is_an_array_literal_argument]` that take +an array without parentheses as an argument. + +### Example: + + # bad + collection [index_or_key] + + # good + collection[index_or_key] diff --git a/config/contents/layout/space_inside_parens.md b/config/contents/layout/space_inside_parens.md index 4ce52d6e..e6f96af2 100644 --- a/config/contents/layout/space_inside_parens.md +++ b/config/contents/layout/space_inside_parens.md @@ -6,10 +6,12 @@ Checks for spaces inside ordinary round parentheses. # bad f( 3) g = (a + 3 ) + f( ) # good f(3) g = (a + 3) + f() ### Example: EnforcedStyle: space # The `space` style enforces that parentheses have a space at the diff --git a/config/contents/layout/trailing_whitespace.md b/config/contents/layout/trailing_whitespace.md index dc2e635d..f815bb2b 100644 --- a/config/contents/layout/trailing_whitespace.md +++ b/config/contents/layout/trailing_whitespace.md @@ -9,14 +9,25 @@ This cop looks for trailing whitespace in the source code. # good x = 0 -### Example: AllowInHeredoc: false +### Example: AllowInHeredoc: false (default) # The line in this example contains spaces after the 0. # bad code = <<~RUBY x = 0 RUBY -### Example: AllowInHeredoc: true (default) + # ok + code = <<~RUBY + x = 0 #{} + RUBY + + # good + trailing_whitespace = ' ' + code = <<~RUBY + x = 0#{trailing_whitespace} + RUBY + +### Example: AllowInHeredoc: true # The line in this example contains spaces after the 0. # good code = <<~RUBY diff --git a/config/contents/lint/ambiguous_assignment.md b/config/contents/lint/ambiguous_assignment.md new file mode 100644 index 00000000..f57b029e --- /dev/null +++ b/config/contents/lint/ambiguous_assignment.md @@ -0,0 +1,14 @@ +This cop checks for mistyped shorthand assignments. + +### Example: + # bad + x =- y + x =+ y + x =* y + x =! y + + # good + x -= y # or x = -y + x += y # or x = +y + x *= y # or x = *y + x != y # or x = !y diff --git a/config/contents/lint/ambiguous_block_association.md b/config/contents/lint/ambiguous_block_association.md index 455ef0d2..825211b4 100644 --- a/config/contents/lint/ambiguous_block_association.md +++ b/config/contents/lint/ambiguous_block_association.md @@ -10,6 +10,8 @@ when param passed without parentheses. # good # With parentheses, there's no ambiguity. + some_method(a { |val| puts val }) + # or (different meaning) some_method(a) { |val| puts val } # good diff --git a/config/contents/lint/binary_operator_with_identical_operands.md b/config/contents/lint/binary_operator_with_identical_operands.md index e9f48553..cc871f7f 100644 --- a/config/contents/lint/binary_operator_with_identical_operands.md +++ b/config/contents/lint/binary_operator_with_identical_operands.md @@ -12,6 +12,7 @@ and thus can generate false positives: ### Example: # bad + x / x x.top >= x.top if a.x != 0 && a.x != 0 @@ -21,3 +22,7 @@ and thus can generate false positives: def childs? left_child || left_child end + + # good + x + x + 1 << 1 diff --git a/config/contents/lint/constant_definition_in_block.md b/config/contents/lint/constant_definition_in_block.md index 27ca1649..7884b8bd 100644 --- a/config/contents/lint/constant_definition_in_block.md +++ b/config/contents/lint/constant_definition_in_block.md @@ -43,4 +43,15 @@ For meta-programming, use `const_set`. included do const_set(:LIST, []) end - end \ No newline at end of file + end + +### Example: AllowedMethods: ['enums'] (default) + # good + + # `enums` for Typed Enums via `T::Enum` in Sorbet. + # https://sorbet.org/docs/tenum + class TestEnum < T::Enum + enums do + Foo = new("foo") + end + end diff --git a/config/contents/lint/debugger.md b/config/contents/lint/debugger.md index a66591c9..8fbe7586 100644 --- a/config/contents/lint/debugger.md +++ b/config/contents/lint/debugger.md @@ -1,4 +1,5 @@ This cop checks for calls to debugger or pry. +The cop can be configured to define which methods and receivers must be fixed. ### Example: diff --git a/config/contents/lint/duplicate_branch.md b/config/contents/lint/duplicate_branch.md new file mode 100644 index 00000000..5e72d487 --- /dev/null +++ b/config/contents/lint/duplicate_branch.md @@ -0,0 +1,79 @@ +This cop checks that there are no repeated bodies +within `if/unless`, `case-when` and `rescue` constructs. + +With `IgnoreLiteralBranches: true`, branches are not registered +as offenses if they return a basic literal value (string, symbol, +integer, float, rational, complex, `true`, `false`, or `nil`), or +return an array, hash, regexp or range that only contains one of +the above basic literal values. + +With `IgnoreConstantBranches: true`, branches are not registered +as offenses if they return a constant value. + +### Example: + # bad + if foo + do_foo + do_something_else + elsif bar + do_foo + do_something_else + end + + # good + if foo || bar + do_foo + do_something_else + end + + # bad + case x + when foo + do_foo + when bar + do_foo + else + do_something_else + end + + # good + case x + when foo, bar + do_foo + else + do_something_else + end + + # bad + begin + do_something + rescue FooError + handle_error + rescue BarError + handle_error + end + + # good + begin + do_something + rescue FooError, BarError + handle_error + end + +### Example: IgnoreLiteralBranches: true + # good + case size + when "small" then 100 + when "medium" then 250 + when "large" then 1000 + else 250 + end + +### Example: IgnoreLiteralBranches: true + # good + case size + when "small" then SMALL_SIZE + when "medium" then MEDIUM_SIZE + when "large" then LARGE_SIZE + else MEDIUM_SIZE + end diff --git a/config/contents/lint/duplicate_regexp_character_class_element.md b/config/contents/lint/duplicate_regexp_character_class_element.md new file mode 100644 index 00000000..f20875a2 --- /dev/null +++ b/config/contents/lint/duplicate_regexp_character_class_element.md @@ -0,0 +1,15 @@ +This cop checks for duplicate elements in Regexp character classes. + +### Example: + + # bad + r = /[xyx]/ + + # bad + r = /[0-9x0-9]/ + + # good + r = /[xy]/ + + # good + r = /[0-9x]/ \ No newline at end of file diff --git a/config/contents/lint/else_layout.md b/config/contents/lint/else_layout.md index ba728d37..9ed76256 100644 --- a/config/contents/lint/else_layout.md +++ b/config/contents/lint/else_layout.md @@ -1,7 +1,11 @@ -This cop checks for odd else block layout - like -having an expression on the same line as the else keyword, +This cop 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 +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. + ### Example: # bad @@ -16,9 +20,18 @@ which is usually a mistake. # good + # This code is compatible with the bad case. It will be auto-corrected like this. if something # ... else do_this do_that + end + + # This code is incompatible with the bad case. + # If `do_this` is a condition, `elsif` should be used instead of `else`. + if something + # ... + elsif do_this + do_that end \ No newline at end of file diff --git a/config/contents/lint/empty_block.md b/config/contents/lint/empty_block.md new file mode 100644 index 00000000..77ebce3d --- /dev/null +++ b/config/contents/lint/empty_block.md @@ -0,0 +1,44 @@ +This cop 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. + +Empty lambdas are ignored by default. + +### Example: + # bad + items.each { |item| } + + # good + items.each { |item| puts item } + +### Example: AllowComments: true (default) + # good + items.each do |item| + # TODO: implement later (inner comment) + end + + items.each { |item| } # TODO: implement later (inline comment) + +### Example: AllowComments: false + # bad + items.each do |item| + # TODO: implement later (inner comment) + end + + items.each { |item| } # TODO: implement later (inline comment) + +### Example: AllowEmptyLambdas: true (default) + # good + allow(subject).to receive(:callable).and_return(-> {}) + + placeholder = lambda do + end + (callable || placeholder).call + +### Example: AllowEmptyLambdas: false + # bad + allow(subject).to receive(:callable).and_return(-> {}) + + placeholder = lambda do + end + (callable || placeholder).call diff --git a/config/contents/lint/empty_class.md b/config/contents/lint/empty_class.md new file mode 100644 index 00000000..a4c86992 --- /dev/null +++ b/config/contents/lint/empty_class.md @@ -0,0 +1,65 @@ +This cop 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. + +### Example: + # bad + class Foo + end + + class Bar + class << self + end + end + + class << obj + end + + # good + class Foo + def do_something + # ... code + end + end + + class Bar + class << self + attr_reader :bar + end + end + + class << obj + attr_reader :bar + end + +### Example: AllowComments: false (default) + # bad + class Foo + # TODO: implement later + end + + class Bar + class << self + # TODO: implement later + end + end + + class << obj + # TODO: implement later + end + +### Example: AllowComments: true + # good + class Foo + # TODO: implement later + end + + class Bar + class << self + # TODO: implement later + end + end + + class << obj + # TODO: implement later + end diff --git a/config/contents/lint/flip_flop.md b/config/contents/lint/flip_flop.md index 7011c2ea..15b3174a 100644 --- a/config/contents/lint/flip_flop.md +++ b/config/contents/lint/flip_flop.md @@ -1,5 +1,11 @@ -This cop looks for uses of flip-flop operator. -flip-flop operator is deprecated since Ruby 2.6.0. +This cop looks for uses of flip-flop operator +based on the Ruby Style Guide. + +Here is the history of flip-flops in Ruby. +flip-flop operator is deprecated in Ruby 2.6.0 and +the deprecation has been reverted by Ruby 2.7.0 and +backported to Ruby 2.6. +See: https://bugs.ruby-lang.org/issues/5400 ### Example: # bad diff --git a/config/contents/lint/hash_compare_by_identity.md b/config/contents/lint/hash_compare_by_identity.md new file mode 100644 index 00000000..99f6e2bd --- /dev/null +++ b/config/contents/lint/hash_compare_by_identity.md @@ -0,0 +1,15 @@ +Prefer using `Hash#compare_by_identity` 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. + +### Example: + # bad + hash = {} + hash[foo.object_id] = :bar + hash.key?(baz.object_id) + + # good + hash = {}.compare_by_identity + hash[foo] = :bar + hash.key?(baz) diff --git a/config/contents/lint/loop.md b/config/contents/lint/loop.md index 4b46e0e2..dfea642e 100644 --- a/config/contents/lint/loop.md +++ b/config/contents/lint/loop.md @@ -1,5 +1,9 @@ This cop 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). + ### Example: # bad diff --git a/config/contents/lint/missing_super.md b/config/contents/lint/missing_super.md index c379b7c2..d305e8c3 100644 --- a/config/contents/lint/missing_super.md +++ b/config/contents/lint/missing_super.md @@ -1,6 +1,11 @@ This cop checks for the presence of constructors and lifecycle callbacks without calls to `super`. +This cop does not consider `method_missing` (and `respond_to_missing?`) +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. + ### Example: # bad class Employee < Person diff --git a/config/contents/lint/nested_percent_literal.md b/config/contents/lint/nested_percent_literal.md index 3aad373f..b42a58de 100644 --- a/config/contents/lint/nested_percent_literal.md +++ b/config/contents/lint/nested_percent_literal.md @@ -9,4 +9,17 @@ This cop checks for nested percent literals. attributes = { valid_attributes: %i[name content], nested_attributes: %i[name content %i[incorrectly nested]] - } \ No newline at end of file + } + + # good + + # Neither is incompatible with the bad case, but probably the intended code. + attributes = { + valid_attributes: %i[name content], + nested_attributes: [:name, :content, %i[incorrectly nested]] + } + + attributes = { + valid_attributes: %i[name content], + nested_attributes: [:name, :content, [:incorrectly, :nested]] + } diff --git a/config/contents/lint/no_return_in_begin_end_blocks.md b/config/contents/lint/no_return_in_begin_end_blocks.md new file mode 100644 index 00000000..40bc70cc --- /dev/null +++ b/config/contents/lint/no_return_in_begin_end_blocks.md @@ -0,0 +1,36 @@ +Checks for the presence of a `return` inside a `begin..end` block +in assignment contexts. +In this situation, the `return` will result in an exit from the current +method, possibly leading to unexpected behavior. + +### Example: + + # bad + + @some_variable ||= begin + return some_value if some_condition_is_met + + do_something + end + +### Example: + + # good + + @some_variable ||= begin + if some_condition_is_met + some_value + else + do_something + end + end + + # good + + some_variable = if some_condition_is_met + return if another_condition_is_met + + some_value + else + do_something + end diff --git a/config/contents/lint/number_conversion.md b/config/contents/lint/number_conversion.md index 71e1f319..2dc5a88d 100644 --- a/config/contents/lint/number_conversion.md +++ b/config/contents/lint/number_conversion.md @@ -2,6 +2,17 @@ This cop 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`). +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`. + ### Example: # bad @@ -14,4 +25,14 @@ fails. Cop prefer parsing with number class instead. Integer('10', 10) Float('10.2') - Complex('10') \ No newline at end of file + Complex('10') + +### Example: IgnoredMethods: [minutes] + + # good + 10.minutes.to_i + +### Example: IgnoredClasses: [Time, DateTime] (default) + + # good + Time.now.to_datetime.to_i \ No newline at end of file diff --git a/config/contents/lint/redundant_safe_navigation.md b/config/contents/lint/redundant_safe_navigation.md new file mode 100644 index 00000000..f23497af --- /dev/null +++ b/config/contents/lint/redundant_safe_navigation.md @@ -0,0 +1,30 @@ +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. + +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`. + +In the example below, the safe navigation operator (`&.`) is unnecessary +because `NilClass` has methods like `respond_to?` and `is_a?`. + +### Example: + # bad + do_something if attrs&.respond_to?(:[]) + + # good + do_something if attrs.respond_to?(:[]) + + # bad + while node&.is_a?(BeginNode) + node = node.parent + end + + # good + while node.is_a?(BeginNode) + node = node.parent + end + + # good - without `&.` this will always return `true` + foo&.respond_to?(:to_a) diff --git a/config/contents/lint/redundant_splat_expansion.md b/config/contents/lint/redundant_splat_expansion.md index cc192824..f4b447f9 100644 --- a/config/contents/lint/redundant_splat_expansion.md +++ b/config/contents/lint/redundant_splat_expansion.md @@ -3,44 +3,62 @@ This cop checks for unneeded usages of splat expansion ### Example: # bad - a = *[1, 2, 3] a = *'a' a = *1 - - begin - foo - rescue *[StandardError, ApplicationError] - bar - end - - case foo - when *[1, 2, 3] - bar - else - baz - end - -### Example: + ['a', 'b', *%w(c d e), 'f', 'g'] # good - c = [1, 2, 3] a = *c a, b = *c a, *b = *c a = *1..10 a = ['a'] + ['a', 'b', 'c', 'd', 'e', 'f', 'g'] + # bad + do_something(*['foo', 'bar', 'baz']) + + # good + do_something('foo', 'bar', 'baz') + + # bad + begin + foo + rescue *[StandardError, ApplicationError] + bar + end + + # good begin foo rescue StandardError, ApplicationError bar end + # bad + case foo + when *[1, 2, 3] + bar + else + baz + end + + # good case foo when 1, 2, 3 bar else baz - end \ No newline at end of file + end + +### Example: AllowPercentLiteralArrayArgument: true (default) + + # good + do_something(*%w[foo bar baz]) + +### Example: AllowPercentLiteralArrayArgument: false + + # bad + do_something(*%w[foo bar baz]) diff --git a/config/contents/lint/shadowing_outer_local_variable.md b/config/contents/lint/shadowing_outer_local_variable.md index 8579b4e1..6581f7f8 100644 --- a/config/contents/lint/shadowing_outer_local_variable.md +++ b/config/contents/lint/shadowing_outer_local_variable.md @@ -3,6 +3,14 @@ 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: + + worker_id, pipe = env + Ractor.new(worker_id, pipe) do |worker_id, pipe| + end + ### Example: # bad diff --git a/config/contents/lint/to_enum_arguments.md b/config/contents/lint/to_enum_arguments.md new file mode 100644 index 00000000..d647a9dc --- /dev/null +++ b/config/contents/lint/to_enum_arguments.md @@ -0,0 +1,14 @@ +This cop ensures that `to_enum`/`enum_for`, called for the current method, +has correct arguments. + +### Example: + # bad + def foo(x, y = 1) + return to_enum(__callee__, x) # `y` is missing + end + + # good + def foo(x, y = 1) + return to_enum(__callee__, x, y) + # alternatives to `__callee__` are `__method__` and `:foo` + end diff --git a/config/contents/lint/unexpected_block_arity.md b/config/contents/lint/unexpected_block_arity.md new file mode 100644 index 00000000..54552b7f --- /dev/null +++ b/config/contents/lint/unexpected_block_arity.md @@ -0,0 +1,29 @@ +This cop 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 +be used. Blocks that have no receiver, or take splatted arguments +(ie. `*args`) are always accepted. + +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: + +Methods: + inject: 2 + reduce: 2 + +### Example: + # bad + values.reduce {} + values.min { |a| a } + values.sort { |a; b| a + b } + + # good + values.reduce { |memo, obj| memo << obj } + values.min { |a, b| a <=> b } + values.sort { |*x| x[0] <=> x[1] } diff --git a/config/contents/lint/unmodified_reduce_accumulator.md b/config/contents/lint/unmodified_reduce_accumulator.md new file mode 100644 index 00000000..8999d664 --- /dev/null +++ b/config/contents/lint/unmodified_reduce_accumulator.md @@ -0,0 +1,59 @@ +Looks for `reduce` or `inject` blocks where the value returned (implicitly or +explicitly) does not include the accumulator. A block is considered valid as +long as at least one return value includes the accumulator. + +If the accumulator is not included in the return value, then the entire +block will just return a transformation of the last element value, and +could be rewritten as such without a loop. + +Also catches instances where an index of the accumulator is returned, as +this may change the type of object being retained. + +NOTE: For the purpose of reducing false positives, this cop only flags +returns in `reduce` blocks where the element is the only variable in +the expression (since we will not be able to tell what other variables +relate to via static analysis). + +### Example: + + # bad + (1..4).reduce(0) do |acc, el| + el * 2 + end + + # bad, may raise a NoMethodError after the first iteration + %w(a b c).reduce({}) do |acc, letter| + acc[letter] = true + end + + # good + (1..4).reduce(0) do |acc, el| + acc + el * 2 + end + + # good, element is returned but modified using the accumulator + values.reduce do |acc, el| + el << acc + el + end + + # good, returns the accumulator instead of the index + %w(a b c).reduce({}) do |acc, letter| + acc[letter] = true + acc + end + + # good, at least one branch returns the accumulator + values.reduce(nil) do |result, value| + break result if something? + value + end + + # good, recursive + keys.reduce(self) { |result, key| result[key] } + + # ignored as the return value cannot be determined + enum.reduce do |acc, el| + x = foo(acc, el) + bar(x) + end \ No newline at end of file diff --git a/config/contents/lint/unreachable_loop.md b/config/contents/lint/unreachable_loop.md index 23711211..5545d009 100644 --- a/config/contents/lint/unreachable_loop.md +++ b/config/contents/lint/unreachable_loop.md @@ -4,6 +4,12 @@ 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. + +`IgnoredPatterns` 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). + ### Example: # bad while node @@ -64,3 +70,11 @@ the code should be refactored to use `if` conditionals. end raise NotFoundError end + + # bad + 2.times { raise ArgumentError } + +### Example: IgnoredPatterns: [/(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/useless_setter_call.md b/config/contents/lint/useless_setter_call.md index 554705f6..e508a164 100644 --- a/config/contents/lint/useless_setter_call.md +++ b/config/contents/lint/useless_setter_call.md @@ -1,5 +1,6 @@ This cop 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 diff --git a/config/contents/metrics/abc_size.md b/config/contents/metrics/abc_size.md index ec4d7fea..8aec6e0f 100644 --- a/config/contents/metrics/abc_size.md +++ b/config/contents/metrics/abc_size.md @@ -1,4 +1,25 @@ This cop checks that the ABC size of methods is not higher than the configured maximum. The ABC size is based on assignments, branches (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric -and https://en.wikipedia.org/wiki/ABC_Software_Metric. \ No newline at end of file +and https://en.wikipedia.org/wiki/ABC_Software_Metric. + +You can have repeated "attributes" calls count as a single "branch". +For this purpose, attributes are any method with no argument; no attempt +is meant to distinguish actual `attr_reader` from other methods. + +### Example: CountRepeatedAttributes: false (default is true) + + # `model` and `current_user`, refenced 3 times each, + # are each counted as only 1 branch each if + # `CountRepeatedAttributes` is set to 'false' + + def search + @posts = model.active.visible_by(current_user) + .search(params[:q]) + @posts = model.some_process(@posts, current_user) + @posts = model.another_process(@posts, current_user) + + render 'pages/search/page' + end + +This cop also takes into account `IgnoredMethods` (defaults to `[]`) \ No newline at end of file diff --git a/config/contents/metrics/block_length.md b/config/contents/metrics/block_length.md index 710cb790..79cf3e4b 100644 --- a/config/contents/metrics/block_length.md +++ b/config/contents/metrics/block_length.md @@ -7,6 +7,10 @@ You can set literals you want to fold with `CountAsOne`. Available are: 'array', 'hash', and 'heredoc'. Each literal will be counted as one line regardless of its actual size. + +NOTE: The `ExcludedMethods` configuration is deprecated and only kept +for backwards compatibility. Please use `IgnoredMethods` instead. + ### Example: CountAsOne: ['array', 'heredoc'] something do @@ -23,4 +27,6 @@ will be counted as one line regardless of its actual size. Heredoc content. HEREDOC - end # 5 points \ No newline at end of file + end # 5 points + +NOTE: This cop does not apply for `Struct` definitions. \ No newline at end of file diff --git a/config/contents/metrics/class_length.md b/config/contents/metrics/class_length.md index 1417d3bc..7aa17c2c 100644 --- a/config/contents/metrics/class_length.md +++ b/config/contents/metrics/class_length.md @@ -23,3 +23,6 @@ will be counted as one line regardless of its actual size. content. HEREDOC end # 5 points + + +NOTE: This cop also applies for `Struct` definitions. \ No newline at end of file diff --git a/config/contents/metrics/method_length.md b/config/contents/metrics/method_length.md index b5e80657..74c86cde 100644 --- a/config/contents/metrics/method_length.md +++ b/config/contents/metrics/method_length.md @@ -6,6 +6,9 @@ You can set literals you want to fold with `CountAsOne`. Available are: 'array', 'hash', and 'heredoc'. Each literal will be counted as one line regardless of its actual size. +NOTE: The `ExcludedMethods` configuration is deprecated and only kept +for backwards compatibility. Please use `IgnoredMethods` instead. + ### Example: CountAsOne: ['array', 'heredoc'] def m diff --git a/config/contents/metrics/parameter_lists.md b/config/contents/metrics/parameter_lists.md index 6fad6d95..e004efba 100644 --- a/config/contents/metrics/parameter_lists.md +++ b/config/contents/metrics/parameter_lists.md @@ -1,3 +1,46 @@ This cop checks for methods with too many parameters. + The maximum number of parameters is configurable. -Keyword arguments can optionally be excluded from the total count. \ No newline at end of file +Keyword arguments can optionally be excluded from the total count, +as they add less complexity than positional or optional parameters. + +### Example: Max: 3 + # good + def foo(a, b, c = 1) + end + +### Example: Max: 2 + # bad + def foo(a, b, c = 1) + end + +### Example: CountKeywordArgs: true (default) + # counts keyword args towards the maximum + + # bad (assuming Max is 3) + def foo(a, b, c, d: 1) + end + + # good (assuming Max is 3) + def foo(a, b, c: 1) + end + +### Example: CountKeywordArgs: false + # don't count keyword args towards the maximum + + # good (assuming Max is 3) + def foo(a, b, c, d: 1) + end + +This cop also checks for the maximum number of optional parameters. +This can be configured using the `MaxOptionalParameters` config option. + +### Example: MaxOptionalParameters: 3 (default) + # good + def foo(a = 1, b = 2, c = 3) + end + +### Example: MaxOptionalParameters: 2 + # bad + def foo(a = 1, b = 2, c = 3) + end diff --git a/config/contents/naming/accessor_method_name.md b/config/contents/naming/accessor_method_name.md index 82707dfc..855ba74e 100644 --- a/config/contents/naming/accessor_method_name.md +++ b/config/contents/naming/accessor_method_name.md @@ -1,4 +1,10 @@ -This cop makes sure that accessor methods are named properly. +This cop 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 +arity. Getters (`get_attribute`) must have no arguments to be +registered, and setters (`set_attribute(value)`) must have exactly +one. ### Example: # bad @@ -15,4 +21,12 @@ This cop makes sure that accessor methods are named properly. # good def attribute + end + + # accepted, incorrect arity for getter + def get_value(attr) + end + + # accepted, incorrect arity for setter + def set_value end \ 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 fff8c66b..3550c80b 100644 --- a/config/contents/naming/memoized_instance_variable_name.md +++ b/config/contents/naming/memoized_instance_variable_name.md @@ -1,5 +1,7 @@ This cop checks for memoized methods whose instance variable name -does not match the method 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`). This cop can be configured with the EnforcedStyleForLeadingUnderscores directive. It can be configured to allow for memoized instance variables @@ -15,6 +17,11 @@ be set or referenced outside of the memoization method. @something ||= calculate_expensive_thing end + def foo + return @something if defined?(@something) + @something = calculate_expensive_thing + end + # good def _foo @foo ||= calculate_expensive_thing @@ -38,6 +45,17 @@ be set or referenced outside of the memoization method. @foo ||= calculate_expensive_thing(helper_variable) end + # good + define_method(:foo) do + @foo ||= calculate_expensive_thing + end + + # good + define_method(:foo) do + return @foo if defined?(@foo) + @foo = calculate_expensive_thing + end + ### Example: EnforcedStyleForLeadingUnderscores: required # bad def foo @@ -49,6 +67,11 @@ be set or referenced outside of the memoization method. @foo ||= calculate_expensive_thing end + def foo + return @foo if defined?(@foo) + @foo = calculate_expensive_thing + end + # good def foo @_foo ||= calculate_expensive_thing @@ -59,6 +82,22 @@ be set or referenced outside of the memoization method. @_foo ||= calculate_expensive_thing end + def foo + return @_foo if defined?(@_foo) + @_foo = calculate_expensive_thing + end + + # good + define_method(:foo) do + @_foo ||= calculate_expensive_thing + end + + # good + define_method(:foo) do + return @_foo if defined?(@_foo) + @_foo = calculate_expensive_thing + end + ### Example: EnforcedStyleForLeadingUnderscores :optional # bad def foo @@ -78,4 +117,20 @@ be set or referenced outside of the memoization method. # good def _foo @_foo ||= calculate_expensive_thing + end + + # good + def foo + return @_foo if defined?(@_foo) + @_foo = calculate_expensive_thing + end + + # good + define_method(:foo) do + @foo ||= calculate_expensive_thing + end + + # good + define_method(:foo) do + @_foo ||= calculate_expensive_thing end \ No newline at end of file diff --git a/config/contents/naming/variable_number.md b/config/contents/naming/variable_number.md index 4eb12b8c..d0145eec 100644 --- a/config/contents/naming/variable_number.md +++ b/config/contents/naming/variable_number.md @@ -2,33 +2,91 @@ This cop makes sure that all numbered variables use the configured style, snake_case, normalcase, or non_integer, for their numbering. +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 - # good + 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 variable_1 = 1 - # good + def some_method_1; end + + def some_method1(arg_1); end + # good + :some_sym1 variable1 = 1 + def some_method1; end + + def some_method1(arg1); end + ### Example: EnforcedStyle: non_integer # bad + :some_sym1 + :some_sym_1 variable1 = 1 - variable_1 = 1 + def some_method1; end + + def some_method_1; end + + def some_methodone(arg1); end + def some_methodone(arg_1); end + # good + :some_symone + :some_sym_one variableone = 1 + variable_one = 1 + + def some_methodone; end + + def some_method_one; end + + def some_methodone(argone); end + def some_methodone(arg_one); end + + # In the following examples, we assume `EnforcedStyle: normalcase` (default). + +### Example: CheckMethodNames: true (default) + # bad + def some_method_1; end - variable_one = 1 \ No newline at end of file +### Example: CheckMethodNames: false + # good + def some_method_1; end + +### Example: CheckSymbols: true (default) + # bad + :some_sym_1 + +### Example: CheckSymbols: false + # good + :some_sym_1 + +### Example: AllowedIdentifier: [capture3] + # good + expect(Open3).to receive(:capture3) diff --git a/config/contents/security/open.md b/config/contents/security/open.md index 3a207364..b5f23f2b 100644 --- a/config/contents/security/open.md +++ b/config/contents/security/open.md @@ -1,14 +1,15 @@ -This cop checks for the use of `Kernel#open`. +This cop checks for the use of `Kernel#open` and `URI.open`. -`Kernel#open` enables not only file access but also process invocation -by prefixing a pipe symbol (e.g., `open("| ls")`). So, it may lead to -a serious security risk by using variable input to the argument of -`Kernel#open`. It would be better to use `File.open`, `IO.popen` or -`URI#open` explicitly. +`Kernel#open` and `URI.open` enable not only file access but also process +invocation by prefixing a pipe symbol (e.g., `open("| ls")`). +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. ### Example: # bad open(something) + URI.open(something) # good File.open(something) diff --git a/config/contents/style/accessor_grouping.md b/config/contents/style/accessor_grouping.md index 2194571d..7649752d 100644 --- a/config/contents/style/accessor_grouping.md +++ b/config/contents/style/accessor_grouping.md @@ -2,6 +2,9 @@ This cop 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. + ### Example: EnforcedStyle: grouped (default) # bad class Foo diff --git a/config/contents/style/arguments_forwarding.md b/config/contents/style/arguments_forwarding.md new file mode 100644 index 00000000..42481859 --- /dev/null +++ b/config/contents/style/arguments_forwarding.md @@ -0,0 +1,34 @@ +In Ruby 2.7, arguments forwarding has been added. + +This cop identifies places where `do_something(*args, &block)` +can be replaced by `do_something(...)`. + +### Example: + # bad + def foo(*args, &block) + bar(*args, &block) + end + + # bad + def foo(*args, **kwargs, &block) + bar(*args, **kwargs, &block) + end + + # good + def foo(...) + bar(...) + end + +### Example: AllowOnlyRestArgument: true (default) + # good + def foo(*args) + bar(*args) + end + +### Example: AllowOnlyRestArgument: false + # 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 diff --git a/config/contents/style/class_equality_comparison.md b/config/contents/style/class_equality_comparison.md new file mode 100644 index 00000000..0b236722 --- /dev/null +++ b/config/contents/style/class_equality_comparison.md @@ -0,0 +1,12 @@ +This cop enforces the use of `Object#instance_of?` instead of class comparison +for equality. + +### Example: + # bad + var.class == Date + var.class.equal?(Date) + var.class.eql?(Date) + var.class.name == 'Date' + + # good + var.instance_of?(Date) diff --git a/config/contents/style/collection_compact.md b/config/contents/style/collection_compact.md new file mode 100644 index 00000000..72b33d74 --- /dev/null +++ b/config/contents/style/collection_compact.md @@ -0,0 +1,23 @@ +This cop checks for places where custom logic on rejection nils from arrays +and hashes can be replaced with `{Array,Hash}#{compact,compact!}`. + +It is marked as unsafe by default because false positives may occur in the +nil check of block arguments to the receiver object. +For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }` +and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine +when the receiver is a hash object. + +### Example: + # bad + array.reject { |e| e.nil? } + array.select { |e| !e.nil? } + + # good + array.compact + + # bad + hash.reject! { |k, v| v.nil? } + hash.select! { |k, v| !v.nil? } + + # good + hash.compact! diff --git a/config/contents/style/combinable_loops.md b/config/contents/style/combinable_loops.md index 22cded63..2b326b8b 100644 --- a/config/contents/style/combinable_loops.md +++ b/config/contents/style/combinable_loops.md @@ -43,3 +43,9 @@ a state that the second loop depends on; these two aren't combinable. do_something_else(item) end end + + # good + def method + each_slice(2) { |slice| do_something(slice) } + each_slice(3) { |slice| do_something(slice) } + end diff --git a/config/contents/style/comment_annotation.md b/config/contents/style/comment_annotation.md index aa8ee0c0..44ff57bb 100644 --- a/config/contents/style/comment_annotation.md +++ b/config/contents/style/comment_annotation.md @@ -1,6 +1,12 @@ This cop checks that comment annotation keywords are written according to guidelines. +NOTE: With a multiline comment block (where each line is only a +comment), only the first line will be able to register an offense, even +if an annotation keyword starts another line. This is done to prevent +incorrect registering of keywords (eg. `review`) inside a paragraph as an +annotation. + ### Example: # bad # TODO make better diff --git a/config/contents/style/commented_keyword.md b/config/contents/style/commented_keyword.md index 405dec08..e98f96b6 100644 --- a/config/contents/style/commented_keyword.md +++ b/config/contents/style/commented_keyword.md @@ -1,10 +1,13 @@ This cop checks for comments put on the same line as some keywords. -These keywords are: `begin`, `class`, `def`, `end`, `module`. +These keywords are: `class`, `module`, `def`, `begin`, `end`. Note that some comments (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`) are allowed. +Auto-correction removes comments from `end` keyword and keeps comments +for `class`, `module`, `def` and `begin` above the keyword. + ### Example: # bad if condition diff --git a/config/contents/style/document_dynamic_eval_definition.md b/config/contents/style/document_dynamic_eval_definition.md new file mode 100644 index 00000000..90e8ec2d --- /dev/null +++ b/config/contents/style/document_dynamic_eval_definition.md @@ -0,0 +1,71 @@ +When using `class_eval` (or other `eval`) with string interpolation, +add a comment block showing its appearance if interpolated (a practice used in Rails code). + +### Example: + # from activesupport/lib/active_support/core_ext/string/output_safety.rb + + # bad + UNSAFE_STRING_METHODS.each do |unsafe_method| + if 'String'.respond_to?(unsafe_method) + class_eval <<-EOT, __FILE__, __LINE__ + 1 + def #{unsafe_method}(*params, &block) + to_str.#{unsafe_method}(*params, &block) + end + + def #{unsafe_method}!(*params) + @dirty = true + super + end + EOT + end + end + + # good, inline comments in heredoc + UNSAFE_STRING_METHODS.each do |unsafe_method| + if 'String'.respond_to?(unsafe_method) + class_eval <<-EOT, __FILE__, __LINE__ + 1 + def #{unsafe_method}(*params, &block) # def capitalize(*params, &block) + to_str.#{unsafe_method}(*params, &block) # to_str.capitalize(*params, &block) + end # end + + def #{unsafe_method}!(*params) # def capitalize!(*params) + @dirty = true # @dirty = true + super # super + end # end + EOT + end + end + + # good, block comments in heredoc + class_eval <<-EOT, __FILE__, __LINE__ + 1 + # def capitalize!(*params) + # @dirty = true + # super + # end + + def #{unsafe_method}!(*params) + @dirty = true + super + end + EOT + + # good, block comments before heredoc + class_eval( + # def capitalize!(*params) + # @dirty = true + # super + # end + + <<-EOT, __FILE__, __LINE__ + 1 + def #{unsafe_method}!(*params) + @dirty = true + super + end + EOT + ) + + # bad - interpolated string without comment + class_eval("def #{unsafe_method}!(*params); end") + + # good - with inline comment or replace it with block comment using heredoc + class_eval("def #{unsafe_method}!(*params); end # def capitalize!(*params); end") \ No newline at end of file diff --git a/config/contents/style/documentation.md b/config/contents/style/documentation.md index 0f4f5829..11945c25 100644 --- a/config/contents/style/documentation.md +++ b/config/contents/style/documentation.md @@ -49,3 +49,8 @@ same for all its children. module Namespace Public = Class.new end + + # Macro calls + module Namespace + extend Foo + end diff --git a/config/contents/style/format_string_token.md b/config/contents/style/format_string_token.md index 5fd94668..f325b942 100644 --- a/config/contents/style/format_string_token.md +++ b/config/contents/style/format_string_token.md @@ -28,7 +28,28 @@ to encoded URLs or Date/Time formatting strings. # bad format('%s', greeting: 'Hello') - format('%{greeting}', 'Hello') + format('%{greeting}', greeting: 'Hello') + + # good + format('%s', 'Hello') + +It is allowed to contain unannotated token +if the number of them is less than or equals to +`MaxUnannotatedPlaceholdersAllowed`. + +### Example: MaxUnannotatedPlaceholdersAllowed: 0 + + # bad + format('%06d', 10) + format('%s %s.', 'Hello', 'world') + + # good + format('%06d', number: 10) + +### Example: MaxUnannotatedPlaceholdersAllowed: 1 (default) + + # bad + format('%s %s.', 'Hello', 'world') # good - format('%s', 'Hello') \ No newline at end of file + format('%06d', 10) \ No newline at end of file diff --git a/config/contents/style/hash_except.md b/config/contents/style/hash_except.md new file mode 100644 index 00000000..b8300c13 --- /dev/null +++ b/config/contents/style/hash_except.md @@ -0,0 +1,19 @@ +This cop checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods +that can be replaced with `Hash#except` method. + +This cop should only be enabled on Ruby version 3.0 or higher. +(`Hash#except` was added in Ruby 3.0.) + +For safe detection, it is limited to commonly used string and symbol comparisons +when used `==`. +And do not check `Hash#delete_if` and `Hash#keep_if` to change receiver object. + +### Example: + + # bad + {foo: 1, bar: 2, baz: 3}.reject {|k, v| k == :bar } + {foo: 1, bar: 2, baz: 3}.select {|k, v| k != :bar } + {foo: 1, bar: 2, baz: 3}.filter {|k, v| k != :bar } + + # good + {foo: 1, bar: 2, baz: 3}.except(:bar) diff --git a/config/contents/style/identical_conditional_branches.md b/config/contents/style/identical_conditional_branches.md index fd9e7907..f8b53abe 100644 --- a/config/contents/style/identical_conditional_branches.md +++ b/config/contents/style/identical_conditional_branches.md @@ -1,5 +1,10 @@ -This cop checks for identical lines at the beginning or end of -each branch of a conditional statement. +This cop checks for identical expressions at the beginning or end of +each branch of a conditional expression. Such expressions should normally +be placed outside the conditional expression - before or after it. + +NOTE: The cop is poorly named and some people might think that it actually +checks for duplicated conditional branches. The name will probably be changed +in a future major RuboCop release. ### Example: # bad diff --git a/config/contents/style/if_unless_modifier.md b/config/contents/style/if_unless_modifier.md index 70d240a9..cfb720ac 100644 --- a/config/contents/style/if_unless_modifier.md +++ b/config/contents/style/if_unless_modifier.md @@ -16,12 +16,16 @@ cop. The tab size is configured in the `IndentationWidth` of the Foo.do_something end - do_something_in_a_method_with_a_long_name(arg) if long_condition + do_something_with_a_long_name(arg) if long_condition_that_prevents_code_fit_on_single_line # good do_stuff(bar) if condition Foo.do_something unless qux.empty? - if long_condition - do_something_in_a_method_with_a_long_name(arg) + if long_condition_that_prevents_code_fit_on_single_line + do_something_with_a_long_name(arg) + end + + if short_condition # a long comment that makes it too long if it were just a single line + do_something end \ No newline at end of file diff --git a/config/contents/style/infinite_loop.md b/config/contents/style/infinite_loop.md index 22357ac2..94e870c4 100644 --- a/config/contents/style/infinite_loop.md +++ b/config/contents/style/infinite_loop.md @@ -1,5 +1,9 @@ Use `Kernel#loop` for infinite loops. +This cop is marked as unsafe as the rule does not necessarily +apply if the body might raise a `StopIteration` exception; contrary to +other infinite loops, `Kernel#loop` silently rescues that and returns `nil`. + ### Example: # bad while true diff --git a/config/contents/style/keyword_parameters_order.md b/config/contents/style/keyword_parameters_order.md index b26ab4cf..c3bf6524 100644 --- a/config/contents/style/keyword_parameters_order.md +++ b/config/contents/style/keyword_parameters_order.md @@ -15,3 +15,13 @@ and optional parameters at the end. def some_method(second:, first: false, third: 10) # body omitted end + + # bad + do_something do |first: false, second:, third: 10| + # body omitted + end + + # good + do_something do |second:, first: false, third: 10| + # body omitted + end diff --git a/config/contents/style/method_call_with_args_parentheses.md b/config/contents/style/method_call_with_args_parentheses.md index d2e63038..2538f55f 100644 --- a/config/contents/style/method_call_with_args_parentheses.md +++ b/config/contents/style/method_call_with_args_parentheses.md @@ -35,6 +35,9 @@ options. to `true` allows the presence of parentheses in such a method call even with arguments. +NOTE: Parens are required around a method with arguments when inside an +endless method definition (>= Ruby 3.0). + ### Example: EnforcedStyle: require_parentheses (default) # bad diff --git a/config/contents/style/method_def_parentheses.md b/config/contents/style/method_def_parentheses.md index b09b7c8a..3e6b99ad 100644 --- a/config/contents/style/method_def_parentheses.md +++ b/config/contents/style/method_def_parentheses.md @@ -1,6 +1,9 @@ This cop checks for parentheses around the arguments in method definitions. Both instance and class/singleton methods are checked. +This cop does not consider endless methods, since parentheses are +always required for them. + ### Example: EnforcedStyle: require_parentheses (default) # The `require_parentheses` style requires method definitions # to always use parentheses diff --git a/config/contents/style/multiple_comparison.md b/config/contents/style/multiple_comparison.md index d8ee73d5..09617c2c 100644 --- a/config/contents/style/multiple_comparison.md +++ b/config/contents/style/multiple_comparison.md @@ -1,5 +1,8 @@ This cop checks against comparing a variable with multiple items, where -`Array#include?` could be used instead to avoid code repetition. +`Array#include?`, `Set#include?` or a `case` could be used instead +to avoid code repetition. +It accepts comparisons of multiple method calls to avoid unnecessary method calls +by default. It can be configured by `AllowMethodComparison` option. ### Example: # bad @@ -8,4 +11,27 @@ This cop checks against comparing a variable with multiple items, where # good a = 'a' - foo if ['a', 'b', 'c'].include?(a) \ No newline at end of file + foo if ['a', 'b', 'c'].include?(a) + + VALUES = Set['a', 'b', 'c'].freeze + # elsewhere... + foo if VALUES.include?(a) + + case foo + when 'a', 'b', 'c' then foo + # ... + end + + # accepted (but consider `case` as above) + foo if a == b.lightweight || a == b.heavyweight + +### Example: AllowMethodComparison: true (default) + # good + foo if a == b.lightweight || a == b.heavyweight + +### Example: AllowMethodComparison: false + # bad + foo if a == b.lightweight || a == b.heavyweight + + # good + foo if [b.lightweight, b.heavyweight].include?(a) \ No newline at end of file diff --git a/config/contents/style/mutable_constant.md b/config/contents/style/mutable_constant.md index 4a8e7411..bb4e0b88 100644 --- a/config/contents/style/mutable_constant.md +++ b/config/contents/style/mutable_constant.md @@ -9,6 +9,8 @@ frozen objects so there is a decent chance of getting some false positives. Luckily, there is no harm in freezing an already frozen object. +NOTE: Regexp and Range literals are frozen objects since Ruby 3.0. + ### Example: EnforcedStyle: literals (default) # bad CONST = [1, 2, 3] diff --git a/config/contents/style/negated_if_else_condition.md b/config/contents/style/negated_if_else_condition.md new file mode 100644 index 00000000..0a9acbf9 --- /dev/null +++ b/config/contents/style/negated_if_else_condition.md @@ -0,0 +1,23 @@ +This cop checks for uses of `if-else` and ternary operators with a negated condition +which can be simplified by inverting condition and swapping branches. + +### Example: + # bad + if !x + do_something + else + do_something_else + end + + # good + if x + do_something_else + else + do_something + end + + # bad + !x ? do_something : do_something_else + + # good + x ? do_something_else : do_something diff --git a/config/contents/style/nil_lambda.md b/config/contents/style/nil_lambda.md new file mode 100644 index 00000000..1545a19b --- /dev/null +++ b/config/contents/style/nil_lambda.md @@ -0,0 +1,18 @@ +This cop checks for lambdas that always return nil, which can be replaced +with an empty lambda instead. + +### Example: + # bad + -> { nil } + + lambda do + next nil + end + + # good + -> {} + + lambda do + end + + -> (x) { nil if x } diff --git a/config/contents/style/perl_backrefs.md b/config/contents/style/perl_backrefs.md index df7da493..3bde9bd6 100644 --- a/config/contents/style/perl_backrefs.md +++ b/config/contents/style/perl_backrefs.md @@ -1,5 +1,6 @@ This cop looks for uses of Perl-style regexp match -backreferences like $1, $2, etc. +backreferences and their English versions like +$1, $2, $&, &+, $MATCH, $PREMATCH, etc. ### Example: # bad diff --git a/config/contents/style/raise_args.md b/config/contents/style/raise_args.md index ba5e95dc..dc5701ff 100644 --- a/config/contents/style/raise_args.md +++ b/config/contents/style/raise_args.md @@ -8,22 +8,29 @@ The exploded style works identically, but with the addition that it will also suggest constructing error objects when the exception is passed multiple arguments. +The exploded style has an `AllowedCompactTypes` configuration +option that takes an Array of exception name Strings. + ### Example: EnforcedStyle: exploded (default) # bad - raise StandardError.new("message") + raise StandardError.new('message') # good - raise StandardError, "message" - fail "message" + raise StandardError, 'message' + fail 'message' raise MyCustomError.new(arg1, arg2, arg3) raise MyKwArgError.new(key1: val1, key2: val2) + # With `AllowedCompactTypes` set to ['MyWrappedError'] + raise MyWrappedError.new(obj) + raise MyWrappedError.new(obj), 'message' + ### Example: EnforcedStyle: compact # bad - raise StandardError, "message" + raise StandardError, 'message' raise RuntimeError, arg1, arg2, arg3 # good - raise StandardError.new("message") + raise StandardError.new('message') raise MyCustomError.new(arg1, arg2, arg3) - fail "message" \ No newline at end of file + fail 'message' \ No newline at end of file diff --git a/config/contents/style/redundant_argument.md b/config/contents/style/redundant_argument.md new file mode 100644 index 00000000..2b6ea011 --- /dev/null +++ b/config/contents/style/redundant_argument.md @@ -0,0 +1,37 @@ +This cop checks for a redundant argument passed to certain methods. + +Limitations: + +1. This cop matches for method names only and hence cannot tell apart + methods with same name in different classes. +2. This cop is limited to methods with single parameter. +3. This cop is unsafe if certain special global variables (e.g. `$;`, `$/`) are set. + That depends on the nature of the target methods, of course. + +Method names and their redundant arguments can be configured like this: + +Methods: + join: '' + split: ' ' + chomp: "\n" + chomp!: "\n" + foo: 2 + +### Example: + # bad + array.join('') + [1, 2, 3].join("") + string.split(" ") + "first\nsecond".split(" ") + string.chomp("\n") + string.chomp!("\n") + A.foo(2) + + # good + array.join + [1, 2, 3].join + string.split + "first second".split + string.chomp + string.chomp! + A.foo \ No newline at end of file diff --git a/config/contents/style/redundant_begin.md b/config/contents/style/redundant_begin.md index 97a0abec..bcd06526 100644 --- a/config/contents/style/redundant_begin.md +++ b/config/contents/style/redundant_begin.md @@ -22,6 +22,14 @@ Currently it checks for code like this: something end + # bad + begin + do_something + end + + # good + do_something + # bad # When using Ruby 2.5 or later. do_something do diff --git a/config/contents/style/redundant_freeze.md b/config/contents/style/redundant_freeze.md index e9b446c0..88425518 100644 --- a/config/contents/style/redundant_freeze.md +++ b/config/contents/style/redundant_freeze.md @@ -1,4 +1,6 @@ -This cop check for uses of Object#freeze on immutable objects. +This cop check for uses of `Object#freeze` on immutable objects. + +NOTE: Regexp and Range literals are frozen objects since Ruby 3.0. ### Example: # bad diff --git a/config/contents/style/redundant_regexp_character_class.md b/config/contents/style/redundant_regexp_character_class.md index 10e666f6..c29395f4 100644 --- a/config/contents/style/redundant_regexp_character_class.md +++ b/config/contents/style/redundant_regexp_character_class.md @@ -14,5 +14,11 @@ This cop checks for unnecessary single-element Regexp character classes. # good r = /\s/ + # bad + r = %r{/[b]} + + # good + r = %r{/b} + # good r = /[ab]/ \ No newline at end of file diff --git a/config/contents/style/single_line_methods.md b/config/contents/style/single_line_methods.md index 180ec949..cd2758cb 100644 --- a/config/contents/style/single_line_methods.md +++ b/config/contents/style/single_line_methods.md @@ -1,6 +1,8 @@ This cop checks for single-line method definitions that contain a body. It will accept single-line methods with no body. +Endless methods added in Ruby 3.0 are also accepted by this cop. + ### Example: # bad def some_method; body end @@ -10,6 +12,7 @@ It will accept single-line methods with no body. # good def self.resource_class=(klass); end def @table.columns; end + def some_method() = body ### Example: AllowIfMethodIsEmpty: true (default) # good diff --git a/config/contents/style/special_global_vars.md b/config/contents/style/special_global_vars.md index c4679afa..a75cbdbb 100644 --- a/config/contents/style/special_global_vars.md +++ b/config/contents/style/special_global_vars.md @@ -21,10 +21,6 @@ This cop looks for uses of Perl-style global variables. puts $LAST_MATCH_INFO puts $IGNORECASE puts $ARGV # or ARGV - puts $MATCH - puts $PREMATCH - puts $POSTMATCH - puts $LAST_PAREN_MATCH ### Example: EnforcedStyle: use_perl_names # good @@ -46,7 +42,3 @@ This cop looks for uses of Perl-style global variables. puts $~ puts $= puts $* - puts $& - puts $` - puts $' - puts $+ diff --git a/config/contents/style/static_class.md b/config/contents/style/static_class.md new file mode 100644 index 00000000..eae4d0af --- /dev/null +++ b/config/contents/style/static_class.md @@ -0,0 +1,38 @@ +This cop checks for places where classes with only class methods can be +replaced with a module. Classes should be used only when it makes sense to create +instances out of them. + +This cop is marked as unsafe, because it is possible that this class is a parent +for some other subclass, monkey-patched with instance methods or +a dummy instance is instantiated from it somewhere. + +### Example: + # bad + class SomeClass + def self.some_method + # body omitted + end + + def self.some_other_method + # body omitted + end + end + + # good + module SomeModule + module_function + + def some_method + # body omitted + end + + def some_other_method + # body omitted + end + end + + # good - has instance method + class SomeClass + def instance_method; end + def self.class_method; end + end diff --git a/config/contents/style/string_concatenation.md b/config/contents/style/string_concatenation.md index 3948ce45..38fed9cf 100644 --- a/config/contents/style/string_concatenation.md +++ b/config/contents/style/string_concatenation.md @@ -6,6 +6,10 @@ more complex cases where the resulting code would be harder to read. In those cases, it might be useful to extract statements to local variables or methods which you can then interpolate in a string. +NOTE: When concatenation between two strings is broken over multiple +lines, this cop does not register an offense; instead, +`Style/LineEndConcatenation` will pick up the offense if enabled. + ### Example: # bad email_with_name = user.name + ' <' + user.email + '>' @@ -13,3 +17,7 @@ variables or methods which you can then interpolate in a string. # good email_with_name = "#{user.name} <#{user.email}>" email_with_name = format('%s <%s>', user.name, user.email) + + # accepted, line-end concatenation + name = 'First' + + 'Last' diff --git a/config/contents/style/swap_values.md b/config/contents/style/swap_values.md new file mode 100644 index 00000000..47941a6b --- /dev/null +++ b/config/contents/style/swap_values.md @@ -0,0 +1,12 @@ +This cop enforces the use of shorthand-style swapping of 2 variables. +Its autocorrection is marked as unsafe, because it can erroneously remove +the temporary variable which is used later. + +### Example: + # bad + tmp = x + x = y + y = tmp + + # good + x, y = y, x diff --git a/config/contents/style/symbol_proc.md b/config/contents/style/symbol_proc.md index 6bafa728..c4361ba4 100644 --- a/config/contents/style/symbol_proc.md +++ b/config/contents/style/symbol_proc.md @@ -3,6 +3,7 @@ Use symbols as procs when possible. ### Example: # bad something.map { |s| s.upcase } + something.map { _1.upcase } # good something.map(&:upcase) \ No newline at end of file diff --git a/config/contents/style/while_until_modifier.md b/config/contents/style/while_until_modifier.md index ec02a8a2..bc2f6524 100644 --- a/config/contents/style/while_until_modifier.md +++ b/config/contents/style/while_until_modifier.md @@ -18,4 +18,13 @@ configured in the `Layout/LineLength` cop. end # good - x += 1 until x > 10 \ No newline at end of file + x += 1 until x > 10 + +### Example: + # bad + x += 100 while x < 500 # a long comment that makes code too long if it were a single line + + # good + while x < 500 # a long comment that makes code too long if it were a single line + x += 100 + end \ No newline at end of file From dba6724ee695a19ead3c9c8448a447864c7cd087 Mon Sep 17 00:00:00 2001 From: Daniel Wright Date: Tue, 24 Nov 2020 11:33:09 -0800 Subject: [PATCH 3/5] Fixes Broken ConfigUpgrader Spec --- spec/support/config_upgrader_rubocop.yml | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/spec/support/config_upgrader_rubocop.yml b/spec/support/config_upgrader_rubocop.yml index ddf7a4cc..712e2533 100644 --- a/spec/support/config_upgrader_rubocop.yml +++ b/spec/support/config_upgrader_rubocop.yml @@ -3,6 +3,46 @@ Style/AccessorMethodName: Style/FrozenStringLiteralComment: Enabled: false +# 1.5 through 1.7 +Layout/SpaceBeforeBrackets: # (new in 1.7) + Enabled: true +Lint/AmbiguousAssignment: # (new in 1.7) + Enabled: true +Lint/UnexpectedBlockArity: # (new in 1.5) + Enabled: true +Style/HashExcept: # (new in 1.7) + Enabled: true + + # 1.1 through 1.4 +Lint/DuplicateBranch: # (new in 1.3) + Enabled: true +Lint/DuplicateRegexpCharacterClassElement: # (new in 1.1) + Enabled: true +Lint/EmptyBlock: # (new in 1.1) + Enabled: true +Lint/EmptyClass: # (new in 1.3) + Enabled: true +Lint/NoReturnInBeginEndBlocks: # (new in 1.2) + Enabled: true +Lint/ToEnumArguments: # (new in 1.1) + Enabled: true +Lint/UnmodifiedReduceAccumulator: # (new in 1.1) + Enabled: true +Style/ArgumentsForwarding: # (new in 1.1) + Enabled: true +Style/CollectionCompact: # (new in 1.2) + Enabled: true +Style/DocumentDynamicEvalDefinition: # (new in 1.1) + Enabled: true +Style/NegatedIfElseCondition: # (new in 1.2) + Enabled: true +Style/NilLambda: # (new in 1.3) + Enabled: true +Style/RedundantArgument: # (new in 1.4) + Enabled: true +Style/SwapValues: # (new in 1.1) + Enabled: true + # 0.91 Layout/BeginEndAlignment: # (new in 0.91) Enabled: true From 3558b88c06838bbb7446e16464877612271ec5a2 Mon Sep 17 00:00:00 2001 From: Daniel Wright Date: Mon, 4 Jan 2021 12:12:57 -0800 Subject: [PATCH 4/5] Fixes Broken Rubocop Configuration Patch The API was changed in v1.6.0 (see rubocop-hq/rubocop#9143). This does the minimum necessary to fix the broken spec, but there is probably a more appropriate solution using the new API. --- lib/rubocop/config_patch.rb | 2 +- spec/rubocop/config_patch_spec.rb | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/rubocop/config_patch.rb b/lib/rubocop/config_patch.rb index 45046ea3..2a25c9cc 100644 --- a/lib/rubocop/config_patch.rb +++ b/lib/rubocop/config_patch.rb @@ -3,7 +3,7 @@ require "rubocop/config" module RuboCopConfigRescue - def reject_obsolete_cops_and_parameters + def reject_obsolete! super rescue RuboCop::ValidationError => e warn e.message diff --git a/spec/rubocop/config_patch_spec.rb b/spec/rubocop/config_patch_spec.rb index 4c80d4fe..1e01cab5 100644 --- a/spec/rubocop/config_patch_spec.rb +++ b/spec/rubocop/config_patch_spec.rb @@ -33,6 +33,7 @@ module CC::Engine The `Layout/AlignArguments` cop has been renamed to `Layout/ArgumentAlignment`. (obsolete configuration found in .rubocop.yml, please update it) unrecognized cop Layout/AlignArguments found in .rubocop.yml + Did you mean `Layout/HashAlignment`? EOM expect { config.validate }.to output(expected).to_stderr @@ -50,9 +51,10 @@ module CC::Engine expected = <<~EOM - The `Style/TrailingComma` cop has been removed. Please use `Style/TrailingCommaInArguments`, `Style/TrailingCommaInArrayLiteral`, and/or `Style/TrailingCommaInHashLiteral` instead. + 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 + Did you mean `Style/TrailingCommaInArguments`? EOM expect { config.validate }.to output(expected).to_stderr From f4cc5d2713d9afa2eb1ed220e267ec35a66b36bc Mon Sep 17 00:00:00 2001 From: Daniel Wright Date: Mon, 4 Jan 2021 12:26:18 -0800 Subject: [PATCH 5/5] Delinting the Gemfile --- Gemfile | 4 ++-- Gemfile.lock | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 9f322af2..ab3fb466 100644 --- a/Gemfile +++ b/Gemfile @@ -13,8 +13,8 @@ gem "rubocop-performance", require: false gem "rubocop-rails", require: false gem "rubocop-rake", require: false gem "rubocop-rspec", require: false -gem "rubocop-sequel", "0.1.0", require: false -gem 'rubocop-sorbet', require: false +gem "rubocop-sequel", require: false +gem "rubocop-sorbet", require: false gem "rubocop-thread_safety", require: false gem "safe_yaml" gem "test-prof", require: false diff --git a/Gemfile.lock b/Gemfile.lock index 2ca8383d..7f5dc283 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -98,7 +98,7 @@ DEPENDENCIES rubocop-rails rubocop-rake rubocop-rspec - rubocop-sequel (= 0.1.0) + rubocop-sequel rubocop-sorbet rubocop-thread_safety safe_yaml