-
-
Notifications
You must be signed in to change notification settings - Fork 269
/
hook_argument.rb
134 lines (120 loc) · 3.37 KB
/
hook_argument.rb
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
132
133
134
# 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|
autocorrect(corrector, node, method_send)
end
end
end
alias on_numblock on_block
private
def autocorrect(corrector, _node, method_send)
scope = implicit_style? ? '' : "(#{style.inspect})"
corrector.replace(
LocationHelp.arguments_with_whitespace(method_send), scope
)
end
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(
LocationHelp.arguments_with_whitespace(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
end
end
end
end