Skip to content

Commit

Permalink
Merge pull request #1362 from ydah/fix/InternalAffairs/NumblockHandler
Browse files Browse the repository at this point in the history
Fix `InternalAffairs/NumblockHandler` offenses
  • Loading branch information
bquorning committed Aug 25, 2022
2 parents 740ce57 + 1f36197 commit 425bc13
Show file tree
Hide file tree
Showing 56 changed files with 490 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -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)

Expand Down
28 changes: 25 additions & 3 deletions lib/rubocop/cop/rspec/around_block.rb
Expand Up @@ -30,18 +30,23 @@ class AroundBlock < Base
MSG_UNUSED_ARG = 'You should call `%<arg>s.call` ' \
'or `%<arg>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
Expand All @@ -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)
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/capybara/feature_methods.rb
Expand Up @@ -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|
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/context_method.rb
Expand Up @@ -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')
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/context_wording.rb
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/described_class.rb
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/empty_example_group.rb
Expand Up @@ -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) }

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/empty_hook.rb
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/empty_line_after_example.rb
Expand Up @@ -47,7 +47,7 @@ class EmptyLineAfterExample < Base

MSG = 'Add an empty line after `%<example>s`.'

def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless example?(node)
return if allowed_one_liner?(node)

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/empty_line_after_example_group.rb
Expand Up @@ -29,7 +29,7 @@ class EmptyLineAfterExampleGroup < Base

MSG = 'Add an empty line after `%<example_group>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|
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/empty_line_after_final_let.rb
Expand Up @@ -22,7 +22,7 @@ class EmptyLineAfterFinalLet < Base

MSG = 'Add an empty line after the last `%<let>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) }
Expand Down
2 changes: 2 additions & 0 deletions lib/rubocop/cop/rspec/empty_line_after_hook.rb
Expand Up @@ -66,6 +66,8 @@ def on_block(node)
end
end

alias on_numblock on_block

private

def chained_single_line_hooks?(node)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/empty_line_after_subject.rb
Expand Up @@ -21,7 +21,7 @@ class EmptyLineAfterSubject < Base

MSG = 'Add an empty line after `%<subject>s`.'

def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless subject?(node)
return unless inside_example_group?(node)

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/example_length.rb
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/example_without_description.rb
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/example_wording.rb
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/expect_change.rb
Expand Up @@ -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|
Expand Down
4 changes: 3 additions & 1 deletion lib/rubocop/cop/rspec/expect_in_hook.rb
Expand Up @@ -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?

Expand All @@ -36,6 +36,8 @@ def on_block(node)
end
end

alias on_numblock on_block

private

def message(expect, hook)
Expand Down
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/factory_bot/create_list.rb
Expand Up @@ -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)
Expand Down
8 changes: 6 additions & 2 deletions lib/rubocop/cop/rspec/hook_argument.rb
Expand Up @@ -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|
Expand All @@ -86,6 +88,8 @@ def on_block(node)
end
end

alias on_numblock on_block

private

def check_implicit(method_send)
Expand Down
3 changes: 3 additions & 0 deletions lib/rubocop/cop/rspec/hooks_before_examples.rb
Expand Up @@ -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
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/instance_spy.rb
Expand Up @@ -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|
Expand Down
15 changes: 15 additions & 0 deletions lib/rubocop/cop/rspec/iterated_expectation.rb
Expand Up @@ -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 ...)
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/leading_subject.rb
Expand Up @@ -37,7 +37,7 @@ class LeadingSubject < Base

MSG = 'Declare `subject` above any other `%<offending>s` declarations.'

def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless subject?(node)
return unless inside_example_group?(node)

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/let_before_examples.rb
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/let_setup.rb
Expand Up @@ -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|
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/missing_example_group_argument.rb
Expand Up @@ -22,7 +22,7 @@ module RSpec
class MissingExampleGroupArgument < Base
MSG = 'The first argument to `%<method>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?

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/multiple_expectations.rb
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/multiple_memoized_helpers.rb
Expand Up @@ -89,7 +89,7 @@ class MultipleMemoizedHelpers < Base

MSG = 'Example group has too many memoized helpers [%<count>d/%<max>d]'

def on_block(node)
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless spec_group?(node)

count = all_helpers(node).uniq.count
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/multiple_subjects.rb
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/rspec/named_subject.rb
Expand Up @@ -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
Expand Down

0 comments on commit 425bc13

Please sign in to comment.