From 1971dfaae435b7941cbb42b16154838da518bf4c Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Mon, 8 Aug 2022 13:46:19 +0300 Subject: [PATCH 01/47] Depend on rubocop-ast 1.20.1 for numblocks support in #macro? --- changelog/change_rubocop_ast_version.md | 1 + rubocop.gemspec | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog/change_rubocop_ast_version.md diff --git a/changelog/change_rubocop_ast_version.md b/changelog/change_rubocop_ast_version.md new file mode 100644 index 00000000000..ec7b770b054 --- /dev/null +++ b/changelog/change_rubocop_ast_version.md @@ -0,0 +1 @@ +* [#10915](https://github.com/rubocop/rubocop/pull/10915): Depend on rubocop-ast 1.20.1 for numblocks support in #macro?. ([@gsamokovarov][]) diff --git a/rubocop.gemspec b/rubocop.gemspec index d0977aa4ff9..dda7f76decf 100644 --- a/rubocop.gemspec +++ b/rubocop.gemspec @@ -37,7 +37,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency('rainbow', '>= 2.2.2', '< 4.0') s.add_runtime_dependency('regexp_parser', '>= 1.8', '< 3.0') s.add_runtime_dependency('rexml', '>= 3.2.5', '< 4.0') - s.add_runtime_dependency('rubocop-ast', '>= 1.20.0', '< 2.0') + s.add_runtime_dependency('rubocop-ast', '>= 1.20.1', '< 2.0') s.add_runtime_dependency('ruby-progressbar', '~> 1.7') s.add_runtime_dependency('unicode-display_width', '>= 1.4.0', '< 3.0') From b214a068c60cf5aba431cbe675d2279c2851e9eb Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 13:56:14 +0300 Subject: [PATCH 02/47] Introduce InternalAffairs/NumblockHandler The `InternalAffairs/NumblockHandler` ensures cops that handle `block` nodes will also handle `numblock` nodes or disable it explicitly. We have exceptions for this check like cops that check block parameters but for the majority of the cases we want `numblock` nodes to handled. --- .rubocop.yml | 4 ++ lib/rubocop/cop/internal_affairs.rb | 1 + .../cop/internal_affairs/numblock_handler.rb | 69 +++++++++++++++++++ .../internal_affairs/numblock_handler_spec.rb | 47 +++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 lib/rubocop/cop/internal_affairs/numblock_handler.rb create mode 100644 spec/rubocop/cop/internal_affairs/numblock_handler_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index 4fcabe3d29a..de805221ffc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -163,5 +163,9 @@ InternalAffairs/StyleDetectedApiUse: Exclude: - 'lib/rubocop/cop/mixin/percent_array.rb' +InternalAffairs/NumblockHandler: + Exclude: + - 'lib/rubocop/cop/internal_affairs/*.rb' + Gemspec/DependencyVersion: Enabled: true diff --git a/lib/rubocop/cop/internal_affairs.rb b/lib/rubocop/cop/internal_affairs.rb index eb006c6aa48..9a9831e87c4 100644 --- a/lib/rubocop/cop/internal_affairs.rb +++ b/lib/rubocop/cop/internal_affairs.rb @@ -10,6 +10,7 @@ require_relative 'internal_affairs/node_destructuring' require_relative 'internal_affairs/node_matcher_directive' require_relative 'internal_affairs/node_type_predicate' +require_relative 'internal_affairs/numblock_handler' require_relative 'internal_affairs/offense_location_keyword' require_relative 'internal_affairs/redundant_context_config_parameter' require_relative 'internal_affairs/redundant_described_class_as_subject' diff --git a/lib/rubocop/cop/internal_affairs/numblock_handler.rb b/lib/rubocop/cop/internal_affairs/numblock_handler.rb new file mode 100644 index 00000000000..4b884c81344 --- /dev/null +++ b/lib/rubocop/cop/internal_affairs/numblock_handler.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module InternalAffairs + # Checks for missing `numblock handlers. The blocks with numbered + # arguments introduced in Ruby 2.7 are parsed with a node type of + # `numblock` instead of block. Cops that define `block` handlers + # need to define `numblock` handlers or disable this cope for them. + # + # @example + # + # # bad + # class BlockRelatedCop < Base + # def on_block(node) + # end + # end + # + # # good + # class BlockRelatedCop < Base + # def on_block(node) + # end + # + # alias on_numblock on_block + # end + # + # class BlockRelatedCop < Base + # def on_block(node) + # end + # + # alias_method :on_numblock, :on_block + # end + # + # class BlockRelatedCop < Base + # def on_block(node) + # end + # + # def on_numblock(node) + # end + # end + class NumblockHandler < Base + MSG = 'Define on_numblock to handle blocks with numbered arguments.' + + def on_def(node) + return unless block_handler?(node) + return unless node.parent + + add_offense(node) unless numblock_handler?(node.parent) + end + + private + + # @!method block_handler?(node) + def_node_matcher :block_handler?, <<~PATTERN + (def :on_block (args (arg :node)) ...) + PATTERN + + # @!method numblock_handler?(node) + def_node_matcher :numblock_handler?, <<~PATTERN + { + `(def :on_numblock (args (arg :node)) ...) + `(alias (sym :on_numblock) (sym :on_block)) + `(send nil? :alias_method (sym :on_numblock) (sym :on_block)) + } + PATTERN + end + end + end +end diff --git a/spec/rubocop/cop/internal_affairs/numblock_handler_spec.rb b/spec/rubocop/cop/internal_affairs/numblock_handler_spec.rb new file mode 100644 index 00000000000..7bdd71690e4 --- /dev/null +++ b/spec/rubocop/cop/internal_affairs/numblock_handler_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::InternalAffairs::NumblockHandler, :config do + it 'registers an offense for cops with forgotten numblock handlers' do + expect_offense <<~RUBY + class Cop < Base + def on_block(node) + ^^^^^^^^^^^^^^^^^^ Define on_numblock to handle blocks with numbered arguments. + end + end + RUBY + end + + it 'does not register an offense for cops with on_numblock alias' do + expect_no_offenses <<~RUBY + class Cop < Base + def on_block(node) + end + + alias on_numblock on_block + end + RUBY + end + + it 'does not register an offense for cops with on_numblock alias_method' do + expect_no_offenses <<~RUBY + class Cop < Base + def on_block(node) + end + + alias_method :on_numblock, :on_block + end + RUBY + end + + it 'does not register an offense for cops with on_numblock method' do + expect_no_offenses <<~RUBY + class Cop < Base + def on_block(node) + end + + def on_numblock(node) + end + end + RUBY + end +end From ec1739def584a7785ee2948319e17e68879dff11 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:02:00 +0300 Subject: [PATCH 03/47] Disable InternalAffairs/NumbockHandler for block cops While, technically, we can use gemspec definitions like: ``` Gem::Specification.new do _1.metadata['rubygems_mfa_required'] = 'true' end ``` --- lib/rubocop/cop/gemspec/require_mfa.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/gemspec/require_mfa.rb b/lib/rubocop/cop/gemspec/require_mfa.rb index 06db67a14ed..b07fe7d2487 100644 --- a/lib/rubocop/cop/gemspec/require_mfa.rb +++ b/lib/rubocop/cop/gemspec/require_mfa.rb @@ -84,7 +84,7 @@ class RequireMFA < Base (str "true") PATTERN - def on_block(node) # rubocop:disable Metrics/MethodLength + def on_block(node) # rubocop:disable Metrics/MethodLength, InternalAffairs/NumblockHandler gem_specification(node) do |block_var| metadata_value = metadata(node) mfa_value = mfa_value(metadata_value) From 1cf4f0825c57bda2ab607df11d75d50d924d6c80 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:03:10 +0300 Subject: [PATCH 04/47] Disable InternalAffairs/NumblockHandler for Layout/SpaceAroundBlockParameters --- lib/rubocop/cop/layout/space_around_block_parameters.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/layout/space_around_block_parameters.rb b/lib/rubocop/cop/layout/space_around_block_parameters.rb index 3202494bb01..a3de6c9e346 100644 --- a/lib/rubocop/cop/layout/space_around_block_parameters.rb +++ b/lib/rubocop/cop/layout/space_around_block_parameters.rb @@ -29,7 +29,7 @@ class SpaceAroundBlockParameters < Base include RangeHelp extend AutoCorrector - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler arguments = node.arguments return unless node.arguments? && pipes?(arguments) From 462955c027492e1b0f3587eec346f5a9bb9d4466 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:03:26 +0300 Subject: [PATCH 05/47] Disable InternalAffairs/NumblockHandler for Lint/EmptyBlock --- lib/rubocop/cop/lint/empty_block.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/lint/empty_block.rb b/lib/rubocop/cop/lint/empty_block.rb index a2ff31b6b32..286375b073b 100644 --- a/lib/rubocop/cop/lint/empty_block.rb +++ b/lib/rubocop/cop/lint/empty_block.rb @@ -63,7 +63,7 @@ module Lint class EmptyBlock < Base MSG = 'Empty block detected.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return if node.body return if allow_empty_lambdas? && lambda_or_proc?(node) return if cop_config['AllowComments'] && allow_comment?(node) From fef71ab133cce1db73de9f64edccaf8113b44e4c Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:04:18 +0300 Subject: [PATCH 06/47] Disable InternalAffairs/NumblockHandler for Naming/BlockParameterName --- lib/rubocop/cop/naming/block_parameter_name.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/naming/block_parameter_name.rb b/lib/rubocop/cop/naming/block_parameter_name.rb index b4f44902092..b9c43a1f4a0 100644 --- a/lib/rubocop/cop/naming/block_parameter_name.rb +++ b/lib/rubocop/cop/naming/block_parameter_name.rb @@ -38,7 +38,7 @@ module Naming class BlockParameterName < Base include UncommunicativeName - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless node.arguments? check(node, node.arguments) From 5425fd8cc0621a3578e1b9cebeadc96c1189308c Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:04:27 +0300 Subject: [PATCH 07/47] Disable InternalAffairs/NumblockHandler for Style/TrailingCommaInBlockArgs --- lib/rubocop/cop/style/trailing_comma_in_block_args.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/trailing_comma_in_block_args.rb b/lib/rubocop/cop/style/trailing_comma_in_block_args.rb index 1ed5e6edce3..9f4cf315d3b 100644 --- a/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +++ b/lib/rubocop/cop/style/trailing_comma_in_block_args.rb @@ -64,7 +64,7 @@ class TrailingCommaInBlockArgs < Base MSG = 'Useless trailing comma present in block arguments.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler # lambda literal (`->`) never has block arguments. return if node.send_node.lambda_literal? return unless useless_trailing_comma?(node) From e8afc00f7369e00d6f93b1e2f271b05a723ca8ae Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:04:46 +0300 Subject: [PATCH 08/47] Disable InternalAffairs/NumblockHandler for Style/SingleLineBlockParams --- lib/rubocop/cop/style/single_line_block_params.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/single_line_block_params.rb b/lib/rubocop/cop/style/single_line_block_params.rb index 6df4fd4ebe5..89e9b431df3 100644 --- a/lib/rubocop/cop/style/single_line_block_params.rb +++ b/lib/rubocop/cop/style/single_line_block_params.rb @@ -33,7 +33,7 @@ class SingleLineBlockParams < Base MSG = 'Name `%s` block params `|%s|`.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless node.single_line? return unless eligible_method?(node) From 37ef3deeefd92a12657cb491dd85ee3265c75ec0 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:05:21 +0300 Subject: [PATCH 09/47] Disable InternalAffairs/NumblockHandler for Style/EmptyBlockParameter --- lib/rubocop/cop/style/empty_block_parameter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/empty_block_parameter.rb b/lib/rubocop/cop/style/empty_block_parameter.rb index 2222cdd1393..02426fa8ae3 100644 --- a/lib/rubocop/cop/style/empty_block_parameter.rb +++ b/lib/rubocop/cop/style/empty_block_parameter.rb @@ -28,7 +28,7 @@ class EmptyBlockParameter < Base MSG = 'Omit pipes for the empty block parameters.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler send_node = node.send_node check(node) unless send_node.send_type? && send_node.lambda_literal? end From 71776fcf8dd1a0e6e86ecee081396e9ef9bf75ef Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:05:48 +0300 Subject: [PATCH 10/47] Disable InternalAffairs/NumblockHandler for Style/EmptyLambdaParameter --- lib/rubocop/cop/style/empty_lambda_parameter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/empty_lambda_parameter.rb b/lib/rubocop/cop/style/empty_lambda_parameter.rb index cb2bc219935..6832f455a9d 100644 --- a/lib/rubocop/cop/style/empty_lambda_parameter.rb +++ b/lib/rubocop/cop/style/empty_lambda_parameter.rb @@ -23,7 +23,7 @@ class EmptyLambdaParameter < Base MSG = 'Omit parentheses for the empty lambda parameters.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler send_node = node.send_node return unless send_node.send_type? From 45dc712ad301203a5f51ef147fadcc439a9e65a0 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:06:18 +0300 Subject: [PATCH 11/47] Disable InternalAffairs/NumblockHandler for Style/NilLambda --- lib/rubocop/cop/style/nil_lambda.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/nil_lambda.rb b/lib/rubocop/cop/style/nil_lambda.rb index b84972255e0..fdedf855103 100644 --- a/lib/rubocop/cop/style/nil_lambda.rb +++ b/lib/rubocop/cop/style/nil_lambda.rb @@ -43,7 +43,7 @@ class NilLambda < Base { ({return next break} nil) (nil) } PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless node.lambda? || node.proc? return unless nil_return?(node.body) From 9a3f41fcbe59aa86fa7bbe7505e6d823ffab8513 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:07:16 +0300 Subject: [PATCH 12/47] Disable InternalAffairs/NumblockHandler for Style/EachForSimpleLoop --- lib/rubocop/cop/style/each_for_simple_loop.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/each_for_simple_loop.rb b/lib/rubocop/cop/style/each_for_simple_loop.rb index 1d3e13d9647..0262d4f36b3 100644 --- a/lib/rubocop/cop/style/each_for_simple_loop.rb +++ b/lib/rubocop/cop/style/each_for_simple_loop.rb @@ -27,7 +27,7 @@ class EachForSimpleLoop < Base MSG = 'Use `Integer#times` for a simple loop which iterates a fixed number of times.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless offending_each_range(node) send_node = node.send_node From b5d452ce04aea584d678a76145899c03feefc92b Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:08:23 +0300 Subject: [PATCH 13/47] Disable InternalAffairs/NumblockHandler for Style/RedundantFetchBlock --- lib/rubocop/cop/style/redundant_fetch_block.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/redundant_fetch_block.rb b/lib/rubocop/cop/style/redundant_fetch_block.rb index 17503445188..26ac4b14835 100644 --- a/lib/rubocop/cop/style/redundant_fetch_block.rb +++ b/lib/rubocop/cop/style/redundant_fetch_block.rb @@ -50,7 +50,7 @@ class RedundantFetchBlock < Base ${nil? #basic_literal? #const_type?}) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler redundant_fetch_block_candidate?(node) do |send, body| return if should_not_check?(send, body) From 3b8b65de9dec08f95ea1253314a9422d32cf8fcc Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:09:06 +0300 Subject: [PATCH 14/47] Disable InternalAffairs/NumblockHandler for HashTransformMethod This mixin (`HashTransformMethod`) holds implementation details for the cops Style/HashTransformKeys and Style/HashTransformValues. Their usage is based on named block arguments and destructuring, which is not how one would use numbered arguments. I'll delay (avoid) this implementation. --- lib/rubocop/cop/mixin/hash_transform_method.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/mixin/hash_transform_method.rb b/lib/rubocop/cop/mixin/hash_transform_method.rb index c449ad2b07e..52e9fecf513 100644 --- a/lib/rubocop/cop/mixin/hash_transform_method.rb +++ b/lib/rubocop/cop/mixin/hash_transform_method.rb @@ -14,7 +14,7 @@ module HashTransformMethod {(array ...) (send _ :each_with_index) (send _ :with_index _ ?) (send _ :zip ...)} PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler on_bad_each_with_object(node) do |*match| handle_possible_offense(node, match, 'each_with_object') end From fff6f47a87aa5d3613c02a8c89aa5d7252e486f1 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:09:58 +0300 Subject: [PATCH 15/47] Disable InternalAffairs/NumblockHandler for Layout/SpaceAroundKeyword --- lib/rubocop/cop/layout/space_around_keyword.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/layout/space_around_keyword.rb b/lib/rubocop/cop/layout/space_around_keyword.rb index 0a7fe3bdfc1..d3725cd5d0e 100644 --- a/lib/rubocop/cop/layout/space_around_keyword.rb +++ b/lib/rubocop/cop/layout/space_around_keyword.rb @@ -41,7 +41,7 @@ def on_and(node) check(node, [:operator].freeze) if node.keyword? end - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler check(node, %i[begin end].freeze) end From 3fea15646400cd1f3eb473eefef30049fc3ce772 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:10:40 +0300 Subject: [PATCH 16/47] Fix Layout/BlockAlignment with numblocks --- lib/rubocop/cop/layout/block_alignment.rb | 2 ++ .../cop/layout/block_alignment_spec.rb | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/rubocop/cop/layout/block_alignment.rb b/lib/rubocop/cop/layout/block_alignment.rb index ebd13b39429..aef4e627fc5 100644 --- a/lib/rubocop/cop/layout/block_alignment.rb +++ b/lib/rubocop/cop/layout/block_alignment.rb @@ -82,6 +82,8 @@ def on_block(node) check_block_alignment(start_for_block_node(node), node) end + alias on_numblock on_block + def style_parameter_name 'EnforcedStyleAlignWith' end diff --git a/spec/rubocop/cop/layout/block_alignment_spec.rb b/spec/rubocop/cop/layout/block_alignment_spec.rb index 65e7471803d..30c2e1cf354 100644 --- a/spec/rubocop/cop/layout/block_alignment_spec.rb +++ b/spec/rubocop/cop/layout/block_alignment_spec.rb @@ -675,4 +675,23 @@ def abc RUBY end end + + context 'Ruby 2.7', :ruby27 do + it 'accepts end aligned with a call chain left hand side' do + expect_no_offenses(<<~RUBY) + parser.diagnostics.consumer = lambda do + _1 << diagnostic + end + RUBY + end + + it 'registers an offense for mismatched block end with a mass assignment' do + expect_offense(<<~RUBY) + var1, var2 = lambda do + [_1, _2] + end + ^^^ `end` at 3, 2 is not aligned with `var1, var2` at 1, 0. + RUBY + end + end end From 92970845cb5b26268c2958e96703d6ee69b94f9a Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:11:39 +0300 Subject: [PATCH 17/47] Fix Layout/BlockEndNewline with numblocks --- lib/rubocop/cop/layout/block_end_newline.rb | 2 ++ .../cop/layout/block_end_newline_spec.rb | 36 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/lib/rubocop/cop/layout/block_end_newline.rb b/lib/rubocop/cop/layout/block_end_newline.rb index 625ccfa4a2b..595eb684a7e 100644 --- a/lib/rubocop/cop/layout/block_end_newline.rb +++ b/lib/rubocop/cop/layout/block_end_newline.rb @@ -39,6 +39,8 @@ def on_block(node) register_offense(node) end + alias on_numblock on_block + private def register_offense(node) diff --git a/spec/rubocop/cop/layout/block_end_newline_spec.rb b/spec/rubocop/cop/layout/block_end_newline_spec.rb index 51bdd3784ac..f687d9fee2c 100644 --- a/spec/rubocop/cop/layout/block_end_newline_spec.rb +++ b/spec/rubocop/cop/layout/block_end_newline_spec.rb @@ -182,4 +182,40 @@ } RUBY end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense and corrects when multiline block `}` is not on its own line ' \ + 'and using method chain' do + expect_offense(<<~RUBY) + test { + _1 }.bar.baz + ^ Expression at 2, 6 should be on its own line. + RUBY + + expect_correction(<<~RUBY) + test { + _1 + }.bar.baz + RUBY + end + + it 'registers an offense and corrects when multiline block `}` is not on its own line ' \ + 'and using heredoc argument' do + expect_offense(<<~RUBY) + test { + _1.push(<<~EOS) } + ^ Expression at 2, 19 should be on its own line. + Heredoc text. + EOS + RUBY + + expect_correction(<<~RUBY) + test { + _1.push(<<~EOS) + Heredoc text. + EOS + } + RUBY + end + end end From 413cc86a334c202ead1d038cf8cce99f71936399 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:12:38 +0300 Subject: [PATCH 18/47] Fix Layout/EmptyLinesAroundAccessModifier with numblocks --- .../empty_lines_around_access_modifier.rb | 7 ++-- ...empty_lines_around_access_modifier_spec.rb | 33 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb b/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb index 3d3b814a3bf..ecb17609b4e 100644 --- a/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +++ b/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb @@ -80,8 +80,11 @@ def on_block(node) @block_line = node.source_range.first_line end - def on_send(node) - return unless node.bare_access_modifier? && !node.parent&.block_type? + alias on_numblock on_block + + def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity + return unless node.bare_access_modifier? && + !(node.parent&.block_type? || node.parent&.numblock_type?) return if expected_empty_lines?(node) message = message(node) diff --git a/spec/rubocop/cop/layout/empty_lines_around_access_modifier_spec.rb b/spec/rubocop/cop/layout/empty_lines_around_access_modifier_spec.rb index 51bf8b88fac..87baf160511 100644 --- a/spec/rubocop/cop/layout/empty_lines_around_access_modifier_spec.rb +++ b/spec/rubocop/cop/layout/empty_lines_around_access_modifier_spec.rb @@ -418,4 +418,37 @@ def test; end end end end + + context 'Ruby 2.7', :ruby27 do + %w[private protected public module_function].each do |access_modifier| + it "registers an offense for missing around line before #{access_modifier}" do + expect_offense(<<~RUBY) + included do + _1 + #{access_modifier} + #{'^' * access_modifier.size} Keep a blank line before and after `#{access_modifier}`. + def test; end + end + RUBY + + expect_correction(<<~RUBY) + included do + _1 + + #{access_modifier} + + def test; end + end + RUBY + end + + it "ignores #{access_modifier} with numblock argument" do + expect_no_offenses(<<~RUBY) + def foo + #{access_modifier} { _1 } + end + RUBY + end + end + end end From 8010fb455d0494be19596d246951125d245265e9 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:14:02 +0300 Subject: [PATCH 19/47] Fix Layout/EmptyLinesAroundBlockBody with numblocks --- .../layout/empty_lines_around_block_body.rb | 2 ++ .../empty_lines_around_block_body_spec.rb | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/rubocop/cop/layout/empty_lines_around_block_body.rb b/lib/rubocop/cop/layout/empty_lines_around_block_body.rb index 351f4cee4dc..f29901c1714 100644 --- a/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +++ b/lib/rubocop/cop/layout/empty_lines_around_block_body.rb @@ -32,6 +32,8 @@ def on_block(node) check(node, node.body, adjusted_first_line: first_line) end + + alias on_numblock on_block end end end diff --git a/spec/rubocop/cop/layout/empty_lines_around_block_body_spec.rb b/spec/rubocop/cop/layout/empty_lines_around_block_body_spec.rb index cb85fd7fd9f..2910b2f8350 100644 --- a/spec/rubocop/cop/layout/empty_lines_around_block_body_spec.rb +++ b/spec/rubocop/cop/layout/empty_lines_around_block_body_spec.rb @@ -40,6 +40,24 @@ RUBY end + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for block body ending with a blank' do + expect_offense(<<~RUBY) + some_method #{open} + _1 + + ^{} Extra empty line detected at block body end. + #{close} + RUBY + + expect_correction(<<~RUBY) + some_method #{open} + _1 + #{close} + RUBY + end + end + it 'accepts block body starting with a line with spaces' do expect_no_offenses(<<~RUBY) some_method #{open} From 69b6400e31f755212edd85cac5a0332515f79bb2 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:15:27 +0300 Subject: [PATCH 20/47] Fix Layout/IndentationWidth with numblocks --- lib/rubocop/cop/layout/indentation_width.rb | 2 ++ .../cop/layout/indentation_width_spec.rb | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/rubocop/cop/layout/indentation_width.rb b/lib/rubocop/cop/layout/indentation_width.rb index d5cfcb9844b..7cfb3a6a523 100644 --- a/lib/rubocop/cop/layout/indentation_width.rb +++ b/lib/rubocop/cop/layout/indentation_width.rb @@ -90,6 +90,8 @@ def on_block(node) check_members(end_loc, [node.body]) end + alias on_numblock on_block + def on_class(node) base = node.loc.keyword return if same_line?(base, node.body) diff --git a/spec/rubocop/cop/layout/indentation_width_spec.rb b/spec/rubocop/cop/layout/indentation_width_spec.rb index a65e2337f8e..993937e94a4 100644 --- a/spec/rubocop/cop/layout/indentation_width_spec.rb +++ b/spec/rubocop/cop/layout/indentation_width_spec.rb @@ -1599,6 +1599,26 @@ def bar end end + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for bad indentation of a {} body' do + expect_offense(<<~RUBY) + func { + _1&.foo + ^^^ Use 2 (not 3) spaces for indentation. + } + RUBY + end + + it 'registers an offense for bad indentation of a do-end body' do + expect_offense(<<~RUBY) + func do + _1&.foo + ^^^ Use 2 (not 3) spaces for indentation. + end + RUBY + end + end + # The cop uses the block end/} as the base for indentation, so if it's not # on its own line, all bets are off. it 'accepts badly indented code if block end is not on separate line' do From d4ad9bcf78672182b65f9775cbbbda4995d7eb3f Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:16:01 +0300 Subject: [PATCH 21/47] Fix Layout/LineLength with numblocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While applying the cop to `numbock`s, I have found a bug with regular `block` nodes and singe-line do-end blocks without arguments. This got autocorrected to... ```ruby foo.select do 4444000039123123129993912312312999199291203123 end ``` ... that 👇 ```ruby foo.select d o 4444000039123123129993912312312999199291203123 end ``` This is not valid Ruby code, so I fixed that while at it. --- lib/rubocop/cop/layout/line_length.rb | 4 ++- spec/rubocop/cop/layout/line_length_spec.rb | 40 ++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/rubocop/cop/layout/line_length.rb b/lib/rubocop/cop/layout/line_length.rb index 0b1d2866bb1..c9a146e4db9 100644 --- a/lib/rubocop/cop/layout/line_length.rb +++ b/lib/rubocop/cop/layout/line_length.rb @@ -74,6 +74,8 @@ def on_block(node) check_for_breakable_block(node) end + alias on_numblock on_block + def on_potential_breakable_node(node) check_for_breakable_node(node) end @@ -131,7 +133,7 @@ def breakable_block_range(block_node) if block_node.arguments? && !block_node.lambda? block_node.arguments.loc.end else - block_node.loc.begin + block_node.braces? ? block_node.loc.begin : block_node.loc.begin.adjust(begin_pos: 1) end end diff --git a/spec/rubocop/cop/layout/line_length_spec.rb b/spec/rubocop/cop/layout/line_length_spec.rb index ecf519c7345..fd6913556f2 100644 --- a/spec/rubocop/cop/layout/line_length_spec.rb +++ b/spec/rubocop/cop/layout/line_length_spec.rb @@ -966,7 +966,7 @@ def baz(bar) end context 'do/end' do - it 'adds an offense and does correct it' do + it 'adds an offense for block with arguments and does correct it' do expect_offense(<<~RUBY) foo.select do |bar| 4444000039123123129993912312312999199291203123 end ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Line is too long. [70/40] @@ -977,6 +977,18 @@ def baz(bar) 4444000039123123129993912312312999199291203123 end RUBY end + + it 'adds an offense for block without arguments and does correct it' do + expect_offense(<<~RUBY) + foo.select do 4444000039123123129993912312312999199291203123 end + ^^^^^^^^^^^^^^^^^^^^^^^^ Line is too long. [64/40] + RUBY + + expect_correction(<<~RUBY) + foo.select do + 4444000039123123129993912312312999199291203123 end + RUBY + end end context 'let block' do @@ -1036,6 +1048,32 @@ def baz(bar) end end end + + context 'Ruby 2.7', :ruby27 do + it 'adds an offense for {} block does correct it' do + expect_offense(<<~RUBY) + foo.select { _1 + 4444000039123123129993912312312999199291203123123 } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Line is too long. [69/40] + RUBY + + expect_correction(<<~RUBY) + foo.select { + _1 + 4444000039123123129993912312312999199291203123123 } + RUBY + end + + it 'adds an offense for do-end block and does correct it' do + expect_offense(<<~RUBY) + foo.select do _1 + 4444000039123123129993912312312999199291203123 end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Line is too long. [69/40] + RUBY + + expect_correction(<<~RUBY) + foo.select do + _1 + 4444000039123123129993912312312999199291203123 end + RUBY + end + end end context 'semicolon' do From 39d2ffcf337b6c1a7ee13c7f6caa3bb579f0a2dc Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:17:37 +0300 Subject: [PATCH 22/47] Fix Layout/MultilineBlockLayout with numblocks --- .../cop/layout/multiline_block_layout.rb | 2 ++ .../cop/layout/multiline_block_layout_spec.rb | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/lib/rubocop/cop/layout/multiline_block_layout.rb b/lib/rubocop/cop/layout/multiline_block_layout.rb index 03482837fa1..080de95ab4f 100644 --- a/lib/rubocop/cop/layout/multiline_block_layout.rb +++ b/lib/rubocop/cop/layout/multiline_block_layout.rb @@ -68,6 +68,8 @@ def on_block(node) add_offense_for_expression(node, node.body, MSG) end + alias on_numblock on_block + private def args_on_beginning_line?(node) diff --git a/spec/rubocop/cop/layout/multiline_block_layout_spec.rb b/spec/rubocop/cop/layout/multiline_block_layout_spec.rb index d1f390e1a59..cf00c16ca03 100644 --- a/spec/rubocop/cop/layout/multiline_block_layout_spec.rb +++ b/spec/rubocop/cop/layout/multiline_block_layout_spec.rb @@ -348,4 +348,34 @@ def f end RUBY end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense and corrects for missing newline in {} block w/o params' do + expect_offense(<<~RUBY) + test { _1 + ^^ Block body expression is on the same line as the block start. + } + RUBY + + expect_correction(<<~RUBY) + test {#{trailing_whitespace} + _1 + } + RUBY + end + + it 'registers an offense and corrects for missing newline in do/end block with params' do + expect_offense(<<~RUBY) + test do _1 + ^^ Block body expression is on the same line as the block start. + end + RUBY + + expect_correction(<<~RUBY) + test do#{trailing_whitespace} + _1 + end + RUBY + end + end end From 9d90591efeecff85d376749118c27cbc81bb59c1 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:19:14 +0300 Subject: [PATCH 23/47] Fix Layout/SpaceBeforeBlockBraces with numblocks --- .../cop/layout/space_before_block_braces.rb | 2 + .../layout/space_before_block_braces_spec.rb | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/lib/rubocop/cop/layout/space_before_block_braces.rb b/lib/rubocop/cop/layout/space_before_block_braces.rb index 710d1e40f07..b844c7e838a 100644 --- a/lib/rubocop/cop/layout/space_before_block_braces.rb +++ b/lib/rubocop/cop/layout/space_before_block_braces.rb @@ -76,6 +76,8 @@ def on_block(node) end end + alias on_numblock on_block + private def check_empty(left_brace, space_plus_brace, used_style) diff --git a/spec/rubocop/cop/layout/space_before_block_braces_spec.rb b/spec/rubocop/cop/layout/space_before_block_braces_spec.rb index ec4bc161569..ce7de02b510 100644 --- a/spec/rubocop/cop/layout/space_before_block_braces_spec.rb +++ b/spec/rubocop/cop/layout/space_before_block_braces_spec.rb @@ -47,6 +47,37 @@ } RUBY end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense and corrects opposite + correct style' do + expect_offense(<<~RUBY) + each{ _1 } + ^ Space missing to the left of {. + each { _1 } + RUBY + + expect_correction(<<~RUBY) + each { _1 } + each { _1 } + RUBY + end + + it 'registers an offense and corrects multiline block where the left ' \ + 'brace has no outer space' do + expect_offense(<<~RUBY) + foo.map{ + ^ Space missing to the left of {. + _1.bar.to_s + } + RUBY + + expect_correction(<<~RUBY) + foo.map { + _1.bar.to_s + } + RUBY + end + end end context 'when EnforcedStyle is no_space' do @@ -80,6 +111,21 @@ expect_no_offenses('each{ puts }') end + context 'Ruby 2.7', :ruby27 do + it 'registers an offense and corrects correct + opposite style' do + expect_offense(<<~RUBY) + each{ _1 } + each { _1 } + ^ Space detected to the left of {. + RUBY + + expect_correction(<<~RUBY) + each{ _1 } + each{ _1 } + RUBY + end + end + context 'with `EnforcedStyle` of `Style/BlockDelimiters`' do let(:config) do merged_config = RuboCop::ConfigLoader.default_configuration[ From e707f3b302db55494f749ddccd12f282101c3e4a Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:19:45 +0300 Subject: [PATCH 24/47] Fix Lint/NextWithoutAccumulator with numblocks --- .../cop/lint/next_without_accumulator.rb | 31 +++++++++++++++---- .../cop/lint/next_without_accumulator_spec.rb | 12 +++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/rubocop/cop/lint/next_without_accumulator.rb b/lib/rubocop/cop/lint/next_without_accumulator.rb index 0c239cb5324..da811e60ad0 100644 --- a/lib/rubocop/cop/lint/next_without_accumulator.rb +++ b/lib/rubocop/cop/lint/next_without_accumulator.rb @@ -25,13 +25,8 @@ module Lint class NextWithoutAccumulator < Base MSG = 'Use `next` with an accumulator argument in a `reduce`.' - # @!method on_body_of_reduce(node) - def_node_matcher :on_body_of_reduce, <<~PATTERN - (block (send _recv {:reduce :inject} !sym) _blockargs $(begin ...)) - PATTERN - def on_block(node) - on_body_of_reduce(node) do |body| + on_block_body_of_reduce(node) do |body| void_next = body.each_node(:next).find do |n| n.children.empty? && parent_block_node(n) == node end @@ -40,11 +35,35 @@ def on_block(node) end end + def on_numblock(node) + on_numblock_body_of_reduce(node) do |body| + void_next = body.each_node(:next).find do |n| + n.children.empty? && parent_numblock_node(n) == node + end + + add_offense(void_next) if void_next + end + end + private + # @!method on_block_body_of_reduce(node) + def_node_matcher :on_block_body_of_reduce, <<~PATTERN + (block (send _recv {:reduce :inject} !sym) _blockargs $(begin ...)) + PATTERN + + # @!method on_numblock_body_of_reduce(node) + def_node_matcher :on_numblock_body_of_reduce, <<~PATTERN + (numblock (send _recv {:reduce :inject} !sym) _argscount $(begin ...)) + PATTERN + def parent_block_node(node) node.each_ancestor(:block).first end + + def parent_numblock_node(node) + node.each_ancestor(:numblock).first + end end end end diff --git a/spec/rubocop/cop/lint/next_without_accumulator_spec.rb b/spec/rubocop/cop/lint/next_without_accumulator_spec.rb index 179095af295..832ec4a4463 100644 --- a/spec/rubocop/cop/lint/next_without_accumulator_spec.rb +++ b/spec/rubocop/cop/lint/next_without_accumulator_spec.rb @@ -33,6 +33,18 @@ end RUBY end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for a bare next' do + expect_offense(<<~RUBY) + (1..4).#{reduce_alias}(0) do + next if _2.odd? + ^^^^ Use `next` with an accumulator argument in a `reduce`. + _1 + i + end + RUBY + end + end end end From 911de3685042ea7f06eda8a4551fa80570d23fa0 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:20:05 +0300 Subject: [PATCH 25/47] Fix Lint/NonDeterministicRequireOrder with numblocks --- .../cop/lint/non_deterministic_require_order.rb | 12 ++++++++++++ .../lint/non_deterministic_require_order_spec.rb | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/rubocop/cop/lint/non_deterministic_require_order.rb b/lib/rubocop/cop/lint/non_deterministic_require_order.rb index df9bc2494e3..6a5aeac60bc 100644 --- a/lib/rubocop/cop/lint/non_deterministic_require_order.rb +++ b/lib/rubocop/cop/lint/non_deterministic_require_order.rb @@ -74,6 +74,18 @@ def on_block(node) end end + def on_numblock(node) + return if target_ruby_version >= 3.0 + return unless node.body + return unless unsorted_dir_loop?(node.send_node) + + node.argument_list + .filter { |argument| var_is_required?(node.body, argument.name) } + .each do + add_offense(node.send_node) { |corrector| correct_block(corrector, node.send_node) } + end + end + def on_block_pass(node) return if target_ruby_version >= 3.0 return unless method_require?(node) diff --git a/spec/rubocop/cop/lint/non_deterministic_require_order_spec.rb b/spec/rubocop/cop/lint/non_deterministic_require_order_spec.rb index 2328b8cf13a..086ea99ed55 100644 --- a/spec/rubocop/cop/lint/non_deterministic_require_order_spec.rb +++ b/spec/rubocop/cop/lint/non_deterministic_require_order_spec.rb @@ -131,6 +131,21 @@ RUBY end + it 'registers an offsense and autocorrects to add .sort when the numblock has `require`' do + expect_offense(<<~RUBY) + Dir["./lib/**/*.rb"].each do + ^^^^^^^^^^^^^^^^^^^^^^^^^ Sort files before requiring them. + require _1 + end + RUBY + + expect_correction(<<~RUBY) + Dir["./lib/**/*.rb"].sort.each do + require _1 + end + RUBY + end + it 'registers an offsense and autocorrects to add .sort when the block has `require_relative`' do expect_offense(<<~RUBY) Dir["./lib/**/*.rb"].each do |file| From 58a6577096acc86b5e1eda97c44178c9fb8dda03 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:26:43 +0300 Subject: [PATCH 26/47] Fix Lint/RedundantWithIndex with numblocks --- lib/rubocop/cop/lint/redundant_with_index.rb | 23 ++++++++------- .../cop/lint/redundant_with_index_spec.rb | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/lib/rubocop/cop/lint/redundant_with_index.rb b/lib/rubocop/cop/lint/redundant_with_index.rb index 45e514dc7bc..8b22899f5cf 100644 --- a/lib/rubocop/cop/lint/redundant_with_index.rb +++ b/lib/rubocop/cop/lint/redundant_with_index.rb @@ -33,16 +33,6 @@ class RedundantWithIndex < Base MSG_EACH_WITH_INDEX = 'Use `each` instead of `each_with_index`.' MSG_WITH_INDEX = 'Remove redundant `with_index`.' - # @!method redundant_with_index?(node) - def_node_matcher :redundant_with_index?, <<~PATTERN - (block - $(send - _ {:each_with_index :with_index} ...) - (args - (arg _)) - ...) - PATTERN - def on_block(node) return unless (send = redundant_with_index?(node)) @@ -58,8 +48,21 @@ def on_block(node) end end + alias on_numblock on_block + private + # @!method redundant_with_index?(node) + def_node_matcher :redundant_with_index?, <<~PATTERN + { + (block + $(send _ {:each_with_index :with_index} ...) + (args (arg _)) ...) + (numblock + $(send _ {:each_with_index :with_index} ...) 1 ...) + } + PATTERN + def message(node) if node.method?(:each_with_index) MSG_EACH_WITH_INDEX diff --git a/spec/rubocop/cop/lint/redundant_with_index_spec.rb b/spec/rubocop/cop/lint/redundant_with_index_spec.rb index 068f52dfb03..fc9744351fd 100644 --- a/spec/rubocop/cop/lint/redundant_with_index_spec.rb +++ b/spec/rubocop/cop/lint/redundant_with_index_spec.rb @@ -51,4 +51,32 @@ it 'accepts an index is used as a block argument' do expect_no_offenses('ary.each_with_index { |v, i| v; i }') end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for `ary.each_with_index { _1 }` and corrects to `ary.each`' do + expect_offense(<<~RUBY) + ary.each_with_index { _1 } + ^^^^^^^^^^^^^^^ Use `each` instead of `each_with_index`. + RUBY + + expect_correction(<<~RUBY) + ary.each { _1 } + RUBY + end + + it 'registers an offense when using `ary.each.with_index { _1 }` and corrects to `ary.each`' do + expect_offense(<<~RUBY) + ary.each.with_index { _1 } + ^^^^^^^^^^ Remove redundant `with_index`. + RUBY + + expect_correction(<<~RUBY) + ary.each { _1 } + RUBY + end + + it 'accepts an index is used as a numblock argument' do + expect_no_offenses('ary.each_with_index { _1; _2 }') + end + end end From 198047bcadfd9f5fe9eee1df4b569769e8b996f6 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:27:44 +0300 Subject: [PATCH 27/47] Fix Lint/RedundantWithObject with numblocks --- lib/rubocop/cop/lint/redundant_with_object.rb | 23 +++++++++--------- .../cop/lint/redundant_with_object_spec.rb | 24 +++++++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/lib/rubocop/cop/lint/redundant_with_object.rb b/lib/rubocop/cop/lint/redundant_with_object.rb index cfc54b1dba0..3e3c0b24ac6 100644 --- a/lib/rubocop/cop/lint/redundant_with_object.rb +++ b/lib/rubocop/cop/lint/redundant_with_object.rb @@ -31,19 +31,8 @@ class RedundantWithObject < Base extend AutoCorrector MSG_EACH_WITH_OBJECT = 'Use `each` instead of `each_with_object`.' - MSG_WITH_OBJECT = 'Remove redundant `with_object`.' - # @!method redundant_with_object?(node) - def_node_matcher :redundant_with_object?, <<~PATTERN - (block - $(send _ {:each_with_object :with_object} - _) - (args - (arg _)) - ...) - PATTERN - def on_block(node) return unless (send = redundant_with_object?(node)) @@ -59,8 +48,20 @@ def on_block(node) end end + alias on_numblock on_block + private + # @!method redundant_with_object?(node) + def_node_matcher :redundant_with_object?, <<~PATTERN + { + (block + $(send _ {:each_with_object :with_object} _) (args (arg _)) ...) + (numblock + $(send _ {:each_with_object :with_object} _) 1 ...) + } + PATTERN + def message(node) if node.method?(:each_with_object) MSG_EACH_WITH_OBJECT diff --git a/spec/rubocop/cop/lint/redundant_with_object_spec.rb b/spec/rubocop/cop/lint/redundant_with_object_spec.rb index 7dd5f0073e2..9fcb70e26b2 100644 --- a/spec/rubocop/cop/lint/redundant_with_object_spec.rb +++ b/spec/rubocop/cop/lint/redundant_with_object_spec.rb @@ -67,4 +67,28 @@ expect_no_offenses('ary.each_with_object { |v| v }') end end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense and corrects when using `ary.each_with_object { _1 }`' do + expect_offense(<<~RUBY) + ary.each_with_object([]) { _1 } + ^^^^^^^^^^^^^^^^^^^^ Use `each` instead of `each_with_object`. + RUBY + + expect_correction(<<~RUBY) + ary.each { _1 } + RUBY + end + + it 'registers an offense and corrects when using `ary.each.with_object([]) { _1 }`' do + expect_offense(<<~RUBY) + ary.each.with_object([]) { _1 } + ^^^^^^^^^^^^^^^ Remove redundant `with_object`. + RUBY + + expect_correction(<<~RUBY) + ary.each { _1 } + RUBY + end + end end From bff739ad30636ea49dec682ed9b7a863c10457d3 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:29:59 +0300 Subject: [PATCH 28/47] Fix Lint/UnreachableLoop for numblocks --- lib/rubocop/cop/lint/unreachable_loop.rb | 8 +++++++- .../rubocop/cop/lint/unreachable_loop_spec.rb | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/lint/unreachable_loop.rb b/lib/rubocop/cop/lint/unreachable_loop.rb index a423b9b803a..4871fe6f6f4 100644 --- a/lib/rubocop/cop/lint/unreachable_loop.rb +++ b/lib/rubocop/cop/lint/unreachable_loop.rb @@ -101,10 +101,14 @@ def on_block(node) check(node) if loop_method?(node) end + def on_numblock(node) + check(node) if loop_method?(node) + end + private def loop_method?(node) - return false unless node.block_type? + return false unless node.block_type? || node.numblock_type? send_node = node.send_node return false if matches_allowed_pattern?(send_node.source) @@ -179,6 +183,8 @@ def check_case(node) def preceded_by_continue_statement?(break_statement) break_statement.left_siblings.any? do |sibling| + # Numblocks have the arguments count as a number in the AST. + next if sibling.is_a?(Integer) next if sibling.loop_keyword? || loop_method?(sibling) sibling.each_descendant(*CONTINUE_KEYWORDS).any? diff --git a/spec/rubocop/cop/lint/unreachable_loop_spec.rb b/spec/rubocop/cop/lint/unreachable_loop_spec.rb index baf2e841758..8ebd1a001ec 100644 --- a/spec/rubocop/cop/lint/unreachable_loop_spec.rb +++ b/spec/rubocop/cop/lint/unreachable_loop_spec.rb @@ -178,6 +178,15 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This loop will have at most one iteration. RUBY end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense' do + expect_offense(<<~RUBY) + 2.times { raise _1 } + ^^^^^^^^^^^^^^^^^^^^ This loop will have at most one iteration. + RUBY + end + end end end @@ -250,4 +259,15 @@ end RUBY end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense when using `return do_something(value) || break` in a loop' do + expect_offense(<<~RUBY) + [1, 2, 3].each do + ^^^^^^^^^^^^^^^^^ This loop will have at most one iteration. + return _1.odd? || break + end + RUBY + end + end end From 8cb4af9261dbb010865356dffd8c08b06b56a3bf Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:30:33 +0300 Subject: [PATCH 29/47] Fix Lint/UselessAccessModifier with numblocks --- .../cop/lint/useless_access_modifier.rb | 10 +++--- .../cop/lint/useless_access_modifier_spec.rb | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/lib/rubocop/cop/lint/useless_access_modifier.rb b/lib/rubocop/cop/lint/useless_access_modifier.rb index 2b04eb7509d..ba74732f0ba 100644 --- a/lib/rubocop/cop/lint/useless_access_modifier.rb +++ b/lib/rubocop/cop/lint/useless_access_modifier.rb @@ -142,6 +142,8 @@ def on_block(node) check_node(node.body) end + alias on_numblock on_block + private def autocorrect(corrector, node) @@ -157,17 +159,17 @@ def autocorrect(corrector, node) # @!method dynamic_method_definition?(node) def_node_matcher :dynamic_method_definition?, <<~PATTERN - {(send nil? :define_method ...) (block (send nil? :define_method ...) ...)} + {(send nil? :define_method ...) ({block numblock} (send nil? :define_method ...) ...)} PATTERN # @!method class_or_instance_eval?(node) def_node_matcher :class_or_instance_eval?, <<~PATTERN - (block (send _ {:class_eval :instance_eval}) ...) + ({block numblock} (send _ {:class_eval :instance_eval}) ...) PATTERN # @!method class_or_module_or_struct_new_call?(node) def_node_matcher :class_or_module_or_struct_new_call?, <<~PATTERN - (block (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...) + ({block numblock} (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...) PATTERN def check_node(node) @@ -277,7 +279,7 @@ def any_context_creating_methods?(child) matcher_name = "#{m}_block?".to_sym unless respond_to?(matcher_name) self.class.def_node_matcher matcher_name, <<~PATTERN - (block (send {nil? const} {:#{m}} ...) ...) + ({block numblock} (send {nil? const} {:#{m}} ...) ...) PATTERN end diff --git a/spec/rubocop/cop/lint/useless_access_modifier_spec.rb b/spec/rubocop/cop/lint/useless_access_modifier_spec.rb index 6ab9b2a80cc..a851b3a08dd 100644 --- a/spec/rubocop/cop/lint/useless_access_modifier_spec.rb +++ b/spec/rubocop/cop/lint/useless_access_modifier_spec.rb @@ -329,6 +329,42 @@ def another_method end RUBY end + + context 'Ruby 2.7', :ruby27 do + it 'still points out redundant uses within the block' do + expect_offense(<<~RUBY) + class SomeClass + concerning :SecondThing do + p _1 + def omg + end + private + def method + end + private + ^^^^^^^ Useless `private` access modifier. + def another_method + end + end + end + RUBY + + expect_correction(<<~RUBY) + class SomeClass + concerning :SecondThing do + p _1 + def omg + end + private + def method + end + def another_method + end + end + end + RUBY + end + end end context 'when using ActiveSupport behavior when Rails is not eabled' do From 92cbae59628d787b619800f31a1e7d170a9114ae Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:30:52 +0300 Subject: [PATCH 30/47] Fix Lint/Void with numblocks --- lib/rubocop/cop/lint/void.rb | 2 ++ spec/rubocop/cop/lint/void_spec.rb | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/rubocop/cop/lint/void.rb b/lib/rubocop/cop/lint/void.rb index 3d0f8fa08e2..5ae162ddebb 100644 --- a/lib/rubocop/cop/lint/void.rb +++ b/lib/rubocop/cop/lint/void.rb @@ -67,6 +67,8 @@ def on_block(node) check_expression(node.body) end + alias on_numblock on_block + def on_begin(node) check_begin(node) end diff --git a/spec/rubocop/cop/lint/void_spec.rb b/spec/rubocop/cop/lint/void_spec.rb index 5226d616c2e..5844b48e22f 100644 --- a/spec/rubocop/cop/lint/void_spec.rb +++ b/spec/rubocop/cop/lint/void_spec.rb @@ -188,6 +188,18 @@ def foo=(rhs) RUBY end + context 'Ruby 2.7', :ruby27 do + it 'registers two offenses for void literals in `#tap` method' do + expect_offense(<<~RUBY) + foo.tap do + _1 + ^^ Variable `_1` used in void context. + 42 + end + RUBY + end + end + it 'accepts empty block' do expect_no_offenses(<<~RUBY) array.each { |_item| } From 494424c33987415d1d807f1a5e13ac59aed0dffa Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:31:58 +0300 Subject: [PATCH 31/47] Fix Metrics{AbcSize,CyclomaticComplexity} with numblocks Both of them use `MethodComplexity` which now supports `define_method` with numblocks. --- lib/rubocop/cop/mixin/method_complexity.rb | 8 ++++---- spec/rubocop/cop/metrics/abc_size_spec.rb | 11 +++++++++++ .../cop/metrics/cyclomatic_complexity_spec.rb | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/lib/rubocop/cop/mixin/method_complexity.rb b/lib/rubocop/cop/mixin/method_complexity.rb index 92be750b239..7fb1f4b8687 100644 --- a/lib/rubocop/cop/mixin/method_complexity.rb +++ b/lib/rubocop/cop/mixin/method_complexity.rb @@ -29,14 +29,14 @@ def on_block(node) end end + alias on_numblock on_block + private # @!method define_method?(node) def_node_matcher :define_method?, <<~PATTERN - (block - (send nil? :define_method ({sym str} $_)) - args - _) + ({block numblock} + (send nil? :define_method ({sym str} $_)) _ _) PATTERN def check_complexity(node, method_name) diff --git a/spec/rubocop/cop/metrics/abc_size_spec.rb b/spec/rubocop/cop/metrics/abc_size_spec.rb index 24de31eb20d..b79817342e0 100644 --- a/spec/rubocop/cop/metrics/abc_size_spec.rb +++ b/spec/rubocop/cop/metrics/abc_size_spec.rb @@ -67,6 +67,17 @@ def method_name RUBY end + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for a `define_method` with numblock' do + expect_offense(<<~RUBY) + define_method :method_name do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Assignment Branch Condition size for method_name is too high. [<1, 0, 0> 1/0] + x = _1 + end + RUBY + end + end + it 'treats safe navigation method calls like regular method calls + a condition' do expect_offense(<<~RUBY) def method_name diff --git a/spec/rubocop/cop/metrics/cyclomatic_complexity_spec.rb b/spec/rubocop/cop/metrics/cyclomatic_complexity_spec.rb index 1b147f213e2..dffbb3d5214 100644 --- a/spec/rubocop/cop/metrics/cyclomatic_complexity_spec.rb +++ b/spec/rubocop/cop/metrics/cyclomatic_complexity_spec.rb @@ -268,6 +268,20 @@ def method_name_2 RUBY end + context 'Ruby 2.7', :ruby27 do + it 'counts enumerating methods with numblocks as +1' do + expect_offense(<<~RUBY) + define_method :method_name do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cyclomatic complexity for method_name is too high. [3/1] + (_1.._2).map do |i| # map: +1 + i * 2 + end.each.with_index { |val, i| puts val, i } # each: +0, with_index: +1 + return treasure.map + end + RUBY + end + end + it 'counts enumerating methods with block-pass as +1' do expect_offense(<<~RUBY) define_method :method_name do From d5dd79650393f4042fce5419153808bff6d15dfc Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:33:53 +0300 Subject: [PATCH 32/47] Fix Style/MethodCalledOnDoEndBlock with numblocks --- .../cop/style/method_called_on_do_end_block.rb | 5 ++++- .../cop/style/method_called_on_do_end_block_spec.rb | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/method_called_on_do_end_block.rb b/lib/rubocop/cop/style/method_called_on_do_end_block.rb index b58adc8f195..808558233f8 100644 --- a/lib/rubocop/cop/style/method_called_on_do_end_block.rb +++ b/lib/rubocop/cop/style/method_called_on_do_end_block.rb @@ -35,12 +35,15 @@ def on_block(node) ignore_node(node.send_node) end + alias on_numblock on_block + def on_send(node) return if ignored_node?(node) receiver = node.receiver - return unless receiver&.block_type? && receiver.loc.end.is?('end') + return unless (receiver&.block_type? || receiver&.numblock_type?) && + receiver.loc.end.is?('end') range = range_between(receiver.loc.end.begin_pos, node.source_range.end_pos) diff --git a/spec/rubocop/cop/style/method_called_on_do_end_block_spec.rb b/spec/rubocop/cop/style/method_called_on_do_end_block_spec.rb index 51eedd011e6..82943c99b35 100644 --- a/spec/rubocop/cop/style/method_called_on_do_end_block_spec.rb +++ b/spec/rubocop/cop/style/method_called_on_do_end_block_spec.rb @@ -67,4 +67,15 @@ expect_no_offenses('a { b }.c') end end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for a chained call' do + expect_offense(<<~RUBY) + a do + _1 + end.c + ^^^^^ Avoid chaining a method call on a do...end block. + RUBY + end + end end From 6e67b8940ee2a15601437f6bcedbdcbaa24aed95 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:34:16 +0300 Subject: [PATCH 33/47] Fix Style/Proc with numblocks --- lib/rubocop/cop/style/proc.rb | 5 ++++- spec/rubocop/cop/style/proc_spec.rb | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/proc.rb b/lib/rubocop/cop/style/proc.rb index 02bdc65b504..c9091183069 100644 --- a/lib/rubocop/cop/style/proc.rb +++ b/lib/rubocop/cop/style/proc.rb @@ -19,7 +19,8 @@ class Proc < Base MSG = 'Use `proc` instead of `Proc.new`.' # @!method proc_new?(node) - def_node_matcher :proc_new?, '(block $(send (const {nil? cbase} :Proc) :new) ...)' + def_node_matcher :proc_new?, + '({block numblock} $(send (const {nil? cbase} :Proc) :new) ...)' def on_block(node) proc_new?(node) do |block_method| @@ -28,6 +29,8 @@ def on_block(node) end end end + + alias on_numblock on_block end end end diff --git a/spec/rubocop/cop/style/proc_spec.rb b/spec/rubocop/cop/style/proc_spec.rb index bbf64250789..0536448a224 100644 --- a/spec/rubocop/cop/style/proc_spec.rb +++ b/spec/rubocop/cop/style/proc_spec.rb @@ -30,4 +30,17 @@ it 'accepts the ::Proc.new call without block' do expect_no_offenses('p = ::Proc.new') end + + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for a Proc.new call' do + expect_offense(<<~RUBY) + f = Proc.new { puts _1 } + ^^^^^^^^ Use `proc` instead of `Proc.new`. + RUBY + + expect_correction(<<~RUBY) + f = proc { puts _1 } + RUBY + end + end end From b9555f655fa40040dd5a9ed2785558d707ec2028 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:34:36 +0300 Subject: [PATCH 34/47] Fix Style/For with numblocks The autocorrect can and will generate broken code when using numbered arguments as `_1` is not a valid local variable name outside numblocks. --- lib/rubocop/cop/style/for.rb | 2 ++ spec/rubocop/cop/style/for_spec.rb | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/lib/rubocop/cop/style/for.rb b/lib/rubocop/cop/style/for.rb index 3bf47e9fc46..f3c336bca48 100644 --- a/lib/rubocop/cop/style/for.rb +++ b/lib/rubocop/cop/style/for.rb @@ -75,6 +75,8 @@ def on_block(node) end end + alias on_numblock on_block + private def suspect_enumerable?(node) diff --git a/spec/rubocop/cop/style/for_spec.rb b/spec/rubocop/cop/style/for_spec.rb index cda622103e4..739ee7f06b3 100644 --- a/spec/rubocop/cop/style/for_spec.rb +++ b/spec/rubocop/cop/style/for_spec.rb @@ -442,6 +442,27 @@ def func RUBY end + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for each without an item and uses _ as the item' do + expect_offense(<<~RUBY) + def func + [1, 2, 3].each do + ^^^^^^^^^^^^^^^^^ Prefer `for` over `each`. + puts _1 + end + end + RUBY + + expect_correction(<<~RUBY) + def func + for _ in [1, 2, 3] do + puts _1 + end + end + RUBY + end + end + it 'registers an offense for correct + opposite style' do expect_offense(<<~RUBY) def func From a13618869ddd9e959ee42e73fa45bbc65953f0af Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:35:52 +0300 Subject: [PATCH 35/47] Fix Style/TopLevelMethodDefinition with numblocks --- lib/rubocop/cop/style/top_level_method_definition.rb | 4 +++- .../cop/style/top_level_method_definition_spec.rb | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/top_level_method_definition.rb b/lib/rubocop/cop/style/top_level_method_definition.rb index 4b94428b2ae..c896db41785 100644 --- a/lib/rubocop/cop/style/top_level_method_definition.rb +++ b/lib/rubocop/cop/style/top_level_method_definition.rb @@ -63,6 +63,8 @@ def on_block(node) add_offense(node) end + alias on_numblock on_block + private def top_level_method_definition?(node) @@ -75,7 +77,7 @@ def top_level_method_definition?(node) # @!method define_method_block?(node) def_node_matcher :define_method_block?, <<~PATTERN - (block (send _ {:define_method} _) ...) + ({block numblock} (send _ {:define_method} _) ...) PATTERN end end diff --git a/spec/rubocop/cop/style/top_level_method_definition_spec.rb b/spec/rubocop/cop/style/top_level_method_definition_spec.rb index d1d5ccb9090..05456ad13c4 100644 --- a/spec/rubocop/cop/style/top_level_method_definition_spec.rb +++ b/spec/rubocop/cop/style/top_level_method_definition_spec.rb @@ -23,6 +23,15 @@ def self.foo; end RUBY end + context 'Ruby >= 2.7', :ruby27 do + it 'registers offense with inline numblock' do + expect_offense(<<~RUBY) + define_method(:foo) { puts _1 } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not define methods at the top-level. + RUBY + end + end + it 'registers offense for multi-line block' do expect_offense(<<~RUBY) define_method(:foo) do |x| From a049d3287342f684d94dd0ebd5c63f33fa703a83 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:36:52 +0300 Subject: [PATCH 36/47] Fix Style/CombinableLoops with numblocks --- lib/rubocop/cop/style/combinable_loops.rb | 4 +++- .../rubocop/cop/style/combinable_loops_spec.rb | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/combinable_loops.rb b/lib/rubocop/cop/style/combinable_loops.rb index c29529a122e..4ed6d763666 100644 --- a/lib/rubocop/cop/style/combinable_loops.rb +++ b/lib/rubocop/cop/style/combinable_loops.rb @@ -66,6 +66,8 @@ def on_block(node) add_offense(node) if same_collection_looping?(node, node.left_sibling) end + alias on_numblock on_block + def on_for(node) return unless node.parent&.begin_type? @@ -82,7 +84,7 @@ def collection_looping_method?(node) end def same_collection_looping?(node, sibling) - sibling&.block_type? && + (sibling&.block_type? || sibling&.numblock_type?) && sibling.send_node.method?(node.method_name) && sibling.receiver == node.receiver && sibling.send_node.arguments == node.send_node.arguments diff --git a/spec/rubocop/cop/style/combinable_loops_spec.rb b/spec/rubocop/cop/style/combinable_loops_spec.rb index 7ac3e3e3118..465deb208a3 100644 --- a/spec/rubocop/cop/style/combinable_loops_spec.rb +++ b/spec/rubocop/cop/style/combinable_loops_spec.rb @@ -18,6 +18,24 @@ RUBY end + context 'Ruby 2.7' do + it 'registers an offense when looping over the same data as previous loop in numblocks' do + expect_offense(<<~RUBY) + items.each { do_something(_1) } + items.each { do_something_else(_1, arg) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Combine this loop with the previous loop. + + items.each_with_index { do_something(_1) } + items.each_with_index { do_something_else(_1, arg) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Combine this loop with the previous loop. + + items.reverse_each { do_something(_1) } + items.reverse_each { do_something_else(_1, arg) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Combine this loop with the previous loop. + RUBY + end + end + it 'does not register an offense when the same loops are interleaved with some code' do expect_no_offenses(<<~RUBY) items.each { |item| do_something(item) } From 33d5d21cccce863787b8dbfe44935097619f15c3 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:37:11 +0300 Subject: [PATCH 37/47] Fix Style/MultilineBlockChain with numblocks --- lib/rubocop/cop/style/multiline_block_chain.rb | 4 +++- .../rubocop/cop/style/multiline_block_chain_spec.rb | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/multiline_block_chain.rb b/lib/rubocop/cop/style/multiline_block_chain.rb index 8634465366f..7f9de566ae3 100644 --- a/lib/rubocop/cop/style/multiline_block_chain.rb +++ b/lib/rubocop/cop/style/multiline_block_chain.rb @@ -31,7 +31,7 @@ def on_block(node) node.send_node.each_node(:send) do |send_node| receiver = send_node.receiver - next unless receiver&.block_type? && receiver&.multiline? + next unless (receiver&.block_type? || receiver&.numblock_type?) && receiver&.multiline? range = range_between(receiver.loc.end.begin_pos, node.send_node.source_range.end_pos) @@ -42,6 +42,8 @@ def on_block(node) break end end + + alias on_numblock on_block end end end diff --git a/spec/rubocop/cop/style/multiline_block_chain_spec.rb b/spec/rubocop/cop/style/multiline_block_chain_spec.rb index 0ee57f02224..2e8330fa993 100644 --- a/spec/rubocop/cop/style/multiline_block_chain_spec.rb +++ b/spec/rubocop/cop/style/multiline_block_chain_spec.rb @@ -24,6 +24,19 @@ RUBY end + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for a slightly more complicated case' do + expect_offense(<<~RUBY) + a do + _1 + end.c1.c2 do + ^^^^^^^^^ Avoid multi-line chains of blocks. + _1 + end + RUBY + end + end + it 'registers two offenses for a chain of three blocks' do expect_offense(<<~RUBY) a do From 254564b8280e63f5c1a61264b1598b8a42dab5bb Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:37:24 +0300 Subject: [PATCH 38/47] Fix Style/ObjectThen with numblocks --- lib/rubocop/cop/style/object_then.rb | 2 ++ spec/rubocop/cop/style/object_then_spec.rb | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/rubocop/cop/style/object_then.rb b/lib/rubocop/cop/style/object_then.rb index fc09314a750..f36ae076fdd 100644 --- a/lib/rubocop/cop/style/object_then.rb +++ b/lib/rubocop/cop/style/object_then.rb @@ -32,6 +32,8 @@ def on_block(node) check_method_node(node.send_node) end + alias on_numblock on_block + def on_send(node) return unless node.arguments.one? && node.first_argument.block_pass_type? diff --git a/spec/rubocop/cop/style/object_then_spec.rb b/spec/rubocop/cop/style/object_then_spec.rb index 80b34dcdcaf..27780e00b5f 100644 --- a/spec/rubocop/cop/style/object_then_spec.rb +++ b/spec/rubocop/cop/style/object_then_spec.rb @@ -15,6 +15,19 @@ RUBY end + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for yield_self with block' do + expect_offense(<<~RUBY) + obj.yield_self { _1.test } + ^^^^^^^^^^ Prefer `then` over `yield_self`. + RUBY + + expect_correction(<<~RUBY) + obj.then { _1.test } + RUBY + end + end + it 'registers an offense for yield_self with proc param' do expect_offense(<<~RUBY) obj.yield_self(&:test) From be532afb98b2f56a8b2e348c4b68f4ba150371b9 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:38:40 +0300 Subject: [PATCH 39/47] Fix Style/Next for numblocks --- lib/rubocop/cop/style/next.rb | 2 ++ spec/rubocop/cop/style/next_spec.rb | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/rubocop/cop/style/next.rb b/lib/rubocop/cop/style/next.rb index b3b47b231a5..e17db2cb62b 100644 --- a/lib/rubocop/cop/style/next.rb +++ b/lib/rubocop/cop/style/next.rb @@ -71,6 +71,8 @@ def on_block(node) check(node) end + alias on_numblock on_block + def on_while(node) check(node) end diff --git a/spec/rubocop/cop/style/next_spec.rb b/spec/rubocop/cop/style/next_spec.rb index 461e6859a80..e1f214ea82a 100644 --- a/spec/rubocop/cop/style/next_spec.rb +++ b/spec/rubocop/cop/style/next_spec.rb @@ -24,6 +24,26 @@ RUBY end + context 'Ruby 2.7', :ruby27 do + it "registers an offense for #{condition} inside of downto numblock" do + expect_offense(<<~RUBY, condition: condition) + 3.downto(1) do + %{condition} _1 == 1 + ^{condition}^^^^^^^^ Use `next` to skip iteration. + puts _1 + end + end + RUBY + + expect_correction(<<~RUBY) + 3.downto(1) do + next #{opposite} _1 == 1 + puts _1 + end + RUBY + end + end + it "registers an offense for #{condition} inside of each" do expect_offense(<<~RUBY, condition: condition) [].each do |o| From 88c78bd62b05943cb4dcd22e1aac9a6a0a437da9 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:38:59 +0300 Subject: [PATCH 40/47] Fix Style/RedundantSelf with numblocks --- lib/rubocop/cop/style/redundant_self.rb | 2 ++ spec/rubocop/cop/style/redundant_self_spec.rb | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/rubocop/cop/style/redundant_self.rb b/lib/rubocop/cop/style/redundant_self.rb index 3edfa90cf7d..af9279c6b45 100644 --- a/lib/rubocop/cop/style/redundant_self.rb +++ b/lib/rubocop/cop/style/redundant_self.rb @@ -120,6 +120,8 @@ def on_block(node) add_scope(node, @local_variables_scopes[node]) end + alias on_numblock on_block + def on_if(node) # Allow conditional nodes to use `self` in the condition if that variable # name is used in an `lvasgn` or `masgn` within the `if`. diff --git a/spec/rubocop/cop/style/redundant_self_spec.rb b/spec/rubocop/cop/style/redundant_self_spec.rb index 3aaee581dcc..71c7890a2fd 100644 --- a/spec/rubocop/cop/style/redundant_self_spec.rb +++ b/spec/rubocop/cop/style/redundant_self_spec.rb @@ -167,6 +167,23 @@ RUBY end + context 'Ruby 2.7', :ruby27 do + it 'registers offense for self usage in numblocks' do + expect_offense(<<~RUBY) + %w[x y z].select do + self.axis == _1 + ^^^^ Redundant `self` detected. + end + RUBY + + expect_correction(<<~RUBY) + %w[x y z].select do + axis == _1 + end + RUBY + end + end + describe 'instance methods' do it 'accepts a self receiver used to distinguish from blockarg' do expect_no_offenses(<<~RUBY) From bdb1db984316e246cdc0116014dac8e72f8850cc Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:39:16 +0300 Subject: [PATCH 41/47] Fix Style/RedundantBegin with numblocks --- lib/rubocop/cop/style/redundant_begin.rb | 2 + .../rubocop/cop/style/redundant_begin_spec.rb | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/lib/rubocop/cop/style/redundant_begin.rb b/lib/rubocop/cop/style/redundant_begin.rb index 54f0a3a8df4..fe5b0bfd44a 100644 --- a/lib/rubocop/cop/style/redundant_begin.rb +++ b/lib/rubocop/cop/style/redundant_begin.rb @@ -89,6 +89,8 @@ def on_block(node) register_offense(node.body) end + alias on_numblock on_block + def on_kwbegin(node) return unless (target_node = offensive_kwbegins(node).to_a.last) diff --git a/spec/rubocop/cop/style/redundant_begin_spec.rb b/spec/rubocop/cop/style/redundant_begin_spec.rb index 8f2f0011df6..ff4781d8b49 100644 --- a/spec/rubocop/cop/style/redundant_begin_spec.rb +++ b/spec/rubocop/cop/style/redundant_begin_spec.rb @@ -531,4 +531,42 @@ def a_method end RUBY end + + context 'Ruby 2.7', :ruby27 do + it 'reports an offense when assigning nested blocks which contain `begin` blocks' do + expect_offense(<<~RUBY) + var = do_something do + begin + ^^^^^ Redundant `begin` block detected. + do_something do + begin + ^^^^^ Redundant `begin` block detected. + _1 + ensure + bar + end + end + ensure + baz + end + end + RUBY + + expect_correction(<<~RUBY) + var = do_something do + #{trailing_whitespace} + do_something do + #{trailing_whitespace} + _1 + ensure + bar + #{trailing_whitespace} + end + ensure + baz + #{trailing_whitespace} + end + RUBY + end + end end From 381c2b8f1265a0c7d283676a330ed98c769f0bb0 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:39:46 +0300 Subject: [PATCH 42/47] Fix Style/RedundantSortBy with numblocks --- lib/rubocop/cop/style/redundant_sort_by.rb | 32 ++++++++++++++----- .../cop/style/redundant_sort_by_spec.rb | 13 ++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/lib/rubocop/cop/style/redundant_sort_by.rb b/lib/rubocop/cop/style/redundant_sort_by.rb index a746cdf3263..2cc1be8b78d 100644 --- a/lib/rubocop/cop/style/redundant_sort_by.rb +++ b/lib/rubocop/cop/style/redundant_sort_by.rb @@ -19,18 +19,24 @@ class RedundantSortBy < Base include RangeHelp extend AutoCorrector - MSG = 'Use `sort` instead of `sort_by { |%s| %s }`.' - - # @!method redundant_sort_by(node) - def_node_matcher :redundant_sort_by, <<~PATTERN - (block $(send _ :sort_by) (args (arg $_x)) (lvar _x)) - PATTERN + MSG_BLOCK = 'Use `sort` instead of `sort_by { |%s| %s }`.' + MSG_NUMBLOCK = 'Use `sort` instead of `sort_by { _1 }`.' def on_block(node) - redundant_sort_by(node) do |send, var_name| + redundant_sort_by_block(node) do |send, var_name| range = sort_by_range(send, node) - add_offense(range, message: format(MSG, var: var_name)) do |corrector| + add_offense(range, message: format(MSG_BLOCK, var: var_name)) do |corrector| + corrector.replace(range, 'sort') + end + end + end + + def on_numblock(node) + redundant_sort_by_numblock(node) do |send| + range = sort_by_range(send, node) + + add_offense(range, message: format(MSG_NUMBLOCK)) do |corrector| corrector.replace(range, 'sort') end end @@ -38,6 +44,16 @@ def on_block(node) private + # @!method redundant_sort_by_block(node) + def_node_matcher :redundant_sort_by_block, <<~PATTERN + (block $(send _ :sort_by) (args (arg $_x)) (lvar _x)) + PATTERN + + # @!method redundant_sort_by_numblock(node) + def_node_matcher :redundant_sort_by_numblock, <<~PATTERN + (numblock $(send _ :sort_by) 1 (lvar :_1)) + PATTERN + def sort_by_range(send, node) range_between(send.loc.selector.begin_pos, node.loc.end.end_pos) end diff --git a/spec/rubocop/cop/style/redundant_sort_by_spec.rb b/spec/rubocop/cop/style/redundant_sort_by_spec.rb index 91d9a5bbd46..f3fcbe6ee1e 100644 --- a/spec/rubocop/cop/style/redundant_sort_by_spec.rb +++ b/spec/rubocop/cop/style/redundant_sort_by_spec.rb @@ -12,6 +12,19 @@ RUBY end + context 'Ruby 2.7', :ruby27 do + it 'autocorrects array.sort_by { |x| x }' do + expect_offense(<<~RUBY) + array.sort_by { _1 } + ^^^^^^^^^^^^^^ Use `sort` instead of `sort_by { _1 }`. + RUBY + + expect_correction(<<~RUBY) + array.sort + RUBY + end + end + it 'autocorrects array.sort_by { |y| y }' do expect_offense(<<~RUBY) array.sort_by { |y| y } From c55de181ce6dab3a96b338d0d90580dd4ec6667a Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:40:45 +0300 Subject: [PATCH 43/47] Fix Style/InverseMethods with numblocks --- lib/rubocop/cop/style/inverse_methods.rb | 14 ++++++++------ spec/rubocop/cop/style/inverse_methods_spec.rb | 13 +++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/rubocop/cop/style/inverse_methods.rb b/lib/rubocop/cop/style/inverse_methods.rb index 83c6d92085a..1ed7dfb9ecd 100644 --- a/lib/rubocop/cop/style/inverse_methods.rb +++ b/lib/rubocop/cop/style/inverse_methods.rb @@ -59,18 +59,18 @@ def self.autocorrect_incompatible_with def_node_matcher :inverse_candidate?, <<~PATTERN { (send $(send $(...) $_ $...) :!) - (send (block $(send $(...) $_) $...) :!) + (send ({block numblock} $(send $(...) $_) $...) :!) (send (begin $(send $(...) $_ $...)) :!) } PATTERN # @!method inverse_block?(node) def_node_matcher :inverse_block?, <<~PATTERN - (block $(send (...) $_) ... { $(send ... :!) - $(send (...) {:!= :!~} ...) - (begin ... $(send ... :!)) - (begin ... $(send (...) {:!= :!~} ...)) - }) + ({block numblock} $(send (...) $_) ... { $(send ... :!) + $(send (...) {:!= :!~} ...) + (begin ... $(send ... :!)) + (begin ... $(send (...) {:!= :!~} ...)) + }) PATTERN def on_send(node) @@ -102,6 +102,8 @@ def on_block(node) end end + alias on_numblock on_block + private def correct_inverse_method(corrector, node) diff --git a/spec/rubocop/cop/style/inverse_methods_spec.rb b/spec/rubocop/cop/style/inverse_methods_spec.rb index 25d8f8f8215..699bae6bc2f 100644 --- a/spec/rubocop/cop/style/inverse_methods_spec.rb +++ b/spec/rubocop/cop/style/inverse_methods_spec.rb @@ -44,6 +44,19 @@ RUBY end + context 'Ruby 2.7', :ruby27 do + it 'registers an offense for calling !.none? with a numblock' do + expect_offense(<<~RUBY) + !foo.none? { _1.even? } + ^^^^^^^^^^^^^^^^^^^^^^^ Use `any?` instead of inverting `none?`. + RUBY + + expect_correction(<<~RUBY) + foo.any? { _1.even? } + RUBY + end + end + it 'registers an offense for calling !.any? inside parens' do expect_offense(<<~RUBY) !(foo.any? &:working?) From ba939753047bca1ff98552d122656af5eae5a524 Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:41:17 +0300 Subject: [PATCH 44/47] Fix Style/CollectionMethods with numblocks --- lib/rubocop/cop/style/collection_methods.rb | 2 ++ spec/rubocop/cop/style/collection_methods_spec.rb | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/rubocop/cop/style/collection_methods.rb b/lib/rubocop/cop/style/collection_methods.rb index 2ab49a0804a..8d69a13d898 100644 --- a/lib/rubocop/cop/style/collection_methods.rb +++ b/lib/rubocop/cop/style/collection_methods.rb @@ -48,6 +48,8 @@ def on_block(node) check_method_node(node.send_node) end + alias on_numblock on_block + def on_send(node) return unless implicit_block?(node) diff --git a/spec/rubocop/cop/style/collection_methods_spec.rb b/spec/rubocop/cop/style/collection_methods_spec.rb index e6e97a6e202..87d158a2864 100644 --- a/spec/rubocop/cop/style/collection_methods_spec.rb +++ b/spec/rubocop/cop/style/collection_methods_spec.rb @@ -25,6 +25,19 @@ RUBY end + context 'Ruby 2.7', :ruby27 do + it "registers an offense for #{method} with numblock" do + expect_offense(<<~RUBY, method: method) + [1, 2, 3].%{method} { _1 + 1 } + ^{method} Prefer `#{preferred_method}` over `#{method}`. + RUBY + + expect_correction(<<~RUBY) + [1, 2, 3].#{preferred_method} { _1 + 1 } + RUBY + end + end + it "registers an offense for #{method} with proc param" do expect_offense(<<~RUBY, method: method) [1, 2, 3].%{method}(&:test) From 78532ed583edc5c27e5710942f6e8b0d3b7afffa Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:44:54 +0300 Subject: [PATCH 45/47] Fix Style/EachWithObject with numblocks The autocorrection does not remove the return value in `each_with_object`, but the numbered arguments are swapped. Not the best autocorrection, but it is still correct as `each_with_object` ignores the return value of its block. --- lib/rubocop/cop/style/each_with_object.rb | 47 +++++++++++++++---- .../cop/style/each_with_object_spec.rb | 19 ++++++++ 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/lib/rubocop/cop/style/each_with_object.rb b/lib/rubocop/cop/style/each_with_object.rb index 77e0abd79cd..3149231909c 100644 --- a/lib/rubocop/cop/style/each_with_object.rb +++ b/lib/rubocop/cop/style/each_with_object.rb @@ -23,13 +23,8 @@ class EachWithObject < Base MSG = 'Use `each_with_object` instead of `%s`.' METHODS = %i[inject reduce].freeze - # @!method each_with_object_candidate?(node) - def_node_matcher :each_with_object_candidate?, <<~PATTERN - (block $(send _ {:inject :reduce} _) $_ $_) - PATTERN - def on_block(node) - each_with_object_candidate?(node) do |method, args, body| + each_with_object_block_candidate?(node) do |method, args, body| _, method_name, method_arg = *method return if simple_method_arg?(method_arg) @@ -40,14 +35,38 @@ def on_block(node) message = format(MSG, method: method_name) add_offense(method.loc.selector, message: message) do |corrector| - autocorrect(corrector, node, return_value) + autocorrect_block(corrector, node, return_value) + end + end + end + + def on_numblock(node) + each_with_object_numblock_candidate?(node) do |method, body| + _, method_name, method_arg = *method + return if simple_method_arg?(method_arg) + + return unless return_value(body)&.source == '_1' + + message = format(MSG, method: method_name) + add_offense(method.loc.selector, message: message) do |corrector| + autocorrect_numblock(corrector, node) end end end private - def autocorrect(corrector, node, return_value) + # @!method each_with_object_block_candidate?(node) + def_node_matcher :each_with_object_block_candidate?, <<~PATTERN + (block $(send _ {:inject :reduce} _) $_ $_) + PATTERN + + # @!method each_with_object_numblock_candidate?(node) + def_node_matcher :each_with_object_numblock_candidate?, <<~PATTERN + (numblock $(send _ {:inject :reduce} _) 2 $_) + PATTERN + + def autocorrect_block(corrector, node, return_value) corrector.replace(node.send_node.loc.selector, 'each_with_object') first_arg, second_arg = *node.arguments @@ -62,6 +81,18 @@ def autocorrect(corrector, node, return_value) end end + def autocorrect_numblock(corrector, node) + corrector.replace(node.send_node.loc.selector, 'each_with_object') + + # We don't remove the return value to avoid a clobbering error. + node.body.each_descendant do |var| + next unless var.lvar_type? + + corrector.replace(var, '_2') if var.source == '_1' + corrector.replace(var, '_1') if var.source == '_2' + end + end + def simple_method_arg?(method_arg) method_arg&.basic_literal? end diff --git a/spec/rubocop/cop/style/each_with_object_spec.rb b/spec/rubocop/cop/style/each_with_object_spec.rb index c312b74c846..07ef3ed8e8f 100644 --- a/spec/rubocop/cop/style/each_with_object_spec.rb +++ b/spec/rubocop/cop/style/each_with_object_spec.rb @@ -24,6 +24,25 @@ RUBY end + context 'Ruby 2.7', :ruby27 do + it 'finds inject and reduce with passed in and returned hash and numblock' do + expect_offense(<<~RUBY) + [].reduce({}) do + ^^^^^^ Use `each_with_object` instead of `reduce`. + _1[_2] = 1 + _1 + end + RUBY + + expect_correction(<<~RUBY) + [].each_with_object({}) do + _2[_1] = 1 + _2 + end + RUBY + end + end + it 'correctly autocorrects' do expect_offense(<<~RUBY) [1, 2, 3].inject({}) do |h, i| From abb950d0d474f52d1c65d19365e5b8b7fd2796ad Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:45:49 +0300 Subject: [PATCH 46/47] Fix Style/HashEachMethods with numblock --- lib/rubocop/cop/style/hash_each_methods.rb | 4 +++- spec/rubocop/cop/style/hash_each_methods_spec.rb | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/style/hash_each_methods.rb b/lib/rubocop/cop/style/hash_each_methods.rb index c37e4941d67..61d90657c89 100644 --- a/lib/rubocop/cop/style/hash_each_methods.rb +++ b/lib/rubocop/cop/style/hash_each_methods.rb @@ -35,13 +35,15 @@ class HashEachMethods < Base # @!method kv_each(node) def_node_matcher :kv_each, <<~PATTERN - (block $(send (send _ ${:keys :values}) :each) ...) + ({block numblock} $(send (send _ ${:keys :values}) :each) ...) PATTERN def on_block(node) register_kv_offense(node) end + alias on_numblock on_block + private def register_kv_offense(node) diff --git a/spec/rubocop/cop/style/hash_each_methods_spec.rb b/spec/rubocop/cop/style/hash_each_methods_spec.rb index d34423c7ff1..5dd05782671 100644 --- a/spec/rubocop/cop/style/hash_each_methods_spec.rb +++ b/spec/rubocop/cop/style/hash_each_methods_spec.rb @@ -32,6 +32,19 @@ it 'does not register an offense for Hash#each_value' do expect_no_offenses('foo.each_value { |v| p v }') end + + context 'Ruby 2.7' do + it 'registers offense, autocorrects foo#keys.each to foo#each_key with numblock' do + expect_offense(<<~RUBY) + foo.keys.each { p _1 } + ^^^^^^^^^ Use `each_key` instead of `keys.each`. + RUBY + + expect_correction(<<~RUBY) + foo.each_key { p _1 } + RUBY + end + end end context 'when receiver is a hash literal' do From e63c32fcbdb6f435bb7f6f7d1f0811202abeeeee Mon Sep 17 00:00:00 2001 From: Genadi Samokovarov Date: Fri, 12 Aug 2022 14:49:38 +0300 Subject: [PATCH 47/47] Single changelog entry for the block cops without numblock fixes --- changelog/fix_block_cops_without_numblock_support.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/fix_block_cops_without_numblock_support.md diff --git a/changelog/fix_block_cops_without_numblock_support.md b/changelog/fix_block_cops_without_numblock_support.md new file mode 100644 index 00000000000..d6b05c931e2 --- /dev/null +++ b/changelog/fix_block_cops_without_numblock_support.md @@ -0,0 +1 @@ +* [#10915](https://github.com/rubocop/rubocop/pull/10915): Fix numblock support to `Layout/BlockAlignment`, `Layout/BlockEndNewline`, `Layout/EmptyLinesAroundAccessModifier`, `Layout/EmptyLinesAroundBlockBody`, `Layout/IndentationWidth`, `Layout/LineLength`, `Layout/MultilineBlockLayout`, `Layout/SpaceBeforeBlockBraces`, `Lint/NextWithoutAccumulator`, `Lint/NonDeterministicRequireOrder`, `Lint/RedundantWithIndex`, `Lint/RedundantWithObject`, `Lint/UnreachableLoop`, `Lint/UselessAccessModifier`, `Lint/Void`, `Metrics/AbcSize`, `Metrics/CyclomaticComplexity`, `Style/CollectionMethods`, `Style/CombinableLoops`, `Style/EachWithObject`, `Style/For`, `Style/HashEachMethods`, `Style/InverseMethods`, `Style/MethodCalledOnDoEndBlock`, `Style/MultilineBlockChain`, `Style/Next`, `Style/ObjectThen`, `Style/Proc`, `Style/RedundantBegin`, `Style/RedundantSelf`, `Style/RedundantSortBy` and `Style/TopLevelMethodDefinition`. ([@gsamokovarov][])