1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks the arguments passed to `before`, `around`, and `after`.
#
# This cop checks for consistent style when specifying RSpec
# hooks which run for each example. There are three supported
# styles: "implicit", "each", and "example." All styles have
# the same behavior.
#
# @example `EnforcedStyle: implicit` (default)
# # bad
# before(:each) do
# # ...
# end
#
# # bad
# before(:example) do
# # ...
# end
#
# # good
# before do
# # ...
# end
#
# @example `EnforcedStyle: each`
# # bad
# before(:example) do
# # ...
# end
#
# # bad
# before do
# # ...
# end
#
# # good
# before(:each) do
# # ...
# end
#
# @example `EnforcedStyle: example`
# # bad
# before(:each) do
# # ...
# end
#
# # bad
# before do
# # ...
# end
#
# # good
# before(:example) do
# # ...
# end
#
class HookArgument < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
IMPLICIT_MSG = 'Omit the default `%<scope>p` argument for RSpec hooks.'
EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'
# @!method scoped_hook(node)
def_node_matcher :scoped_hook, <<-PATTERN
({block numblock} $(send _ #Hooks.all (sym ${:each :example})) ...)
PATTERN
# @!method unscoped_hook(node)
def_node_matcher :unscoped_hook, <<-PATTERN
({block numblock} $(send _ #Hooks.all) ...)
PATTERN
def on_block(node)
hook(node) do |method_send, scope_name|
return correct_style_detected if scope_name.equal?(style)
return check_implicit(method_send) unless scope_name
style_detected(scope_name)
msg = explicit_message(scope_name)
add_offense(method_send, message: msg) do |corrector|
scope = implicit_style? ? '' : "(#{style.inspect})"
corrector.replace(argument_range(method_send), scope)
end
end
end
alias on_numblock on_block
private
def check_implicit(method_send)
style_detected(:implicit)
return if implicit_style?
msg = explicit_message(nil)
add_offense(method_send.loc.selector, message: msg) do |corrector|
scope = "(#{style.inspect})"
corrector.replace(argument_range(method_send), scope)
end
end
def explicit_message(scope)
if implicit_style?
format(IMPLICIT_MSG, scope: scope)
else
format(EXPLICIT_MSG, scope: style)
end
end
def implicit_style?
style.equal?(:implicit)
end
def hook(node, &block)
scoped_hook(node, &block) || unscoped_hook(node, &block)
end
def argument_range(send_node)
send_node.loc.selector.end.with(
end_pos: send_node.loc.expression.end_pos
)
end
end
end
end
end
|