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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -1
  3. data/README.md +1 -1
  4. data/config/default.yml +31 -0
  5. data/lib/rubocop/cop/rspec/be_nil.rb +2 -2
  6. data/lib/rubocop/cop/rspec/change_by_zero.rb +3 -3
  7. data/lib/rubocop/cop/rspec/contain_exactly.rb +45 -0
  8. data/lib/rubocop/cop/rspec/context_wording.rb +13 -5
  9. data/lib/rubocop/cop/rspec/describe_method.rb +16 -8
  10. data/lib/rubocop/cop/rspec/described_class.rb +2 -1
  11. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +3 -1
  12. data/lib/rubocop/cop/rspec/dialect.rb +1 -1
  13. data/lib/rubocop/cop/rspec/duplicated_metadata.rb +1 -1
  14. data/lib/rubocop/cop/rspec/empty_example_group.rb +7 -7
  15. data/lib/rubocop/cop/rspec/empty_hook.rb +2 -2
  16. data/lib/rubocop/cop/rspec/example_wording.rb +1 -1
  17. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -1
  18. data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
  19. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +1 -1
  20. data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +2 -2
  21. data/lib/rubocop/cop/rspec/file_path.rb +1 -1
  22. data/lib/rubocop/cop/rspec/focus.rb +4 -5
  23. data/lib/rubocop/cop/rspec/hook_argument.rb +12 -9
  24. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +5 -3
  25. data/lib/rubocop/cop/rspec/let_before_examples.rb +4 -4
  26. data/lib/rubocop/cop/rspec/let_setup.rb +6 -8
  27. data/lib/rubocop/cop/rspec/match_array.rb +41 -0
  28. data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +1 -2
  29. data/lib/rubocop/cop/rspec/mixin/location_help.rb +37 -0
  30. data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +20 -4
  31. data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -1
  32. data/lib/rubocop/cop/rspec/named_subject.rb +6 -4
  33. data/lib/rubocop/cop/rspec/no_expectation_example.rb +2 -5
  34. data/lib/rubocop/cop/rspec/overwriting_setup.rb +3 -1
  35. data/lib/rubocop/cop/rspec/pending.rb +12 -12
  36. data/lib/rubocop/cop/rspec/pending_without_reason.rb +65 -36
  37. data/lib/rubocop/cop/rspec/predicate_matcher.rb +9 -34
  38. data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +4 -4
  39. data/lib/rubocop/cop/rspec/rails/travel_around.rb +92 -0
  40. data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
  41. data/lib/rubocop/cop/rspec/redundant_around.rb +69 -0
  42. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +3 -6
  43. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +3 -6
  44. data/lib/rubocop/cop/rspec/repeated_include_example.rb +3 -4
  45. data/lib/rubocop/cop/rspec/shared_context.rb +12 -13
  46. data/lib/rubocop/cop/rspec/shared_examples.rb +6 -4
  47. data/lib/rubocop/cop/rspec/skip_block_inside_example.rb +46 -0
  48. data/lib/rubocop/cop/rspec/sort_metadata.rb +2 -2
  49. data/lib/rubocop/cop/rspec/variable_definition.rb +3 -0
  50. data/lib/rubocop/cop/rspec/variable_name.rb +4 -1
  51. data/lib/rubocop/cop/rspec/verified_double_reference.rb +3 -3
  52. data/lib/rubocop/cop/rspec_cops.rb +5 -0
  53. data/lib/rubocop/rspec/example_group.rb +6 -8
  54. data/lib/rubocop/rspec/language/node_pattern.rb +26 -0
  55. data/lib/rubocop/rspec/language.rb +25 -16
  56. data/lib/rubocop/rspec/version.rb +1 -1
  57. data/lib/rubocop-rspec.rb +1 -0
  58. 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 _ _ <#skip_or_pending? ...>)
14
- (send _ _ ... (hash <(pair #skip_or_pending? { true str dstr }) ...>))
13
+ (send _ _ <(sym {:skip :pending}) ...>)
14
+ (send _ _ ... (hash <(pair (sym {:skip :pending}) { true str dstr }) ...>))
15
15
  }
16
16
  PATTERN
17
17
 
18
- # @!method skip_or_pending?(node)
19
- def_node_matcher :skip_or_pending?, '{(sym :skip) (sym :pending)}'
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?, send_pattern('#Expectations.all')
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
- block_pattern('{#Examples.all #Hooks.all}')
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
- block_pattern('#SharedGroups.examples')
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
- #{send_pattern('#Expectations.all')}
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?, block_pattern('{#Helpers.all #Subjects.all}')
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
- send_pattern(<<~PATTERN)
43
- {#ExampleGroups.regular #Examples.regular}
44
- PATTERN
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
- send_pattern(<<~PATTERN)
49
- {
50
- #ExampleGroups.skipped
51
- #Examples.skipped
52
- #Examples.pending
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 pending_by_example_method?(node)
63
- def_node_matcher :pending_by_example_method?, block_pattern(<<~PATTERN)
64
- #Examples.pending
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 pending_by_metadata_without_reason?(node)
68
- def_node_matcher :pending_by_metadata_without_reason?, <<~PATTERN
69
- (send #rspec? {#ExampleGroups.all #Examples.all} ... {<(sym :pending) ...> (hash <(pair (sym :pending) true) ...>)})
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 skipped_by_example_method?(node)
73
- def_node_matcher :skipped_by_example_method?, block_pattern(<<~PATTERN)
74
- #Examples.skipped
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
- :skipped_by_example_group_method?,
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 without_reason?(node)
91
- def_node_matcher :without_reason?, <<~PATTERN
92
- (send nil? ${:pending :skip})
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
- if pending_without_reason?(node)
97
- add_offense(node, message: 'Give the reason for pending.')
98
- elsif skipped_without_reason?(node)
99
- add_offense(node, message: 'Give the reason for skip.')
100
- elsif without_reason?(node) && example?(node.parent)
101
- add_offense(node,
102
- message: "Give the reason for #{node.method_name}.")
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 pending_without_reason?(node)
109
- pending_by_example_method?(node.block_node) ||
110
- pending_by_metadata_without_reason?(node)
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 skipped_without_reason?(node)
114
- skipped_by_example_group_method?(node.block_node) ||
115
- skipped_by_example_method?(node.block_node) ||
116
- skipped_by_metadata_without_reason?(node)
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.loc.expression.end_pos
87
+ end_pos: predicate.source_range.end_pos
88
88
  )
89
89
 
90
90
  corrector.remove(range)
91
91
 
92
- block_range = block_loc(predicate)
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 = args_loc(predicate).source
98
- block_loc = block_loc(predicate)
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.loc.expression,
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.loc.expression, replacement_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 = args_loc(matcher).source
225
- block_loc = block_loc(block_child)
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.loc.expression,
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.loc.expression.with(
100
- begin_pos: node.left_sibling.loc.expression.end_pos
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.loc.expression.with(
104
- end_pos: node.right_sibling.loc.expression.begin_pos
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
@@ -80,7 +80,7 @@ module RuboCop
80
80
 
81
81
  def range(node, offending_node)
82
82
  offending_node.loc.dot.with(
83
- end_pos: node.loc.expression.end_pos
83
+ end_pos: node.source_range.end_pos
84
84
  )
85
85
  end
86
86
  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| skip_or_pending?(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| skip_or_pending?(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
- send_pattern('#Includes.examples')
59
+ '(send nil? #Includes.examples ...)'
60
60
 
61
61
  # @!method shared_examples_name(node)
62
- def_node_matcher :shared_examples_name, <<-PATTERN
63
- (send _ #Includes.examples $_ ...)
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)