rubocop-rspec 2.18.0 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -1
- data/README.md +1 -1
- data/config/default.yml +31 -0
- data/lib/rubocop/cop/rspec/be_nil.rb +2 -2
- data/lib/rubocop/cop/rspec/change_by_zero.rb +3 -3
- data/lib/rubocop/cop/rspec/contain_exactly.rb +45 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +13 -5
- data/lib/rubocop/cop/rspec/describe_method.rb +16 -8
- data/lib/rubocop/cop/rspec/described_class.rb +2 -1
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +3 -1
- data/lib/rubocop/cop/rspec/dialect.rb +1 -1
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +7 -7
- data/lib/rubocop/cop/rspec/empty_hook.rb +2 -2
- data/lib/rubocop/cop/rspec/example_wording.rb +1 -1
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +2 -2
- data/lib/rubocop/cop/rspec/file_path.rb +1 -1
- data/lib/rubocop/cop/rspec/focus.rb +4 -5
- data/lib/rubocop/cop/rspec/hook_argument.rb +12 -9
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +5 -3
- data/lib/rubocop/cop/rspec/let_before_examples.rb +4 -4
- data/lib/rubocop/cop/rspec/let_setup.rb +6 -8
- data/lib/rubocop/cop/rspec/match_array.rb +41 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +1 -2
- data/lib/rubocop/cop/rspec/mixin/location_help.rb +37 -0
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +20 -4
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -1
- data/lib/rubocop/cop/rspec/named_subject.rb +6 -4
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +2 -5
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +3 -1
- data/lib/rubocop/cop/rspec/pending.rb +12 -12
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +65 -36
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +9 -34
- data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +4 -4
- data/lib/rubocop/cop/rspec/rails/travel_around.rb +92 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
- data/lib/rubocop/cop/rspec/redundant_around.rb +69 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +3 -6
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +3 -6
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +3 -4
- data/lib/rubocop/cop/rspec/shared_context.rb +12 -13
- data/lib/rubocop/cop/rspec/shared_examples.rb +6 -4
- data/lib/rubocop/cop/rspec/skip_block_inside_example.rb +46 -0
- data/lib/rubocop/cop/rspec/sort_metadata.rb +2 -2
- data/lib/rubocop/cop/rspec/variable_definition.rb +3 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +4 -1
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +3 -3
- data/lib/rubocop/cop/rspec_cops.rb +5 -0
- data/lib/rubocop/rspec/example_group.rb +6 -8
- data/lib/rubocop/rspec/language/node_pattern.rb +26 -0
- data/lib/rubocop/rspec/language.rb +25 -16
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop-rspec.rb +1 -0
- metadata +13 -7
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helper methods to location.
|
7
|
+
module LocationHelp
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# @param node [RuboCop::AST::SendNode]
|
11
|
+
# @return [Parser::Source::Range]
|
12
|
+
# @example
|
13
|
+
# foo 1, 2
|
14
|
+
# ^^^^^
|
15
|
+
def arguments_with_whitespace(node)
|
16
|
+
node.loc.selector.end.with(
|
17
|
+
end_pos: node.source_range.end_pos
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param node [RuboCop::AST::SendNode]
|
22
|
+
# @return [Parser::Source::Range]
|
23
|
+
# @example
|
24
|
+
# foo { bar }
|
25
|
+
# ^^^^^^^^
|
26
|
+
def block_with_whitespace(node)
|
27
|
+
return unless (parent = node.parent)
|
28
|
+
return unless parent.block_type?
|
29
|
+
|
30
|
+
node.source_range.end.with(
|
31
|
+
end_pos: parent.source_range.end_pos
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -10,13 +10,29 @@ module RuboCop
|
|
10
10
|
# @!method skipped_in_metadata?(node)
|
11
11
|
def_node_matcher :skipped_in_metadata?, <<-PATTERN
|
12
12
|
{
|
13
|
-
(send _ _
|
14
|
-
(send _ _ ... (hash <(pair
|
13
|
+
(send _ _ <(sym {:skip :pending}) ...>)
|
14
|
+
(send _ _ ... (hash <(pair (sym {:skip :pending}) { true str dstr }) ...>))
|
15
15
|
}
|
16
16
|
PATTERN
|
17
17
|
|
18
|
-
# @!method
|
19
|
-
|
18
|
+
# @!method skip_or_pending_inside_block?(node)
|
19
|
+
# Match skip/pending statements inside a block (e.g. `context`)
|
20
|
+
#
|
21
|
+
# @example source that matches
|
22
|
+
# context 'when color is blue' do
|
23
|
+
# skip 'not implemented yet'
|
24
|
+
# pending 'not implemented yet'
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @example source that does not match
|
28
|
+
# skip 'not implemented yet'
|
29
|
+
# pending 'not implemented yet'
|
30
|
+
#
|
31
|
+
# @param node [RuboCop::AST::Node]
|
32
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
33
|
+
def_node_matcher :skip_or_pending_inside_block?, <<-PATTERN
|
34
|
+
(block <(send nil? {:skip :pending} ...) ...>)
|
35
|
+
PATTERN
|
20
36
|
end
|
21
37
|
end
|
22
38
|
end
|
@@ -78,7 +78,8 @@ module RuboCop
|
|
78
78
|
PATTERN
|
79
79
|
|
80
80
|
# @!method expect?(node)
|
81
|
-
def_node_matcher :expect?,
|
81
|
+
def_node_matcher :expect?, '(send nil? #Expectations.all ...)'
|
82
|
+
|
82
83
|
# @!method aggregate_failures_block?(node)
|
83
84
|
def_node_matcher :aggregate_failures_block?, <<-PATTERN
|
84
85
|
(block (send nil? :aggregate_failures ...) ...)
|
@@ -82,12 +82,14 @@ module RuboCop
|
|
82
82
|
MSG = 'Name your test subject if you need to reference it explicitly.'
|
83
83
|
|
84
84
|
# @!method example_or_hook_block?(node)
|
85
|
-
def_node_matcher :example_or_hook_block?,
|
86
|
-
|
85
|
+
def_node_matcher :example_or_hook_block?, <<~PATTERN
|
86
|
+
(block (send nil? {#Examples.all #Hooks.all} ...) ...)
|
87
|
+
PATTERN
|
87
88
|
|
88
89
|
# @!method shared_example?(node)
|
89
|
-
def_node_matcher :shared_example?,
|
90
|
-
|
90
|
+
def_node_matcher :shared_example?, <<~PATTERN
|
91
|
+
(block (send #rspec? #SharedGroups.examples ...) ...)
|
92
|
+
PATTERN
|
91
93
|
|
92
94
|
# @!method subject_usage(node)
|
93
95
|
def_node_search :subject_usage, '$(send nil? :subject)'
|
@@ -65,10 +65,7 @@ module RuboCop
|
|
65
65
|
# @param [RuboCop::AST::Node] node
|
66
66
|
# @return [Boolean]
|
67
67
|
def_node_matcher :regular_or_focused_example?, <<~PATTERN
|
68
|
-
{
|
69
|
-
#{block_pattern('{#Examples.regular | #Examples.focused}')}
|
70
|
-
#{numblock_pattern('{#Examples.regular | #Examples.focused}')}
|
71
|
-
}
|
68
|
+
({block numblock} (send nil? {#Examples.regular #Examples.focused} ...) ...)
|
72
69
|
PATTERN
|
73
70
|
|
74
71
|
# @!method includes_expectation?(node)
|
@@ -76,7 +73,7 @@ module RuboCop
|
|
76
73
|
# @return [Boolean]
|
77
74
|
def_node_search :includes_expectation?, <<~PATTERN
|
78
75
|
{
|
79
|
-
|
76
|
+
(send nil? #Expectations.all ...)
|
80
77
|
(send nil? `#matches_allowed_pattern? ...)
|
81
78
|
}
|
82
79
|
PATTERN
|
@@ -26,7 +26,9 @@ module RuboCop
|
|
26
26
|
MSG = '`%<name>s` is already defined.'
|
27
27
|
|
28
28
|
# @!method setup?(node)
|
29
|
-
def_node_matcher :setup?,
|
29
|
+
def_node_matcher :setup?, <<~PATTERN
|
30
|
+
(block (send nil? {#Helpers.all #Subjects.all} ...) ...)
|
31
|
+
PATTERN
|
30
32
|
|
31
33
|
# @!method first_argument_name(node)
|
32
34
|
def_node_matcher :first_argument_name, '(send _ _ ({str sym} $_))'
|
@@ -38,20 +38,20 @@ module RuboCop
|
|
38
38
|
MSG = 'Pending spec found.'
|
39
39
|
|
40
40
|
# @!method skippable?(node)
|
41
|
-
def_node_matcher :skippable?,
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
def_node_matcher :skippable?, <<~PATTERN
|
42
|
+
{
|
43
|
+
(send #rspec? #ExampleGroups.regular ...)
|
44
|
+
(send nil? #Examples.regular ...)
|
45
|
+
}
|
46
|
+
PATTERN
|
45
47
|
|
46
48
|
# @!method pending_block?(node)
|
47
|
-
def_node_matcher :pending_block?,
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
}
|
54
|
-
PATTERN
|
49
|
+
def_node_matcher :pending_block?, <<~PATTERN
|
50
|
+
{
|
51
|
+
(send #rspec? #ExampleGroups.skipped ...)
|
52
|
+
(send nil? {#Examples.skipped #Examples.pending} ...)
|
53
|
+
}
|
54
|
+
PATTERN
|
55
55
|
|
56
56
|
def on_send(node)
|
57
57
|
return unless pending_block?(node) || skipped?(node)
|
@@ -59,61 +59,90 @@ module RuboCop
|
|
59
59
|
class PendingWithoutReason < Base
|
60
60
|
MSG = 'Give the reason for pending or skip.'
|
61
61
|
|
62
|
-
# @!method
|
63
|
-
def_node_matcher :
|
64
|
-
|
62
|
+
# @!method skipped_in_example?(node)
|
63
|
+
def_node_matcher :skipped_in_example?, <<~PATTERN
|
64
|
+
{
|
65
|
+
(send nil? ${#Examples.skipped #Examples.pending})
|
66
|
+
(block (send nil? ${#Examples.skipped}) ...)
|
67
|
+
(numblock (send nil? ${#Examples.skipped}) ...)
|
68
|
+
}
|
65
69
|
PATTERN
|
66
70
|
|
67
|
-
# @!method
|
68
|
-
def_node_matcher :
|
69
|
-
(send
|
71
|
+
# @!method skipped_by_example_method?(node)
|
72
|
+
def_node_matcher :skipped_by_example_method?, <<~PATTERN
|
73
|
+
(send nil? ${#Examples.skipped #Examples.pending} ...)
|
70
74
|
PATTERN
|
71
75
|
|
72
|
-
# @!method
|
73
|
-
def_node_matcher :
|
74
|
-
#
|
76
|
+
# @!method metadata_without_reason?(node)
|
77
|
+
def_node_matcher :metadata_without_reason?, <<~PATTERN
|
78
|
+
(send #rspec?
|
79
|
+
{#ExampleGroups.all #Examples.all} ...
|
80
|
+
{
|
81
|
+
<(sym ${:pending :skip}) ...>
|
82
|
+
(hash <(pair (sym ${:pending :skip}) true) ...>)
|
83
|
+
}
|
84
|
+
)
|
75
85
|
PATTERN
|
76
86
|
|
77
87
|
# @!method skipped_by_example_group_method?(node)
|
78
|
-
def_node_matcher
|
79
|
-
|
80
|
-
block_pattern(<<~PATTERN)
|
81
|
-
#ExampleGroups.skipped
|
82
|
-
PATTERN
|
83
|
-
)
|
84
|
-
|
85
|
-
# @!method skipped_by_metadata_without_reason?(node)
|
86
|
-
def_node_matcher :skipped_by_metadata_without_reason?, <<~PATTERN
|
87
|
-
(send #rspec? {#ExampleGroups.all #Examples.all} ... {<(sym :skip) ...> (hash <(pair (sym :skip) true) ...>)})
|
88
|
+
def_node_matcher :skipped_by_example_group_method?, <<~PATTERN
|
89
|
+
(send #rspec? ${#ExampleGroups.skipped} ...)
|
88
90
|
PATTERN
|
89
91
|
|
90
|
-
# @!method
|
91
|
-
def_node_matcher :
|
92
|
-
(send nil?
|
92
|
+
# @!method pending_step_without_reason?(node)
|
93
|
+
def_node_matcher :pending_step_without_reason?, <<~PATTERN
|
94
|
+
(send nil? {:skip :pending})
|
93
95
|
PATTERN
|
94
96
|
|
95
97
|
def on_send(node)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
98
|
+
on_pending_by_metadata(node)
|
99
|
+
return unless (parent = parent_node(node))
|
100
|
+
|
101
|
+
if example_group?(parent) || block_node_example_group?(node)
|
102
|
+
on_skipped_by_example_method(node)
|
103
|
+
on_skipped_by_example_group_method(node)
|
104
|
+
elsif example?(parent)
|
105
|
+
on_skipped_by_in_example_method(node, parent)
|
103
106
|
end
|
104
107
|
end
|
105
108
|
|
106
109
|
private
|
107
110
|
|
108
|
-
def
|
109
|
-
|
110
|
-
|
111
|
+
def parent_node(node)
|
112
|
+
node_or_block = node.block_node || node
|
113
|
+
return unless (parent = node_or_block.parent)
|
114
|
+
|
115
|
+
parent.begin_type? && parent.parent ? parent.parent : parent
|
116
|
+
end
|
117
|
+
|
118
|
+
def block_node_example_group?(node)
|
119
|
+
node.block_node &&
|
120
|
+
example_group?(node.block_node) &&
|
121
|
+
explicit_rspec?(node.receiver)
|
122
|
+
end
|
123
|
+
|
124
|
+
def on_skipped_by_in_example_method(node, _direct_parent)
|
125
|
+
skipped_in_example?(node) do |pending|
|
126
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
127
|
+
end
|
111
128
|
end
|
112
129
|
|
113
|
-
def
|
114
|
-
|
115
|
-
|
116
|
-
|
130
|
+
def on_pending_by_metadata(node)
|
131
|
+
metadata_without_reason?(node) do |pending|
|
132
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def on_skipped_by_example_method(node)
|
137
|
+
skipped_by_example_method?(node) do |pending|
|
138
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def on_skipped_by_example_group_method(node)
|
143
|
+
skipped_by_example_group_method?(node) do
|
144
|
+
add_offense(node, message: 'Give the reason for skip.')
|
145
|
+
end
|
117
146
|
end
|
118
147
|
end
|
119
148
|
end
|
@@ -84,22 +84,22 @@ module RuboCop
|
|
84
84
|
|
85
85
|
def remove_predicate(corrector, predicate)
|
86
86
|
range = predicate.loc.dot.with(
|
87
|
-
end_pos: predicate.
|
87
|
+
end_pos: predicate.source_range.end_pos
|
88
88
|
)
|
89
89
|
|
90
90
|
corrector.remove(range)
|
91
91
|
|
92
|
-
block_range =
|
92
|
+
block_range = LocationHelp.block_with_whitespace(predicate)
|
93
93
|
corrector.remove(block_range) if block_range
|
94
94
|
end
|
95
95
|
|
96
96
|
def rewrite_matcher(corrector, predicate, matcher)
|
97
|
-
args =
|
98
|
-
block_loc =
|
97
|
+
args = LocationHelp.arguments_with_whitespace(predicate).source
|
98
|
+
block_loc = LocationHelp.block_with_whitespace(predicate)
|
99
99
|
block = block_loc ? block_loc.source : ''
|
100
100
|
|
101
101
|
corrector.replace(
|
102
|
-
matcher.
|
102
|
+
matcher.source_range,
|
103
103
|
to_predicate_matcher(predicate.method_name) + args + block
|
104
104
|
)
|
105
105
|
end
|
@@ -214,19 +214,19 @@ module RuboCop
|
|
214
214
|
|
215
215
|
def corrector_explicit(corrector, to_node, actual, matcher, block_child)
|
216
216
|
replacement_matcher = replacement_matcher(to_node)
|
217
|
-
corrector.replace(matcher.
|
217
|
+
corrector.replace(matcher.source_range, replacement_matcher)
|
218
218
|
move_predicate(corrector, actual, matcher, block_child)
|
219
219
|
corrector.replace(to_node.loc.selector, 'to')
|
220
220
|
end
|
221
221
|
|
222
222
|
def move_predicate(corrector, actual, matcher, block_child)
|
223
223
|
predicate = to_predicate_method(matcher.method_name)
|
224
|
-
args =
|
225
|
-
block_loc =
|
224
|
+
args = LocationHelp.arguments_with_whitespace(matcher).source
|
225
|
+
block_loc = LocationHelp.block_with_whitespace(block_child)
|
226
226
|
block = block_loc ? block_loc.source : ''
|
227
227
|
|
228
228
|
corrector.remove(block_loc) if block_loc
|
229
|
-
corrector.insert_after(actual.
|
229
|
+
corrector.insert_after(actual.source_range,
|
230
230
|
".#{predicate}" + args + block)
|
231
231
|
end
|
232
232
|
|
@@ -332,31 +332,6 @@ module RuboCop
|
|
332
332
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
333
333
|
check_explicit(node) if style == :explicit
|
334
334
|
end
|
335
|
-
|
336
|
-
private
|
337
|
-
|
338
|
-
# returns args location with whitespace
|
339
|
-
# @example
|
340
|
-
# foo 1, 2
|
341
|
-
# ^^^^^
|
342
|
-
def args_loc(send_node)
|
343
|
-
send_node.loc.selector.end.with(
|
344
|
-
end_pos: send_node.loc.expression.end_pos
|
345
|
-
)
|
346
|
-
end
|
347
|
-
|
348
|
-
# returns block location with whitespace
|
349
|
-
# @example
|
350
|
-
# foo { bar }
|
351
|
-
# ^^^^^^^^
|
352
|
-
def block_loc(send_node)
|
353
|
-
parent = send_node.parent
|
354
|
-
return unless parent.block_type?
|
355
|
-
|
356
|
-
send_node.loc.expression.end.with(
|
357
|
-
end_pos: parent.loc.expression.end_pos
|
358
|
-
)
|
359
|
-
end
|
360
335
|
end
|
361
336
|
end
|
362
337
|
end
|
@@ -96,12 +96,12 @@ module RuboCop
|
|
96
96
|
# @return [Parser::Source::Range]
|
97
97
|
def remove_range(node)
|
98
98
|
if node.left_sibling
|
99
|
-
node.
|
100
|
-
begin_pos: node.left_sibling.
|
99
|
+
node.source_range.with(
|
100
|
+
begin_pos: node.left_sibling.source_range.end_pos
|
101
101
|
)
|
102
102
|
elsif node.right_sibling
|
103
|
-
node.
|
104
|
-
end_pos: node.right_sibling.
|
103
|
+
node.source_range.with(
|
104
|
+
end_pos: node.right_sibling.source_range.begin_pos
|
105
105
|
)
|
106
106
|
end
|
107
107
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
module Rails
|
7
|
+
# Prefer to travel in `before` rather than `around`.
|
8
|
+
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe because the automatic `travel_back` is only run
|
11
|
+
# on test cases that are considered as Rails related.
|
12
|
+
#
|
13
|
+
# And also, this cop's autocorrection is unsafe because the order of
|
14
|
+
# execution will change if other steps exist before traveling in
|
15
|
+
# `around`.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# # bad
|
19
|
+
# around do |example|
|
20
|
+
# freeze_time do
|
21
|
+
# example.run
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# before { freeze_time }
|
27
|
+
class TravelAround < Base
|
28
|
+
extend AutoCorrector
|
29
|
+
|
30
|
+
MSG = 'Prefer to travel in `before` rather than `around`.'
|
31
|
+
|
32
|
+
TRAVEL_METHOD_NAMES = %i[
|
33
|
+
freeze_time
|
34
|
+
travel
|
35
|
+
travel_to
|
36
|
+
].to_set.freeze
|
37
|
+
|
38
|
+
# @!method extract_run_in_travel(node)
|
39
|
+
def_node_matcher :extract_run_in_travel, <<~PATTERN
|
40
|
+
(block
|
41
|
+
$(send nil? TRAVEL_METHOD_NAMES ...)
|
42
|
+
(args ...)
|
43
|
+
(send _ :run)
|
44
|
+
)
|
45
|
+
PATTERN
|
46
|
+
|
47
|
+
# @!method match_around_each?(node)
|
48
|
+
def_node_matcher :match_around_each?, <<~PATTERN
|
49
|
+
(block
|
50
|
+
(send _ :around (sym :each)?)
|
51
|
+
...
|
52
|
+
)
|
53
|
+
PATTERN
|
54
|
+
|
55
|
+
def on_block(node)
|
56
|
+
run_node = extract_run_in_travel(node)
|
57
|
+
return unless run_node
|
58
|
+
|
59
|
+
around_node = extract_surrounding_around_block(run_node)
|
60
|
+
return unless around_node
|
61
|
+
|
62
|
+
add_offense(node) do |corrector|
|
63
|
+
autocorrect(corrector, node, run_node, around_node)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
alias on_numblock on_block
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def autocorrect(corrector, node, run_node, around_node)
|
71
|
+
corrector.replace(
|
72
|
+
node,
|
73
|
+
node.body.source
|
74
|
+
)
|
75
|
+
corrector.insert_before(
|
76
|
+
around_node,
|
77
|
+
"before { #{run_node.source} }\n\n"
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param node [RuboCop::AST::BlockNode]
|
82
|
+
# @return [RuboCop::AST::BlockNode, nil]
|
83
|
+
def extract_surrounding_around_block(node)
|
84
|
+
node.each_ancestor(:block).find do |ancestor|
|
85
|
+
match_around_each?(ancestor)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Remove redundant `around` hook.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# around do |example|
|
11
|
+
# example.run
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
#
|
16
|
+
class RedundantAround < Base
|
17
|
+
extend AutoCorrector
|
18
|
+
|
19
|
+
MSG = 'Remove redundant `around` hook.'
|
20
|
+
|
21
|
+
RESTRICT_ON_SEND = %i[around].freeze
|
22
|
+
|
23
|
+
def on_block(node)
|
24
|
+
return unless match_redundant_around_hook_block?(node)
|
25
|
+
|
26
|
+
add_offense(node) do |corrector|
|
27
|
+
autocorrect(corrector, node)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
alias on_numblock on_block
|
31
|
+
|
32
|
+
def on_send(node)
|
33
|
+
return unless match_redundant_around_hook_send?(node)
|
34
|
+
|
35
|
+
add_offense(node) do |corrector|
|
36
|
+
autocorrect(corrector, node)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @!method match_redundant_around_hook_block?(node)
|
43
|
+
def_node_matcher :match_redundant_around_hook_block?, <<~PATTERN
|
44
|
+
(block
|
45
|
+
(send _ :around ...)
|
46
|
+
(args _?)
|
47
|
+
(send _ :run)
|
48
|
+
)
|
49
|
+
PATTERN
|
50
|
+
|
51
|
+
# @!method match_redundant_around_hook_send?(node)
|
52
|
+
def_node_matcher :match_redundant_around_hook_send?, <<~PATTERN
|
53
|
+
(send
|
54
|
+
_
|
55
|
+
:around
|
56
|
+
...
|
57
|
+
(block-pass
|
58
|
+
(sym :run)
|
59
|
+
)
|
60
|
+
)
|
61
|
+
PATTERN
|
62
|
+
|
63
|
+
def autocorrect(corrector, node)
|
64
|
+
corrector.remove(node)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -43,6 +43,8 @@ module RuboCop
|
|
43
43
|
# end
|
44
44
|
#
|
45
45
|
class RepeatedExampleGroupBody < Base
|
46
|
+
include SkipOrPending
|
47
|
+
|
46
48
|
MSG = 'Repeated %<group>s block body on line(s) %<loc>s'
|
47
49
|
|
48
50
|
# @!method several_example_groups?(node)
|
@@ -59,11 +61,6 @@ module RuboCop
|
|
59
61
|
# @!method const_arg(node)
|
60
62
|
def_node_matcher :const_arg, '(block (send _ _ $const ...) ...)'
|
61
63
|
|
62
|
-
# @!method skip_or_pending?(node)
|
63
|
-
def_node_matcher :skip_or_pending?, <<-PATTERN
|
64
|
-
(block <(send nil? {:skip :pending} ...) ...>)
|
65
|
-
PATTERN
|
66
|
-
|
67
64
|
def on_begin(node)
|
68
65
|
return unless several_example_groups?(node)
|
69
66
|
|
@@ -78,7 +75,7 @@ module RuboCop
|
|
78
75
|
node
|
79
76
|
.children
|
80
77
|
.select { |child| example_group_with_body?(child) }
|
81
|
-
.reject { |child|
|
78
|
+
.reject { |child| skip_or_pending_inside_block?(child) }
|
82
79
|
.group_by { |group| signature_keys(group) }
|
83
80
|
.values
|
84
81
|
.reject(&:one?)
|
@@ -43,6 +43,8 @@ module RuboCop
|
|
43
43
|
# end
|
44
44
|
#
|
45
45
|
class RepeatedExampleGroupDescription < Base
|
46
|
+
include SkipOrPending
|
47
|
+
|
46
48
|
MSG = 'Repeated %<group>s block description on line(s) %<loc>s'
|
47
49
|
|
48
50
|
# @!method several_example_groups?(node)
|
@@ -55,11 +57,6 @@ module RuboCop
|
|
55
57
|
(block (send _ _ $_ $...) ...)
|
56
58
|
PATTERN
|
57
59
|
|
58
|
-
# @!method skip_or_pending?(node)
|
59
|
-
def_node_matcher :skip_or_pending?, <<-PATTERN
|
60
|
-
(block <(send nil? {:skip :pending}) ...>)
|
61
|
-
PATTERN
|
62
|
-
|
63
60
|
# @!method empty_description?(node)
|
64
61
|
def_node_matcher :empty_description?, '(block (send _ _) ...)'
|
65
62
|
|
@@ -77,7 +74,7 @@ module RuboCop
|
|
77
74
|
node
|
78
75
|
.children
|
79
76
|
.select { |child| example_group?(child) }
|
80
|
-
.reject { |child|
|
77
|
+
.reject { |child| skip_or_pending_inside_block?(child) }
|
81
78
|
.reject { |child| empty_description?(child) }
|
82
79
|
.group_by { |group| doc_string_and_metadata(group) }
|
83
80
|
.values
|
@@ -56,12 +56,11 @@ module RuboCop
|
|
56
56
|
|
57
57
|
# @!method include_examples?(node)
|
58
58
|
def_node_matcher :include_examples?,
|
59
|
-
|
59
|
+
'(send nil? #Includes.examples ...)'
|
60
60
|
|
61
61
|
# @!method shared_examples_name(node)
|
62
|
-
def_node_matcher :shared_examples_name,
|
63
|
-
|
64
|
-
PATTERN
|
62
|
+
def_node_matcher :shared_examples_name,
|
63
|
+
'(send nil? #Includes.examples $_name ...)'
|
65
64
|
|
66
65
|
def on_begin(node)
|
67
66
|
return unless several_include_examples?(node)
|