From 3acd12d2fc28d30fc0803af606c1e3ddd54679aa Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 12:53:28 +0900 Subject: [PATCH 01/45] Add support numblocks for `RSpec/AroundBlock` --- lib/rubocop/cop/rspec/around_block.rb | 28 +++++++++- spec/rubocop/cop/rspec/around_block_spec.rb | 62 +++++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/lib/rubocop/cop/rspec/around_block.rb b/lib/rubocop/cop/rspec/around_block.rb index f2c1e29d5..bcff37129 100644 --- a/lib/rubocop/cop/rspec/around_block.rb +++ b/lib/rubocop/cop/rspec/around_block.rb @@ -30,18 +30,23 @@ class AroundBlock < Base MSG_UNUSED_ARG = 'You should call `%s.call` ' \ 'or `%s.run`.' - # @!method hook(node) - def_node_matcher :hook, <<-PATTERN + # @!method hook_block(node) + def_node_matcher :hook_block, <<-PATTERN (block (send nil? :around sym ?) (args $...) ...) PATTERN + # @!method hook_numblock(node) + def_node_matcher :hook_numblock, <<-PATTERN + (numblock (send nil? :around sym ?) ...) + PATTERN + # @!method find_arg_usage(node) def_node_search :find_arg_usage, <<-PATTERN {(send $... {:call :run}) (send _ _ $...) (yield $...) (block-pass $...)} PATTERN def on_block(node) - hook(node) do |(example_proxy)| + hook_block(node) do |(example_proxy)| if example_proxy.nil? add_no_arg_offense(node) else @@ -50,6 +55,12 @@ def on_block(node) end end + def on_numblock(node) + hook_numblock(node) do + check_for_numblock(node) + end + end + private def add_no_arg_offense(node) @@ -68,6 +79,17 @@ def check_for_unused_proxy(block, proxy) message: format(MSG_UNUSED_ARG, arg: name) ) end + + def check_for_numblock(block) + find_arg_usage(block) do |usage| + return if usage.include?(s(:lvar, :_1)) + end + + add_offense( + block.children.last, + message: format(MSG_UNUSED_ARG, arg: :_1) + ) + end end end end diff --git a/spec/rubocop/cop/rspec/around_block_spec.rb b/spec/rubocop/cop/rspec/around_block_spec.rb index 363e06816..1ee577aa7 100644 --- a/spec/rubocop/cop/rspec/around_block_spec.rb +++ b/spec/rubocop/cop/rspec/around_block_spec.rb @@ -116,4 +116,66 @@ RUBY end end + + context 'when Ruby 2.7', :ruby27 do + context 'when the yielded value is unused' do + it 'registers an offense' do + expect_offense(<<-RUBY) + around { _1 } + ^^ You should call `_1.call` or `_1.run`. + RUBY + end + end + + context 'when a method other than #run or #call is called' do + it 'registers an offense' do + expect_offense(<<-RUBY) + around do + _1.inspect + ^^^^^^^^^^ You should call `_1.call` or `_1.run`. + end + RUBY + end + end + + context 'when #run is called' do + it 'does not register an offense' do + expect_no_offenses(<<-RUBY) + around do + _1.run + end + RUBY + end + end + + context 'when #call is called' do + it 'does not register an offense' do + expect_no_offenses(<<-RUBY) + around do + _1.call + end + RUBY + end + end + + context 'when used as a block arg' do + it 'does not register an offense' do + expect_no_offenses(<<-RUBY) + around do + 1.times(&_1) + end + RUBY + end + end + + context 'when passed to another method' do + it 'does not register an offense' do + expect_no_offenses(<<-RUBY) + around do + something_that_might_run_test(_1, another_arg) + end + RUBY + end + end + end end From e191cd45b3fce3dedc78746a04ddc4aee585cf03 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 12:59:42 +0900 Subject: [PATCH 02/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/Capybara/FeatureMethods` --- lib/rubocop/cop/rspec/capybara/feature_methods.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/capybara/feature_methods.rb b/lib/rubocop/cop/rspec/capybara/feature_methods.rb index 413b5068b..983ab5769 100644 --- a/lib/rubocop/cop/rspec/capybara/feature_methods.rb +++ b/lib/rubocop/cop/rspec/capybara/feature_methods.rb @@ -68,7 +68,7 @@ class FeatureMethods < Base ...) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless inside_example_group?(node) feature_method(node) do |send_node, match| From 53d37690b5e5b1220d4c83356bb2b78979a5e12c Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:01:50 +0900 Subject: [PATCH 03/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/ContextMethod` --- lib/rubocop/cop/rspec/context_method.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/context_method.rb b/lib/rubocop/cop/rspec/context_method.rb index c0f52b568..0e5229466 100644 --- a/lib/rubocop/cop/rspec/context_method.rb +++ b/lib/rubocop/cop/rspec/context_method.rb @@ -33,7 +33,7 @@ class ContextMethod < Base (block (send #rspec? :context $(str #method_name?) ...) ...) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler context_method(node) do |context| add_offense(context) do |corrector| corrector.replace(node.send_node.loc.selector, 'describe') From beb3d6c4cc2c138d43621d25688eab8b49c53107 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:02:42 +0900 Subject: [PATCH 04/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/ContextWording` --- lib/rubocop/cop/rspec/context_wording.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/context_wording.rb b/lib/rubocop/cop/rspec/context_wording.rb index 623468c95..162ff97e2 100644 --- a/lib/rubocop/cop/rspec/context_wording.rb +++ b/lib/rubocop/cop/rspec/context_wording.rb @@ -43,7 +43,7 @@ class ContextWording < Base (block (send #rspec? { :context :shared_context } $(str #bad_prefix?) ...) ...) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler context_wording(node) do |context| add_offense(context, message: format(MSG, prefixes: joined_prefixes)) From 23fd9146166b51756866c7a311a274da72bb7efb Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:03:58 +0900 Subject: [PATCH 05/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/DescribedClass` --- lib/rubocop/cop/rspec/described_class.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/described_class.rb b/lib/rubocop/cop/rspec/described_class.rb index 7daa3f57b..06a337691 100644 --- a/lib/rubocop/cop/rspec/described_class.rb +++ b/lib/rubocop/cop/rspec/described_class.rb @@ -82,7 +82,7 @@ class DescribedClass < Base def_node_search :contains_described_class?, '(send nil? :described_class)' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler # In case the explicit style is used, we need to remember what's # being described. @described_class, body = described_constant(node) From a4a6106f0a117395cc573fc74ec7a7018c06c6e8 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:05:28 +0900 Subject: [PATCH 06/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/EmptyExampleGroup` --- lib/rubocop/cop/rspec/empty_example_group.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/empty_example_group.rb b/lib/rubocop/cop/rspec/empty_example_group.rb index ffee3fe79..1e0a85ad8 100644 --- a/lib/rubocop/cop/rspec/empty_example_group.rb +++ b/lib/rubocop/cop/rspec/empty_example_group.rb @@ -134,7 +134,7 @@ class EmptyExampleGroup < Base } PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return if node.each_ancestor(:def, :defs).any? return if node.each_ancestor(:block).any? { |block| example?(block) } From fdb7b0872b6901a31d7e62fc81d76642368f3c84 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:11:42 +0900 Subject: [PATCH 07/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/EmptyHook` --- lib/rubocop/cop/rspec/empty_hook.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/empty_hook.rb b/lib/rubocop/cop/rspec/empty_hook.rb index 820c1c532..05dd527ce 100644 --- a/lib/rubocop/cop/rspec/empty_hook.rb +++ b/lib/rubocop/cop/rspec/empty_hook.rb @@ -33,7 +33,7 @@ class EmptyHook < Base (block $#{send_pattern('#Hooks.all')} _ nil?) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler empty_hook?(node) do |hook| add_offense(hook) do |corrector| corrector.remove( From c7b54fb2e485467f2d74c386722dd8ec25e48eda Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:13:25 +0900 Subject: [PATCH 08/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/EmptyLineAfterExample` --- lib/rubocop/cop/rspec/empty_line_after_example.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/empty_line_after_example.rb b/lib/rubocop/cop/rspec/empty_line_after_example.rb index 75ee17f7c..415366211 100644 --- a/lib/rubocop/cop/rspec/empty_line_after_example.rb +++ b/lib/rubocop/cop/rspec/empty_line_after_example.rb @@ -47,7 +47,7 @@ class EmptyLineAfterExample < Base MSG = 'Add an empty line after `%s`.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example?(node) return if allowed_one_liner?(node) From 1635f06948268a68b80f0711c01f81390c9d0056 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:14:20 +0900 Subject: [PATCH 09/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/EmptyLineAfterExampleGroup` --- lib/rubocop/cop/rspec/empty_line_after_example_group.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/empty_line_after_example_group.rb b/lib/rubocop/cop/rspec/empty_line_after_example_group.rb index e0f89f885..d43573d47 100644 --- a/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +++ b/lib/rubocop/cop/rspec/empty_line_after_example_group.rb @@ -29,7 +29,7 @@ class EmptyLineAfterExampleGroup < Base MSG = 'Add an empty line after `%s`.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group?(node) missing_separating_line_offense(node) do |method| From 1f09eb609cc9946674c3cd2c8bd20fef9dc5676e Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:15:00 +0900 Subject: [PATCH 10/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/EmptyLineAfterFinalLet` --- lib/rubocop/cop/rspec/empty_line_after_final_let.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/empty_line_after_final_let.rb b/lib/rubocop/cop/rspec/empty_line_after_final_let.rb index 1f91190ed..33d7918d8 100644 --- a/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +++ b/lib/rubocop/cop/rspec/empty_line_after_final_let.rb @@ -22,7 +22,7 @@ class EmptyLineAfterFinalLet < Base MSG = 'Add an empty line after the last `%s`.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group_with_body?(node) final_let = node.body.child_nodes.reverse.find { |child| let?(child) } From 3145c96852f97cf083698ac74eed3ebc5a0137cd Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:15:17 +0900 Subject: [PATCH 11/45] Add support numblocks for `RSpec/EmptyLineAfterHook` --- .../cop/rspec/empty_line_after_hook.rb | 2 ++ lib/rubocop/rspec/language.rb | 7 +++- .../cop/rspec/empty_line_after_hook_spec.rb | 32 +++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/empty_line_after_hook.rb b/lib/rubocop/cop/rspec/empty_line_after_hook.rb index b1716342f..499dd710b 100644 --- a/lib/rubocop/cop/rspec/empty_line_after_hook.rb +++ b/lib/rubocop/cop/rspec/empty_line_after_hook.rb @@ -66,6 +66,8 @@ def on_block(node) end end + alias on_numblock on_block + private def chained_single_line_hooks?(node) diff --git a/lib/rubocop/rspec/language.rb b/lib/rubocop/rspec/language.rb index da2c19b25..8e9461ac8 100644 --- a/lib/rubocop/rspec/language.rb +++ b/lib/rubocop/rspec/language.rb @@ -41,7 +41,12 @@ class << self def_node_matcher :example?, block_pattern('#Examples.all') # @!method hook?(node) - def_node_matcher :hook?, block_pattern('#Hooks.all') + def_node_matcher :hook?, <<-PATTERN + { + #{block_pattern('#Hooks.all')} + #{numblock_pattern('#Hooks.all')} + } + PATTERN # @!method let?(node) def_node_matcher :let?, <<-PATTERN diff --git a/spec/rubocop/cop/rspec/empty_line_after_hook_spec.rb b/spec/rubocop/cop/rspec/empty_line_after_hook_spec.rb index 5aaa64c64..fd4ac99e7 100644 --- a/spec/rubocop/cop/rspec/empty_line_after_hook_spec.rb +++ b/spec/rubocop/cop/rspec/empty_line_after_hook_spec.rb @@ -451,5 +451,37 @@ end RUBY end + + context 'when Ruby 2.7', :ruby27 do + it 'registers an offense for empty line after `around` hook' do + expect_offense(<<-RUBY) + RSpec.describe User do + around { _1.run } + ^^^^^^^^^^^^^^^^^ Add an empty line after `around`. + it { does_something } + end + RUBY + + expect_correction(<<-RUBY) + RSpec.describe User do + around { _1.run } + + it { does_something } + end + RUBY + end + + it 'does not register an offense for multiline `around` block' do + expect_no_offenses(<<-RUBY) + RSpec.describe User do + around do + _1.run + end + + it { does_something } + end + RUBY + end + end end end From 43a2a1606d81dfaf84c0f6f4843b461d5efb9311 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:16:14 +0900 Subject: [PATCH 12/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/EmptyLineAfterSubject` --- lib/rubocop/cop/rspec/empty_line_after_subject.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/empty_line_after_subject.rb b/lib/rubocop/cop/rspec/empty_line_after_subject.rb index 47d515d84..8532bacc2 100644 --- a/lib/rubocop/cop/rspec/empty_line_after_subject.rb +++ b/lib/rubocop/cop/rspec/empty_line_after_subject.rb @@ -21,7 +21,7 @@ class EmptyLineAfterSubject < Base MSG = 'Add an empty line after `%s`.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless subject?(node) return unless inside_example_group?(node) From defe35b7db01865fbc911218de772e20831a6eb9 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:18:21 +0900 Subject: [PATCH 13/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/ExampleLength` --- lib/rubocop/cop/rspec/example_length.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/example_length.rb b/lib/rubocop/cop/rspec/example_length.rb index 9f5625046..020e873ce 100644 --- a/lib/rubocop/cop/rspec/example_length.rb +++ b/lib/rubocop/cop/rspec/example_length.rb @@ -52,7 +52,7 @@ class ExampleLength < Base LABEL = 'Example' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example?(node) check_code_length(node) From e266bd9acb88a549148ceb75af13568c91eb17d1 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:18:54 +0900 Subject: [PATCH 14/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/ExampleWithoutDescription` --- lib/rubocop/cop/rspec/example_without_description.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/example_without_description.rb b/lib/rubocop/cop/rspec/example_without_description.rb index 3ada55b5b..46879cc9b 100644 --- a/lib/rubocop/cop/rspec/example_without_description.rb +++ b/lib/rubocop/cop/rspec/example_without_description.rb @@ -57,7 +57,7 @@ class ExampleWithoutDescription < Base # @!method example_description(node) def_node_matcher :example_description, '(send nil? _ $(str $_))' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example?(node) check_example_without_description(node.send_node) From 8a1b769e66a50e7042d60a65097ee9e80ada9024 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:19:14 +0900 Subject: [PATCH 15/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/ExampleWording` --- lib/rubocop/cop/rspec/example_wording.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/example_wording.rb b/lib/rubocop/cop/rspec/example_wording.rb index 19d460164..60ee39003 100644 --- a/lib/rubocop/cop/rspec/example_wording.rb +++ b/lib/rubocop/cop/rspec/example_wording.rb @@ -46,7 +46,7 @@ class ExampleWording < Base } ...) ...) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler it_description(node) do |description_node, message| if message.match?(SHOULD_PREFIX) add_wording_offense(description_node, MSG_SHOULD) From e06ece44b5e04b8feb19c6feb770fcaa9e8add00 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:19:55 +0900 Subject: [PATCH 16/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/ExpectChange` --- lib/rubocop/cop/rspec/expect_change.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/expect_change.rb b/lib/rubocop/cop/rspec/expect_change.rb index 8864ca348..e723e033a 100644 --- a/lib/rubocop/cop/rspec/expect_change.rb +++ b/lib/rubocop/cop/rspec/expect_change.rb @@ -69,7 +69,7 @@ def on_send(node) end end - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless style == :method_call expect_change_with_block(node) do |receiver, message| From be5b98b5a15e04edae29303a054b2e39eef0d724 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:20:34 +0900 Subject: [PATCH 17/45] Add support numblocks for `RSpec/ExpectInHook` --- lib/rubocop/cop/rspec/expect_in_hook.rb | 4 +++- lib/rubocop/rspec/language/node_pattern.rb | 4 ++++ spec/rubocop/cop/rspec/expect_in_hook_spec.rb | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/expect_in_hook.rb b/lib/rubocop/cop/rspec/expect_in_hook.rb index c111f150b..78411aa25 100644 --- a/lib/rubocop/cop/rspec/expect_in_hook.rb +++ b/lib/rubocop/cop/rspec/expect_in_hook.rb @@ -26,7 +26,7 @@ class ExpectInHook < Base # @!method expectation(node) def_node_search :expectation, send_pattern('#Expectations.all') - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless hook?(node) return if node.body.nil? @@ -36,6 +36,8 @@ def on_block(node) end end + alias on_numblock on_block + private def message(expect, hook) diff --git a/lib/rubocop/rspec/language/node_pattern.rb b/lib/rubocop/rspec/language/node_pattern.rb index 486516206..5405411a2 100644 --- a/lib/rubocop/rspec/language/node_pattern.rb +++ b/lib/rubocop/rspec/language/node_pattern.rb @@ -12,6 +12,10 @@ def send_pattern(string) def block_pattern(string) "(block #{send_pattern(string)} ...)" end + + def numblock_pattern(string) + "(numblock #{send_pattern(string)} ...)" + end end end end diff --git a/spec/rubocop/cop/rspec/expect_in_hook_spec.rb b/spec/rubocop/cop/rspec/expect_in_hook_spec.rb index 533bb020e..596358ac2 100644 --- a/spec/rubocop/cop/rspec/expect_in_hook_spec.rb +++ b/spec/rubocop/cop/rspec/expect_in_hook_spec.rb @@ -74,4 +74,20 @@ end RUBY end + + context 'when Ruby 2.7', :ruby27 do + it 'adds an offense for `expect` in `around` hook' do + expect_offense(<<-RUBY) + around do + expect(something).to eq('foo') + ^^^^^^ Do not use `expect` in `around` hook + is_expected(something).to eq('foo') + ^^^^^^^^^^^ Do not use `is_expected` in `around` hook + expect_any_instance_of(Something).to receive(:foo) + ^^^^^^^^^^^^^^^^^^^^^^ Do not use `expect_any_instance_of` in `around` hook + _1.run + end + RUBY + end + end end From b9c3e0e70fcaf4e3edbf84d50ad4b6bab6c11964 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:31:04 +0900 Subject: [PATCH 18/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/FactoryBot/AttributeDefinedStatically` --- .../cop/rspec/factory_bot/attribute_defined_statically.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb b/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb index a4b6dbe17..9b55c33d5 100644 --- a/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +++ b/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb @@ -39,7 +39,7 @@ class AttributeDefinedStatically < Base (block (send _ #attribute_defining_method? ...) _ { (begin $...) $(send ...) } ) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler attributes = factory_attributes(node) || [] attributes = [attributes] unless attributes.is_a?(Array) # rubocop:disable Style/ArrayCoercion, Lint/RedundantCopDisableDirective From ceed99020d3609f4ec2f98841dd8cb9a46648764 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:36:27 +0900 Subject: [PATCH 19/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/FactoryBot/CreateList` https://github.com/rubocop/rubocop-rspec/pull/1362#discussion_r946688547 --- lib/rubocop/cop/rspec/factory_bot/create_list.rb | 2 +- spec/rubocop/cop/rspec/factory_bot/create_list_spec.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/factory_bot/create_list.rb b/lib/rubocop/cop/rspec/factory_bot/create_list.rb index 12db0979e..fdef08df9 100644 --- a/lib/rubocop/cop/rspec/factory_bot/create_list.rb +++ b/lib/rubocop/cop/rspec/factory_bot/create_list.rb @@ -71,7 +71,7 @@ class CreateList < Base (send {nil? #factory_bot?} :create_list (sym _) (int $_) ...) PATTERN - def on_block(node) + def on_block(node) # rubocop:todo InternalAffairs/NumblockHandler return unless style == :create_list return unless n_times_block?(node) diff --git a/spec/rubocop/cop/rspec/factory_bot/create_list_spec.rb b/spec/rubocop/cop/rspec/factory_bot/create_list_spec.rb index bd5490b02..5d3a2cf3f 100644 --- a/spec/rubocop/cop/rspec/factory_bot/create_list_spec.rb +++ b/spec/rubocop/cop/rspec/factory_bot/create_list_spec.rb @@ -230,5 +230,13 @@ SomeFactory.create_list :user, 3 RUBY end + + context 'when Ruby 2.7', :ruby27 do + it 'ignores n.times with numblock' do + expect_no_offenses(<<~RUBY) + 3.times { create :user, position: _1 } + RUBY + end + end end end From 42fa1927504c745f454f607ebe1a8b357b0670ae Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:37:55 +0900 Subject: [PATCH 20/45] Add support numblocks for `RSpec/HookArgument` --- lib/rubocop/cop/rspec/hook_argument.rb | 8 +- spec/rubocop/cop/rspec/hook_argument_spec.rb | 90 ++++++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/lib/rubocop/cop/rspec/hook_argument.rb b/lib/rubocop/cop/rspec/hook_argument.rb index 5fa9c8f41..1ef41035d 100644 --- a/lib/rubocop/cop/rspec/hook_argument.rb +++ b/lib/rubocop/cop/rspec/hook_argument.rb @@ -66,11 +66,13 @@ class HookArgument < Base # @!method scoped_hook(node) def_node_matcher :scoped_hook, <<-PATTERN - (block $(send _ #Hooks.all (sym ${:each :example})) ...) + ({block numblock} $(send _ #Hooks.all (sym ${:each :example})) ...) PATTERN # @!method unscoped_hook(node) - def_node_matcher :unscoped_hook, '(block $(send _ #Hooks.all) ...)' + def_node_matcher :unscoped_hook, <<-PATTERN + ({block numblock} $(send _ #Hooks.all) ...) + PATTERN def on_block(node) hook(node) do |method_send, scope_name| @@ -86,6 +88,8 @@ def on_block(node) end end + alias on_numblock on_block + private def check_implicit(method_send) diff --git a/spec/rubocop/cop/rspec/hook_argument_spec.rb b/spec/rubocop/cop/rspec/hook_argument_spec.rb index ae1b26d3a..c7f15cf40 100644 --- a/spec/rubocop/cop/rspec/hook_argument_spec.rb +++ b/spec/rubocop/cop/rspec/hook_argument_spec.rb @@ -88,6 +88,36 @@ end include_examples 'an example hook' + + context 'when Ruby 2.7', :ruby27 do + it 'detects :each for hooks' do + expect_offense(<<-RUBY) + around(:each) { _1 } + ^^^^^^^^^^^^^ Omit the default `:each` argument for RSpec hooks. + RUBY + + expect_correction(<<-RUBY) + around { _1 } + RUBY + end + + it 'detects :example for hooks' do + expect_offense(<<-RUBY) + around(:example) { _1 } + ^^^^^^^^^^^^^^^^ Omit the default `:example` argument for RSpec hooks. + RUBY + + expect_correction(<<-RUBY) + around { _1 } + RUBY + end + + it 'does not flag hooks without default scopes' do + expect_no_offenses(<<-RUBY) + around { _1 } + RUBY + end + end end context 'when EnforcedStyle is :each' do @@ -143,6 +173,36 @@ end include_examples 'an example hook' + + context 'when Ruby 2.7', :ruby27 do + it 'does not flag :each for hooks' do + expect_no_offenses(<<-RUBY) + around(:each) { _1 } + RUBY + end + + it 'detects :example for hooks' do + expect_offense(<<-RUBY) + around(:example) { _1 } + ^^^^^^^^^^^^^^^^ Use `:each` for RSpec hooks. + RUBY + + expect_correction(<<-RUBY) + around(:each) { _1 } + RUBY + end + + it 'detects hooks without default scopes' do + expect_offense(<<-RUBY) + around { _1 } + ^^^^^^ Use `:each` for RSpec hooks. + RUBY + + expect_correction(<<-RUBY) + around(:each) { _1 } + RUBY + end + end end context 'when EnforcedStyle is :example' do @@ -198,5 +258,35 @@ end include_examples 'an example hook' + + context 'when Ruby 2.7', :ruby27 do + it 'does not flag :example for hooks' do + expect_no_offenses(<<-RUBY) + around(:example) { _1 } + RUBY + end + + it 'detects :each for hooks' do + expect_offense(<<-RUBY) + around(:each) { _1 } + ^^^^^^^^^^^^^ Use `:example` for RSpec hooks. + RUBY + + expect_correction(<<-RUBY) + around(:example) { _1 } + RUBY + end + + it 'detects hooks without default scopes' do + expect_offense(<<-RUBY) + around { _1 } + ^^^^^^ Use `:example` for RSpec hooks. + RUBY + + expect_correction(<<-RUBY) + around(:example) { _1 } + RUBY + end + end end end From b3aedf403be823407fb0fa3d658f801a6a35fb35 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:39:17 +0900 Subject: [PATCH 21/45] Add support numblocks for `RSpec/HooksBeforeExamples` --- .../cop/rspec/hooks_before_examples.rb | 3 + .../cop/rspec/hooks_before_examples_spec.rb | 61 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/lib/rubocop/cop/rspec/hooks_before_examples.rb b/lib/rubocop/cop/rspec/hooks_before_examples.rb index b58534291..af11f4c0b 100644 --- a/lib/rubocop/cop/rspec/hooks_before_examples.rb +++ b/lib/rubocop/cop/rspec/hooks_before_examples.rb @@ -32,6 +32,7 @@ class HooksBeforeExamples < Base def_node_matcher :example_or_group?, <<-PATTERN { #{block_pattern('{#ExampleGroups.all #Examples.all}')} + #{numblock_pattern('{#ExampleGroups.all #Examples.all}')} #{send_pattern('#Includes.examples')} } PATTERN @@ -42,6 +43,8 @@ def on_block(node) check_hooks(node.body) if multiline_block?(node.body) end + alias on_numblock on_block + private def multiline_block?(block) diff --git a/spec/rubocop/cop/rspec/hooks_before_examples_spec.rb b/spec/rubocop/cop/rspec/hooks_before_examples_spec.rb index 79dcfe057..01f3637c0 100644 --- a/spec/rubocop/cop/rspec/hooks_before_examples_spec.rb +++ b/spec/rubocop/cop/rspec/hooks_before_examples_spec.rb @@ -166,4 +166,65 @@ end RUBY end + + context 'when Ruby 2.7', :ruby27 do + it 'flags `around` after `it`' do + expect_offense(<<-RUBY) + RSpec.describe User do + it { is_expected.to be_after_around_hook } + around { _1 } + ^^^^^^^^^^^^^ Move `around` above the examples in the group. + end + RUBY + + expect_correction(<<-RUBY) + RSpec.describe User do + around { _1 } + it { is_expected.to be_after_around_hook } + end + RUBY + end + + it 'flags `around` after `context`' do + expect_offense(<<-RUBY) + RSpec.describe User do + context 'a context' do + it { is_expected.to be_after_around_hook } + end + + around { _1 } + ^^^^^^^^^^^^^ Move `around` above the examples in the group. + end + RUBY + + expect_correction(<<-RUBY) + RSpec.describe User do + around { _1 } + context 'a context' do + it { is_expected.to be_after_around_hook } + end + + end + RUBY + end + + it 'flags `around` after `include_examples`' do + expect_offense(<<-RUBY) + RSpec.describe User do + include_examples('should be after around-hook') + + around { _1 } + ^^^^^^^^^^^^^ Move `around` above the examples in the group. + end + RUBY + + expect_correction(<<-RUBY) + RSpec.describe User do + around { _1 } + include_examples('should be after around-hook') + + end + RUBY + end + end end From 5460abc40c80620163c1249dd740e6aed01f2472 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:40:07 +0900 Subject: [PATCH 22/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/InstanceSpy` --- lib/rubocop/cop/rspec/instance_spy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/instance_spy.rb b/lib/rubocop/cop/rspec/instance_spy.rb index 5b186ecff..bcb37c460 100644 --- a/lib/rubocop/cop/rspec/instance_spy.rb +++ b/lib/rubocop/cop/rspec/instance_spy.rb @@ -42,7 +42,7 @@ class InstanceSpy < Base ...) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example?(node) null_double(node) do |var, receiver| From ed6f01321f85883d3505a9a6156446b8989fcb02 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:40:32 +0900 Subject: [PATCH 23/45] Add support numblocks for `RSpec/IteratedExpectation` --- lib/rubocop/cop/rspec/iterated_expectation.rb | 15 ++++ .../cop/rspec/iterated_expectation_spec.rb | 79 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/lib/rubocop/cop/rspec/iterated_expectation.rb b/lib/rubocop/cop/rspec/iterated_expectation.rb index 58bef7acd..7e02b054f 100644 --- a/lib/rubocop/cop/rspec/iterated_expectation.rb +++ b/lib/rubocop/cop/rspec/iterated_expectation.rb @@ -28,6 +28,13 @@ class IteratedExpectation < Base ) PATTERN + # @!method each_numblock?(node) + def_node_matcher :each_numblock?, <<-PATTERN + (numblock + (send ... :each) _ $(...) + ) + PATTERN + # @!method expectation?(node) def_node_matcher :expectation?, <<-PATTERN (send (send nil? :expect (lvar %)) :to ...) @@ -41,6 +48,14 @@ def on_block(node) end end + def on_numblock(node) + each_numblock?(node) do |body| + if single_expectation?(body, :_1) || only_expectations?(body, :_1) + add_offense(node.send_node) + end + end + end + private def single_expectation?(body, arg) diff --git a/spec/rubocop/cop/rspec/iterated_expectation_spec.rb b/spec/rubocop/cop/rspec/iterated_expectation_spec.rb index 74aecf0c1..b6ecda7e5 100644 --- a/spec/rubocop/cop/rspec/iterated_expectation_spec.rb +++ b/spec/rubocop/cop/rspec/iterated_expectation_spec.rb @@ -85,4 +85,83 @@ end RUBY end + + context 'when Ruby 2.7', :ruby27 do + it 'flags `each` with an expectation' do + expect_offense(<<-RUBY) + it 'validates users' do + [user1, user2, user3].each { expect(_1).to be_valid } + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using the `all` matcher instead of iterating over an array. + end + RUBY + end + + it 'flags `each` when expectation calls method with arguments' do + expect_offense(<<-RUBY) + it 'validates users' do + [user1, user2, user3].each { expect(_1).to be_a(User) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using the `all` matcher instead of iterating over an array. + end + RUBY + end + + it 'ignores `each` without expectation' do + expect_no_offenses(<<-RUBY) + it 'validates users' do + [user1, user2, user3].each { allow(_1).to receive(:method) } + end + RUBY + end + + it 'flags `each` with multiple expectations' do + expect_offense(<<-RUBY) + it 'validates users' do + [user1, user2, user3].each do + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using the `all` matcher instead of iterating over an array. + expect(_1).to receive(:method) + expect(_1).to receive(:other_method) + end + end + RUBY + end + + it 'ignore `each` when the body does not contain only expectations' do + expect_no_offenses(<<-RUBY) + it 'validates users' do + [user1, user2, user3].each do + allow(Something).to receive(:method).and_return(_1) + expect(_1).to receive(:method) + expect(_1).to receive(:other_method) + end + end + RUBY + end + + it 'ignores `each` with expectation on property' do + expect_no_offenses(<<-RUBY) + it 'validates users' do + [user1, user2, user3].each { expect(_1.name).to be } + end + RUBY + end + + it 'ignores assignments in the iteration' do + expect_no_offenses(<<-RUBY) + it 'validates users' do + [user1, user2, user3].each { array = array.concat(_1) } + end + RUBY + end + + it 'ignores `each` when there is a negative expectation' do + expect_no_offenses(<<-RUBY) + it 'validates users' do + [user1, user2, user3].each do + expect(_1).not_to receive(:method) + expect(_1).to receive(:other_method) + end + end + RUBY + end + end end From 15e4e365421083aea6a9af5b983c331fa05f7c10 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:41:08 +0900 Subject: [PATCH 24/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/LeadingSubject` --- lib/rubocop/cop/rspec/leading_subject.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/leading_subject.rb b/lib/rubocop/cop/rspec/leading_subject.rb index c1ceb2877..94cb18683 100644 --- a/lib/rubocop/cop/rspec/leading_subject.rb +++ b/lib/rubocop/cop/rspec/leading_subject.rb @@ -37,7 +37,7 @@ class LeadingSubject < Base MSG = 'Declare `subject` above any other `%s` declarations.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless subject?(node) return unless inside_example_group?(node) From 402812e9e5e0b8b8b01f85fa2e06582f0010b54b Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:41:56 +0900 Subject: [PATCH 25/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/LetBeforeExamples` --- lib/rubocop/cop/rspec/let_before_examples.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/let_before_examples.rb b/lib/rubocop/cop/rspec/let_before_examples.rb index 0292190c6..310e889dd 100644 --- a/lib/rubocop/cop/rspec/let_before_examples.rb +++ b/lib/rubocop/cop/rspec/let_before_examples.rb @@ -43,7 +43,7 @@ class LetBeforeExamples < Base } PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group_with_body?(node) check_let_declarations(node.body) if multiline_block?(node.body) From 17921e9b00103ab5c69cbeb4b9ceac7d4d772e29 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:42:21 +0900 Subject: [PATCH 26/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/LetSetup` --- lib/rubocop/cop/rspec/let_setup.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/let_setup.rb b/lib/rubocop/cop/rspec/let_setup.rb index 482e4de58..7636920f7 100644 --- a/lib/rubocop/cop/rspec/let_setup.rb +++ b/lib/rubocop/cop/rspec/let_setup.rb @@ -49,7 +49,7 @@ class LetSetup < Base # @!method method_called?(node) def_node_search :method_called?, '(send nil? %)' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_or_shared_group_or_including?(node) unused_let_bang(node) do |let| From 567de64e0d0be63d4692ddbb30fcf5004021d76a Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:42:53 +0900 Subject: [PATCH 27/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/MissingExampleGroupArgument` --- lib/rubocop/cop/rspec/missing_example_group_argument.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/missing_example_group_argument.rb b/lib/rubocop/cop/rspec/missing_example_group_argument.rb index a29df6f59..79e9ebea1 100644 --- a/lib/rubocop/cop/rspec/missing_example_group_argument.rb +++ b/lib/rubocop/cop/rspec/missing_example_group_argument.rb @@ -22,7 +22,7 @@ module RSpec class MissingExampleGroupArgument < Base MSG = 'The first argument to `%s` should not be empty.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group?(node) return if node.send_node.arguments? From f15ea489cf73469e048e26d0416b929f10fccde0 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:43:29 +0900 Subject: [PATCH 28/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/MultipleExpectations` --- lib/rubocop/cop/rspec/multiple_expectations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/multiple_expectations.rb b/lib/rubocop/cop/rspec/multiple_expectations.rb index 33df173fd..1baaf06d5 100644 --- a/lib/rubocop/cop/rspec/multiple_expectations.rb +++ b/lib/rubocop/cop/rspec/multiple_expectations.rb @@ -88,7 +88,7 @@ class MultipleExpectations < Base (block (send nil? :aggregate_failures ...) ...) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example?(node) return if example_with_aggregate_failures?(node) From 60697cfdccbd56d890921f4ab8460a6c51c6896f Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:44:49 +0900 Subject: [PATCH 29/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/MultipleMemoizedHelpers` --- lib/rubocop/cop/rspec/multiple_memoized_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb b/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb index 674b383b9..afa35045c 100644 --- a/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +++ b/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb @@ -89,7 +89,7 @@ class MultipleMemoizedHelpers < Base MSG = 'Example group has too many memoized helpers [%d/%d]' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless spec_group?(node) count = all_helpers(node).uniq.count From 04d4106e8e6c9d77286bcbc3ef91825414a8311b Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:45:11 +0900 Subject: [PATCH 30/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/MultipleSubjects` --- lib/rubocop/cop/rspec/multiple_subjects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/multiple_subjects.rb b/lib/rubocop/cop/rspec/multiple_subjects.rb index f5d30f48d..14781cb9b 100644 --- a/lib/rubocop/cop/rspec/multiple_subjects.rb +++ b/lib/rubocop/cop/rspec/multiple_subjects.rb @@ -55,7 +55,7 @@ class MultipleSubjects < Base MSG = 'Do not set more than one subject per example group' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group?(node) subjects = RuboCop::RSpec::ExampleGroup.new(node).subjects From d29ae2c68d466c08d38cf46f80dda4867ea82e7a Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 13:45:52 +0900 Subject: [PATCH 31/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/NamedSubject` --- lib/rubocop/cop/rspec/named_subject.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/named_subject.rb b/lib/rubocop/cop/rspec/named_subject.rb index 1f1885523..e8583c8cb 100644 --- a/lib/rubocop/cop/rspec/named_subject.rb +++ b/lib/rubocop/cop/rspec/named_subject.rb @@ -55,7 +55,7 @@ class NamedSubject < Base # @!method subject_usage(node) def_node_search :subject_usage, '$(send nil? :subject)' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler if !example_or_hook_block?(node) || ignored_shared_example?(node) return end From 922f80cfdcf15a8a04491531ba13bba071d77fde Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:38:28 +0900 Subject: [PATCH 32/45] Add support numblocks for `RSpec/NoExpectationExample` --- lib/rubocop/cop/rspec/no_expectation_example.rb | 12 ++++++++---- .../cop/rspec/no_expectation_example_spec.rb | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/rubocop/cop/rspec/no_expectation_example.rb b/lib/rubocop/cop/rspec/no_expectation_example.rb index b59a1696c..d57a0c43c 100644 --- a/lib/rubocop/cop/rspec/no_expectation_example.rb +++ b/lib/rubocop/cop/rspec/no_expectation_example.rb @@ -34,10 +34,12 @@ class NoExpectationExample < Base # @!method regular_or_focused_example?(node) # @param [RuboCop::AST::Node] node # @return [Boolean] - def_node_matcher( - :regular_or_focused_example?, - block_pattern('{#Examples.regular | #Examples.focused}') - ) + def_node_matcher :regular_or_focused_example?, <<~PATTERN + { + #{block_pattern('{#Examples.regular | #Examples.focused}')} + #{numblock_pattern('{#Examples.regular | #Examples.focused}')} + } + PATTERN # @!method including_any_expectation?(node) # @param [RuboCop::AST::Node] node @@ -54,6 +56,8 @@ def on_block(node) add_offense(node) end + + alias on_numblock on_block end end end diff --git a/spec/rubocop/cop/rspec/no_expectation_example_spec.rb b/spec/rubocop/cop/rspec/no_expectation_example_spec.rb index b9c73ad25..8eac4c8dd 100644 --- a/spec/rubocop/cop/rspec/no_expectation_example_spec.rb +++ b/spec/rubocop/cop/rspec/no_expectation_example_spec.rb @@ -114,4 +114,19 @@ RUBY end end + + context 'when Ruby 2.7', :ruby27 do + context 'with no expectation example with it' do + it 'registers an offense' do + expect_offense(<<~RUBY) + RSpec.describe Foo do + it { _1 } + ^^^^^^^^^ No expectation found in this example. + + it { expect(baz).to be_truthy } + end + RUBY + end + end + end end From 4819b0f54fca88857e2994a6302cefcab7996c90 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:42:15 +0900 Subject: [PATCH 33/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/OverwritingSetup` --- lib/rubocop/cop/rspec/overwriting_setup.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/overwriting_setup.rb b/lib/rubocop/cop/rspec/overwriting_setup.rb index 133975500..2b946b30b 100644 --- a/lib/rubocop/cop/rspec/overwriting_setup.rb +++ b/lib/rubocop/cop/rspec/overwriting_setup.rb @@ -30,7 +30,7 @@ class OverwritingSetup < Base # @!method first_argument_name(node) def_node_matcher :first_argument_name, '(send _ _ ({str sym} $_))' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group_with_body?(node) find_duplicates(node.body) do |duplicate, name| From ffcc71699c24dc79d35930b476b2c1beae05c4ae Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:42:53 +0900 Subject: [PATCH 34/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/PredicateMatcher` --- lib/rubocop/cop/rspec/predicate_matcher.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/predicate_matcher.rb b/lib/rubocop/cop/rspec/predicate_matcher.rb index f29ce2d3f..f6993af08 100644 --- a/lib/rubocop/cop/rspec/predicate_matcher.rb +++ b/lib/rubocop/cop/rspec/predicate_matcher.rb @@ -291,7 +291,7 @@ def on_send(node) end end - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler check_explicit(node) if style == :explicit end From 0dcc250542babad0a90afc62b072f9420410be05 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:43:34 +0900 Subject: [PATCH 35/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/Rails/AvoidSetupHook` --- lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb b/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb index 00c1abe88..c2b83e8e6 100644 --- a/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +++ b/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb @@ -30,7 +30,7 @@ class AvoidSetupHook < Base (args) _) PATTERN - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler setup_call(node) do |setup| add_offense(node) do |corrector| corrector.replace setup, 'before' From 6dcd9ddbe94351ac2297685e86cbc1e3903bef3f Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:43:58 +0900 Subject: [PATCH 36/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/RepeatedDescription` --- lib/rubocop/cop/rspec/repeated_description.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/repeated_description.rb b/lib/rubocop/cop/rspec/repeated_description.rb index f499bb102..431e534d1 100644 --- a/lib/rubocop/cop/rspec/repeated_description.rb +++ b/lib/rubocop/cop/rspec/repeated_description.rb @@ -43,7 +43,7 @@ module RSpec class RepeatedDescription < Base MSG = "Don't repeat descriptions within an example group." - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group?(node) repeated_descriptions(node).each do |repeated_description| From 2b452fcf314a3b3b23fc7d037991a5ed3e7dd4ae Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:44:35 +0900 Subject: [PATCH 37/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/RepeatedExample` --- lib/rubocop/cop/rspec/repeated_example.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/repeated_example.rb b/lib/rubocop/cop/rspec/repeated_example.rb index 7a7274aad..ce14ba64c 100644 --- a/lib/rubocop/cop/rspec/repeated_example.rb +++ b/lib/rubocop/cop/rspec/repeated_example.rb @@ -18,7 +18,7 @@ module RSpec class RepeatedExample < Base MSG = "Don't repeat examples within an example group." - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group?(node) repeated_examples(node).each do |repeated_example| From ca4fa6b08c9083785e27591cf3c74f4dc7cf5b72 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:45:09 +0900 Subject: [PATCH 38/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/ReturnFromStub` --- lib/rubocop/cop/rspec/return_from_stub.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/return_from_stub.rb b/lib/rubocop/cop/rspec/return_from_stub.rb index 759a0d32f..3c05ef05c 100644 --- a/lib/rubocop/cop/rspec/return_from_stub.rb +++ b/lib/rubocop/cop/rspec/return_from_stub.rb @@ -59,7 +59,7 @@ def on_send(node) check_and_return_call(node) end - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless style == :and_return return unless stub_with_block?(node) From 0fbff1c9ffb11034bd68c93c538a62b92ed78db5 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:49:04 +0900 Subject: [PATCH 39/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/ScatteredLet` --- lib/rubocop/cop/rspec/scattered_let.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/scattered_let.rb b/lib/rubocop/cop/rspec/scattered_let.rb index 87253902d..9b89c6b18 100644 --- a/lib/rubocop/cop/rspec/scattered_let.rb +++ b/lib/rubocop/cop/rspec/scattered_let.rb @@ -31,7 +31,7 @@ class ScatteredLet < Base MSG = 'Group all let/let! blocks in the example group together.' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group_with_body?(node) check_let_declarations(node.body) From c94192adfad390229e28d5ff3760c4b20109ff75 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:49:30 +0900 Subject: [PATCH 40/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/ScatteredSetup` --- lib/rubocop/cop/rspec/scattered_setup.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/scattered_setup.rb b/lib/rubocop/cop/rspec/scattered_setup.rb index 58312857b..aaf117165 100644 --- a/lib/rubocop/cop/rspec/scattered_setup.rb +++ b/lib/rubocop/cop/rspec/scattered_setup.rb @@ -26,7 +26,7 @@ class ScatteredSetup < Base MSG = 'Do not define multiple `%s` hooks in the same ' \ 'example group (also defined on %s).' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless example_group?(node) repeated_hooks(node).each do |occurrences| From 79c8bafac14a96fc8a1891f9b69c0c6b0a098e35 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:50:01 +0900 Subject: [PATCH 41/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/SharedContext` --- lib/rubocop/cop/rspec/shared_context.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/shared_context.rb b/lib/rubocop/cop/rspec/shared_context.rb index 0f93f8d15..d30e83eae 100644 --- a/lib/rubocop/cop/rspec/shared_context.rb +++ b/lib/rubocop/cop/rspec/shared_context.rb @@ -79,7 +79,7 @@ class SharedContext < Base def_node_matcher :shared_example, block_pattern('#SharedGroups.examples') - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler context_with_only_examples(node) do add_offense(node.send_node, message: MSG_EXAMPLES) do |corrector| corrector.replace(node.send_node.loc.selector, 'shared_examples') From 4aaf1b3887d460ab3446a5a00b3d334eb6ece9b3 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:50:41 +0900 Subject: [PATCH 42/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/VoidExpect` --- lib/rubocop/cop/rspec/void_expect.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/void_expect.rb b/lib/rubocop/cop/rspec/void_expect.rb index f63a993b7..d94077f75 100644 --- a/lib/rubocop/cop/rspec/void_expect.rb +++ b/lib/rubocop/cop/rspec/void_expect.rb @@ -32,7 +32,7 @@ def on_send(node) check_expect(node) end - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless expect_block?(node) check_expect(node) From 5d8541172bb1db4304d5377635525977f290219a Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 15:06:22 +0900 Subject: [PATCH 43/45] Disable `InternalAffairs/NumblockHandler` for `RSpec/Yield` --- lib/rubocop/cop/rspec/yield.rb | 2 +- spec/rubocop/cop/rspec/yield_spec.rb | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/yield.rb b/lib/rubocop/cop/rspec/yield.rb index 6a9d2e209..9e00a9525 100644 --- a/lib/rubocop/cop/rspec/yield.rb +++ b/lib/rubocop/cop/rspec/yield.rb @@ -26,7 +26,7 @@ class Yield < Base # @!method block_call?(node) def_node_matcher :block_call?, '(send (lvar %) :call ...)' - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless method_on_stub?(node.send_node) block_arg(node.arguments) do |block| diff --git a/spec/rubocop/cop/rspec/yield_spec.rb b/spec/rubocop/cop/rspec/yield_spec.rb index 8b8d482b7..1c61d9548 100644 --- a/spec/rubocop/cop/rspec/yield_spec.rb +++ b/spec/rubocop/cop/rspec/yield_spec.rb @@ -76,4 +76,21 @@ end RUBY end + + context 'when Ruby 2.7', :ruby27 do + it 'ignores `receive` with no block arguments' do + expect_no_offenses(<<-RUBY) + allow(foo).to receive(:bar) { _1.call } + RUBY + end + + it 'ignores stub when `block.call` is not the only statement' do + expect_no_offenses(<<-RUBY) + allow(foo).to receive(:bar) do + result = _1.call + transform(result) + end + RUBY + end + end end From 05779b66a185d7f79a11de0482d7510bc96800fd Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Tue, 16 Aug 2022 15:07:36 +0900 Subject: [PATCH 44/45] Disable `InternalAffairs/NumblockHandler` for spec/rubocop/cop/rspec/base_spec.rb --- spec/rubocop/cop/rspec/base_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/rubocop/cop/rspec/base_spec.rb b/spec/rubocop/cop/rspec/base_spec.rb index bec4f5d28..fed26061b 100644 --- a/spec/rubocop/cop/rspec/base_spec.rb +++ b/spec/rubocop/cop/rspec/base_spec.rb @@ -81,7 +81,7 @@ def on_send(node) before do stub_const('RuboCop::RSpec::ExampleGroupHaterCop', Class.new(described_class) do - def on_block(node) + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler example_group?(node) do add_offense(node, message: 'I flag example groups') end From 1f36197159ec3669844a3f45b00b6e01b45102d7 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Wed, 17 Aug 2022 22:29:10 +0900 Subject: [PATCH 45/45] Add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd4b22ae9..3d3af2fe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * Fix a false positive for `RSpec/Capybara/SpecificMatcher` when may not have a `href` by `have_link`. ([@ydah][]) * Add `NegatedMatcher` configuration option to `RSpec/ChangeByZero`. ([@ydah][]) * Add new `RSpec/Capybara/SpecificFinders` cop. ([@ydah][]) +* Add support for numblocks to `RSpec/AroundBlock`, `RSpec/EmptyLineAfterHook`, `RSpec/ExpectInHook`, `RSpec/HookArgument`, `RSpec/HooksBeforeExamples`, `RSpec/IteratedExpectation`, and `RSpec/NoExpectationExample`. ([@ydah][]) ## 2.12.1 (2022-07-03)