rubocop-rspec 1.41.0 → 1.44.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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -2
  3. data/config/default.yml +41 -3
  4. data/lib/rubocop-rspec.rb +2 -1
  5. data/lib/rubocop/cop/rspec/align_left_let_brace.rb +12 -19
  6. data/lib/rubocop/cop/rspec/align_right_let_brace.rb +12 -19
  7. data/lib/rubocop/cop/rspec/any_instance.rb +1 -1
  8. data/lib/rubocop/cop/rspec/around_block.rb +2 -2
  9. data/lib/rubocop/cop/rspec/base.rb +76 -0
  10. data/lib/rubocop/cop/rspec/be.rb +2 -2
  11. data/lib/rubocop/cop/rspec/be_eql.rb +6 -6
  12. data/lib/rubocop/cop/rspec/before_after_all.rb +1 -1
  13. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +19 -17
  14. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +14 -12
  15. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +1 -1
  16. data/lib/rubocop/cop/rspec/context_method.rb +7 -9
  17. data/lib/rubocop/cop/rspec/context_wording.rb +3 -3
  18. data/lib/rubocop/cop/rspec/cop.rb +2 -66
  19. data/lib/rubocop/cop/rspec/describe_class.rb +40 -30
  20. data/lib/rubocop/cop/rspec/describe_method.rb +14 -6
  21. data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -2
  22. data/lib/rubocop/cop/rspec/described_class.rb +12 -9
  23. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -1
  24. data/lib/rubocop/cop/rspec/dialect.rb +5 -12
  25. data/lib/rubocop/cop/rspec/empty_example_group.rb +124 -6
  26. data/lib/rubocop/cop/rspec/empty_hook.rb +6 -10
  27. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +5 -7
  28. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +5 -9
  29. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +8 -8
  30. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +5 -9
  31. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +6 -6
  32. data/lib/rubocop/cop/rspec/example_length.rb +1 -1
  33. data/lib/rubocop/cop/rspec/example_without_description.rb +1 -1
  34. data/lib/rubocop/cop/rspec/example_wording.rb +10 -11
  35. data/lib/rubocop/cop/rspec/expect_actual.rb +8 -11
  36. data/lib/rubocop/cop/rspec/expect_change.rb +10 -35
  37. data/lib/rubocop/cop/rspec/expect_in_hook.rb +3 -3
  38. data/lib/rubocop/cop/rspec/expect_output.rb +2 -2
  39. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +20 -20
  40. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +20 -22
  41. data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +7 -8
  42. data/lib/rubocop/cop/rspec/file_path.rb +25 -17
  43. data/lib/rubocop/cop/rspec/focus.rb +7 -11
  44. data/lib/rubocop/cop/rspec/hook_argument.rb +16 -23
  45. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +13 -14
  46. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -3
  47. data/lib/rubocop/cop/rspec/implicit_expect.rb +7 -15
  48. data/lib/rubocop/cop/rspec/implicit_subject.rb +16 -11
  49. data/lib/rubocop/cop/rspec/instance_spy.rb +18 -12
  50. data/lib/rubocop/cop/rspec/instance_variable.rb +1 -1
  51. data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +3 -6
  52. data/lib/rubocop/cop/rspec/it_behaves_like.rb +5 -6
  53. data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
  54. data/lib/rubocop/cop/rspec/leading_subject.rb +27 -20
  55. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
  56. data/lib/rubocop/cop/rspec/let_before_examples.rb +13 -11
  57. data/lib/rubocop/cop/rspec/let_setup.rb +6 -3
  58. data/lib/rubocop/cop/rspec/message_chain.rb +7 -6
  59. data/lib/rubocop/cop/rspec/message_expectation.rb +2 -2
  60. data/lib/rubocop/cop/rspec/message_spies.rb +2 -3
  61. data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +1 -1
  62. data/lib/rubocop/cop/rspec/multiple_describes.rb +11 -8
  63. data/lib/rubocop/cop/rspec/multiple_expectations.rb +7 -11
  64. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +148 -0
  65. data/lib/rubocop/cop/rspec/multiple_subjects.rb +18 -19
  66. data/lib/rubocop/cop/rspec/named_subject.rb +2 -2
  67. data/lib/rubocop/cop/rspec/nested_groups.rb +4 -4
  68. data/lib/rubocop/cop/rspec/not_to_not.rb +5 -6
  69. data/lib/rubocop/cop/rspec/overwriting_setup.rb +1 -1
  70. data/lib/rubocop/cop/rspec/pending.rb +1 -1
  71. data/lib/rubocop/cop/rspec/predicate_matcher.rb +30 -67
  72. data/lib/rubocop/cop/rspec/rails/http_status.rb +5 -9
  73. data/lib/rubocop/cop/rspec/receive_counts.rb +15 -17
  74. data/lib/rubocop/cop/rspec/receive_never.rb +12 -12
  75. data/lib/rubocop/cop/rspec/repeated_description.rb +1 -1
  76. data/lib/rubocop/cop/rspec/repeated_example.rb +2 -2
  77. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
  78. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +1 -1
  79. data/lib/rubocop/cop/rspec/repeated_include_example.rb +103 -0
  80. data/lib/rubocop/cop/rspec/return_from_stub.rb +9 -20
  81. data/lib/rubocop/cop/rspec/scattered_let.rb +8 -11
  82. data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
  83. data/lib/rubocop/cop/rspec/shared_context.rb +8 -21
  84. data/lib/rubocop/cop/rspec/shared_examples.rb +6 -9
  85. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +15 -18
  86. data/lib/rubocop/cop/rspec/stubbed_mock.rb +172 -0
  87. data/lib/rubocop/cop/rspec/subject_stub.rb +6 -6
  88. data/lib/rubocop/cop/rspec/unspecified_exception.rb +1 -1
  89. data/lib/rubocop/cop/rspec/variable_definition.rb +6 -6
  90. data/lib/rubocop/cop/rspec/variable_name.rb +28 -9
  91. data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
  92. data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
  93. data/lib/rubocop/cop/rspec/yield.rb +14 -11
  94. data/lib/rubocop/cop/rspec_cops.rb +3 -0
  95. data/lib/rubocop/rspec/corrector/move_node.rb +7 -5
  96. data/lib/rubocop/rspec/description_extractor.rb +1 -1
  97. data/lib/rubocop/rspec/{blank_line_separation.rb → empty_line_separation.rb} +13 -10
  98. data/lib/rubocop/rspec/example_group.rb +2 -2
  99. data/lib/rubocop/rspec/hook.rb +1 -5
  100. data/lib/rubocop/rspec/language.rb +12 -5
  101. data/lib/rubocop/rspec/language/node_pattern.rb +6 -1
  102. data/lib/rubocop/rspec/top_level_describe.rb +2 -2
  103. data/lib/rubocop/rspec/top_level_group.rb +26 -13
  104. data/lib/rubocop/rspec/variable.rb +1 -1
  105. data/lib/rubocop/rspec/version.rb +1 -1
  106. metadata +40 -8
@@ -21,7 +21,7 @@ module RuboCop
21
21
  # end
22
22
  # end
23
23
  #
24
- class SubjectStub < Cop
24
+ class SubjectStub < Base
25
25
  include RuboCop::RSpec::TopLevelGroup
26
26
 
27
27
  MSG = 'Do not stub methods of the object under test.'
@@ -39,14 +39,14 @@ module RuboCop
39
39
  # name # => :thing
40
40
  # end
41
41
  #
42
- # @param node [RuboCop::Node]
42
+ # @param node [RuboCop::AST::Node]
43
43
  #
44
44
  # @yield [Symbol] subject name
45
45
  def_node_matcher :subject, <<-PATTERN
46
- {
47
- (block (send nil? :subject (sym $_)) args ...)
48
- (block (send nil? $:subject) args ...)
49
- }
46
+ (block
47
+ (send nil?
48
+ {:subject (sym $_) | $:subject}
49
+ ) args ...)
50
50
  PATTERN
51
51
 
52
52
  # @!method message_expectation?(node, method_name)
@@ -30,7 +30,7 @@ module RuboCop
30
30
  # }.to raise_error(/err/)
31
31
  #
32
32
  # expect { do_something }.not_to raise_error
33
- class UnspecifiedException < Cop
33
+ class UnspecifiedException < Base
34
34
  MSG = 'Specify the exception being captured'
35
35
 
36
36
  def_node_matcher :empty_raise_error_or_exception, <<-PATTERN
@@ -7,22 +7,22 @@ module RuboCop
7
7
  #
8
8
  # @example EnforcedStyle: symbols (default)
9
9
  # # bad
10
- # let('user_name') { 'Adam' }
11
10
  # subject('user') { create_user }
11
+ # let('user_name') { 'Adam' }
12
12
  #
13
13
  # # good
14
- # let(:user_name) { 'Adam' }
15
14
  # subject(:user) { create_user }
15
+ # let(:user_name) { 'Adam' }
16
16
  #
17
17
  # @example EnforcedStyle: strings
18
18
  # # bad
19
- # let(:user_name) { 'Adam' }
20
19
  # subject(:user) { create_user }
20
+ # let(:user_name) { 'Adam' }
21
21
  #
22
22
  # # good
23
- # let('user_name') { 'Adam' }
24
23
  # subject('user') { create_user }
25
- class VariableDefinition < Cop
24
+ # let('user_name') { 'Adam' }
25
+ class VariableDefinition < Base
26
26
  include ConfigurableEnforcedStyle
27
27
  include RuboCop::RSpec::Variable
28
28
 
@@ -44,7 +44,7 @@ module RuboCop
44
44
  end
45
45
 
46
46
  def string?(node)
47
- node.str_type? || node.dstr_type?
47
+ node.str_type?
48
48
  end
49
49
 
50
50
  def symbol?(node)
@@ -5,25 +5,43 @@ module RuboCop
5
5
  module RSpec
6
6
  # Checks that memoized helper names use the configured style.
7
7
  #
8
+ # Variables can be excluded from checking using the `IgnoredPatterns`
9
+ # option.
10
+ #
8
11
  # @example EnforcedStyle: snake_case (default)
9
12
  # # bad
10
- # let(:userName) { 'Adam' }
11
- # subject(:userName) { 'Adam' }
13
+ # subject(:userName1) { 'Adam' }
14
+ # let(:userName2) { 'Adam' }
12
15
  #
13
16
  # # good
14
- # let(:user_name) { 'Adam' }
15
- # subject(:user_name) { 'Adam' }
17
+ # subject(:user_name_1) { 'Adam' }
18
+ # let(:user_name_2) { 'Adam' }
16
19
  #
17
20
  # @example EnforcedStyle: camelCase
18
21
  # # bad
19
- # let(:user_name) { 'Adam' }
20
- # subject(:user_name) { 'Adam' }
22
+ # subject(:user_name_1) { 'Adam' }
23
+ # let(:user_name_2) { 'Adam' }
21
24
  #
22
25
  # # good
23
- # let(:userName) { 'Adam' }
24
- # subject(:userName) { 'Adam' }
25
- class VariableName < Cop
26
+ # subject(:userName1) { 'Adam' }
27
+ # let(:userName2) { 'Adam' }
28
+ #
29
+ # @example IgnoredPatterns configuration
30
+ #
31
+ # # rubocop.yml
32
+ # # RSpec/VariableName:
33
+ # # EnforcedStyle: snake_case
34
+ # # IgnoredPatterns:
35
+ # # - ^userFood
36
+ #
37
+ # @example
38
+ # # okay because it matches the `^userFood` regex in `IgnoredPatterns`
39
+ # subject(:userFood_1) { 'spaghetti' }
40
+ # let(:userFood_2) { 'fettuccine' }
41
+ #
42
+ class VariableName < Base
26
43
  include ConfigurableNaming
44
+ include IgnoredPattern
27
45
  include RuboCop::RSpec::Variable
28
46
 
29
47
  MSG = 'Use %<style>s for variable names.'
@@ -31,6 +49,7 @@ module RuboCop
31
49
  def on_send(node)
32
50
  variable_definition?(node) do |variable|
33
51
  return if variable.dstr_type? || variable.dsym_type?
52
+ return if matches_ignored_pattern?(variable.value)
34
53
 
35
54
  check_name(node, variable.value, variable.loc.expression)
36
55
  end
@@ -22,7 +22,7 @@ module RuboCop
22
22
  # let(:foo) do
23
23
  # instance_double("ClassName", method_name: 'returned value')
24
24
  # end
25
- class VerifiedDoubles < Cop
25
+ class VerifiedDoubles < Base
26
26
  MSG = 'Prefer using verifying doubles over normal doubles.'
27
27
 
28
28
  def_node_matcher :unverified_double, <<-PATTERN
@@ -11,7 +11,7 @@ module RuboCop
11
11
  #
12
12
  # # good
13
13
  # expect(something).to be(1)
14
- class VoidExpect < Cop
14
+ class VoidExpect < Base
15
15
  MSG = 'Do not use `expect()` without `.to` or `.not_to`. ' \
16
16
  'Chain the methods or remove it.'
17
17
 
@@ -11,7 +11,8 @@ module RuboCop
11
11
  #
12
12
  # # good
13
13
  # expect(foo).to be(:bar).and_yield(1)
14
- class Yield < Cop
14
+ class Yield < Base
15
+ extend AutoCorrector
15
16
  include RangeHelp
16
17
 
17
18
  MSG = 'Use `.and_yield`.'
@@ -27,22 +28,24 @@ module RuboCop
27
28
 
28
29
  block_arg(node.arguments) do |block|
29
30
  if calling_block?(node.body, block)
30
- add_offense(node, location: block_range(node))
31
- end
32
- end
33
- end
31
+ range = block_range(node)
34
32
 
35
- def autocorrect(node)
36
- lambda do |corrector|
37
- node_range = range_with_surrounding_space(
38
- range: block_range(node), side: :left
39
- )
40
- corrector.replace(node_range, generate_replacement(node.body))
33
+ add_offense(range) do |corrector|
34
+ autocorrect(corrector, node, range)
35
+ end
36
+ end
41
37
  end
42
38
  end
43
39
 
44
40
  private
45
41
 
42
+ def autocorrect(corrector, node, range)
43
+ corrector.replace(
44
+ range_with_surrounding_space(range: range, side: :left),
45
+ generate_replacement(node.body)
46
+ )
47
+ end
48
+
46
49
  def calling_block?(node, block)
47
50
  if node.begin_type?
48
51
  node.each_child_node.all? { |child| block_call?(child, block) }
@@ -65,6 +65,7 @@ require_relative 'rspec/message_spies'
65
65
  require_relative 'rspec/missing_example_group_argument'
66
66
  require_relative 'rspec/multiple_describes'
67
67
  require_relative 'rspec/multiple_expectations'
68
+ require_relative 'rspec/multiple_memoized_helpers'
68
69
  require_relative 'rspec/multiple_subjects'
69
70
  require_relative 'rspec/named_subject'
70
71
  require_relative 'rspec/nested_groups'
@@ -78,12 +79,14 @@ require_relative 'rspec/repeated_description'
78
79
  require_relative 'rspec/repeated_example'
79
80
  require_relative 'rspec/repeated_example_group_body'
80
81
  require_relative 'rspec/repeated_example_group_description'
82
+ require_relative 'rspec/repeated_include_example'
81
83
  require_relative 'rspec/return_from_stub'
82
84
  require_relative 'rspec/scattered_let'
83
85
  require_relative 'rspec/scattered_setup'
84
86
  require_relative 'rspec/shared_context'
85
87
  require_relative 'rspec/shared_examples'
86
88
  require_relative 'rspec/single_argument_message_chain'
89
+ require_relative 'rspec/stubbed_mock'
87
90
  require_relative 'rspec/subject_stub'
88
91
  require_relative 'rspec/unspecified_exception'
89
92
  require_relative 'rspec/variable_definition'
@@ -16,19 +16,21 @@ module RuboCop
16
16
  @processed_source = processed_source # used by RangeHelp
17
17
  end
18
18
 
19
- def move_before(other) # rubocop:disable Metrics/AbcSize
19
+ def move_before(other)
20
20
  position = other.loc.expression
21
- indent = "\n" + ' ' * other.loc.column
21
+ indent = ' ' * other.loc.column
22
+ newline_indent = "\n#{indent}"
22
23
 
23
- corrector.insert_before(position, source(original) + indent)
24
+ corrector.insert_before(position, source(original) + newline_indent)
24
25
  corrector.remove(node_range_with_surrounding_space(original))
25
26
  end
26
27
 
27
28
  def move_after(other)
28
29
  position = final_end_location(other)
29
- indent = "\n" + ' ' * other.loc.column
30
+ indent = ' ' * other.loc.column
31
+ newline_indent = "\n#{indent}"
30
32
 
31
- corrector.insert_after(position, indent + source(original))
33
+ corrector.insert_after(position, newline_indent + source(original))
32
34
  corrector.remove(node_range_with_surrounding_space(original))
33
35
  end
34
36
 
@@ -21,7 +21,7 @@ module RuboCop
21
21
 
22
22
  # Decorator of a YARD code object for working with documented rspec cops
23
23
  class CodeObject
24
- COP_CLASS_NAME = 'RuboCop::Cop::RSpec::Cop'
24
+ COP_CLASS_NAME = 'RuboCop::Cop::RSpec::Base'
25
25
  RSPEC_NAMESPACE = 'RuboCop::Cop::RSpec'
26
26
 
27
27
  def initialize(yardoc)
@@ -2,12 +2,23 @@
2
2
 
3
3
  module RuboCop
4
4
  module RSpec
5
- # Helps determine the offending location if there is not a blank line
5
+ # Helps determine the offending location if there is not an empty line
6
6
  # following the node. Allows comments to follow directly after.
7
- module BlankLineSeparation
7
+ module EmptyLineSeparation
8
8
  include FinalEndLocation
9
9
  include RuboCop::Cop::RangeHelp
10
10
 
11
+ def missing_separating_line_offense(node)
12
+ return if last_child?(node)
13
+
14
+ missing_separating_line(node) do |location|
15
+ msg = yield(node.method_name)
16
+ add_offense(location, message: msg) do |corrector|
17
+ corrector.insert_after(location.end, "\n")
18
+ end
19
+ end
20
+ end
21
+
11
22
  def missing_separating_line(node)
12
23
  line = final_end_location(node).line
13
24
 
@@ -32,14 +43,6 @@ module RuboCop
32
43
 
33
44
  node.equal?(node.parent.children.last)
34
45
  end
35
-
36
- def autocorrect(node)
37
- lambda do |corrector|
38
- missing_separating_line(node) do |location|
39
- corrector.insert_after(location.end, "\n")
40
- end
41
- end
42
- end
43
46
  end
44
47
  end
45
48
  end
@@ -36,9 +36,9 @@ module RuboCop
36
36
  #
37
37
  # Searches node and halts when a scope change is detected
38
38
  #
39
- # @param node [RuboCop::Node] node to recursively search
39
+ # @param node [RuboCop::AST::Node] node to recursively search
40
40
  #
41
- # @return [Array<RuboCop::Node>] discovered nodes
41
+ # @return [Array<RuboCop::AST::Node>] discovered nodes
42
42
  def find_all_in_scope(node, predicate)
43
43
  node.each_child_node.flat_map do |child|
44
44
  find_all(child, predicate)
@@ -6,11 +6,7 @@ module RuboCop
6
6
  class Hook < Concept
7
7
  def_node_matcher :extract_metadata, <<~PATTERN
8
8
  (block
9
- {
10
- (send _ _ #valid_scope? $...)
11
- (send _ _ $...)
12
- }
13
- ...
9
+ (send _ _ #valid_scope? ? $...) ...
14
10
  )
15
11
  PATTERN
16
12
 
@@ -4,12 +4,11 @@ module RuboCop
4
4
  module RSpec
5
5
  # RSpec public API methods that are commonly used in cops
6
6
  module Language
7
- RSPEC = '{(const {nil? cbase} :RSpec) nil?}'
8
-
9
7
  # Set of method selectors
10
8
  class SelectorSet
11
9
  def initialize(selectors)
12
- @selectors = selectors
10
+ @selectors = selectors.freeze
11
+ freeze
13
12
  end
14
13
 
15
14
  def ==(other)
@@ -29,7 +28,7 @@ module RuboCop
29
28
  end
30
29
 
31
30
  def block_pass_pattern
32
- "(send #{RSPEC} #{node_pattern_union} _ block_pass)"
31
+ "(send #rspec? #{node_pattern_union} _ block_pass)"
33
32
  end
34
33
 
35
34
  def block_or_block_pass_pattern
@@ -37,7 +36,11 @@ module RuboCop
37
36
  end
38
37
 
39
38
  def send_pattern
40
- "(send #{RSPEC} #{node_pattern_union} ...)"
39
+ "(send #rspec? #{node_pattern_union} ...)"
40
+ end
41
+
42
+ def send_or_block_or_block_pass_pattern
43
+ "{#{send_pattern} #{block_pattern} #{block_pass_pattern}}"
41
44
  end
42
45
 
43
46
  def node_pattern_union
@@ -48,6 +51,10 @@ module RuboCop
48
51
  selectors.map(&:inspect).join(' ')
49
52
  end
50
53
 
54
+ def to_a
55
+ selectors
56
+ end
57
+
51
58
  protected
52
59
 
53
60
  attr_reader :selectors
@@ -7,6 +7,8 @@ module RuboCop
7
7
  module NodePattern
8
8
  extend RuboCop::NodePattern::Macros
9
9
 
10
+ def_node_matcher :rspec?, '{(const {nil? cbase} :RSpec) nil?}'
11
+
10
12
  def_node_matcher :example_group?, ExampleGroups::ALL.block_pattern
11
13
  def_node_matcher :shared_group?, SharedGroups::ALL.block_pattern
12
14
 
@@ -14,7 +16,7 @@ module RuboCop
14
16
  def_node_matcher :spec_group?, spec_groups.block_pattern
15
17
 
16
18
  def_node_matcher :example_group_with_body?, <<-PATTERN
17
- (block #{ExampleGroups::ALL.send_pattern} args [!nil?])
19
+ (block #{ExampleGroups::ALL.send_pattern} args !nil?)
18
20
  PATTERN
19
21
 
20
22
  def_node_matcher :example?, Examples::ALL.block_pattern
@@ -23,6 +25,9 @@ module RuboCop
23
25
 
24
26
  def_node_matcher :let?, Helpers::ALL.block_or_block_pass_pattern
25
27
 
28
+ def_node_matcher :include?,
29
+ Includes::ALL.send_or_block_or_block_pass_pattern
30
+
26
31
  def_node_matcher :subject?, Subject::ALL.block_pattern
27
32
  end
28
33
  end
@@ -16,7 +16,7 @@ module RuboCop
16
16
  private
17
17
 
18
18
  def top_level_describe?(node)
19
- return false unless node.method_name == :describe
19
+ return false unless node.method?(:describe)
20
20
 
21
21
  top_level_nodes.include?(node)
22
22
  end
@@ -44,7 +44,7 @@ module RuboCop
44
44
 
45
45
  def describe_statement_children(node)
46
46
  node.each_child_node(:send).select do |element|
47
- element.method_name == :describe
47
+ element.method?(:describe)
48
48
  end
49
49
  end
50
50
  end
@@ -10,29 +10,42 @@ module RuboCop
10
10
  def_node_matcher :example_or_shared_group?,
11
11
  (ExampleGroups::ALL + SharedGroups::ALL).block_pattern
12
12
 
13
- def on_block(node)
14
- return unless respond_to?(:on_top_level_group)
15
- return unless top_level_group?(node)
13
+ def on_new_investigation
14
+ super
16
15
 
17
- on_top_level_group(node)
16
+ return unless root_node
17
+
18
+ top_level_groups.each do |node|
19
+ on_top_level_example_group(node) if example_group?(node)
20
+ on_top_level_group(node)
21
+ end
22
+ end
23
+
24
+ def top_level_groups
25
+ @top_level_groups ||=
26
+ top_level_nodes(root_node).select { |n| example_or_shared_group?(n) }
18
27
  end
19
28
 
20
29
  private
21
30
 
31
+ # Dummy methods to be overridden in the consumer
32
+ def on_top_level_example_group(_node); end
33
+
34
+ def on_top_level_group(_node); end
35
+
22
36
  def top_level_group?(node)
23
37
  top_level_groups.include?(node)
24
38
  end
25
39
 
26
- def top_level_groups
27
- @top_level_groups ||=
28
- top_level_nodes.select { |n| example_or_shared_group?(n) }
29
- end
30
-
31
- def top_level_nodes
32
- if root_node.begin_type?
33
- root_node.children
40
+ def top_level_nodes(node)
41
+ if node.nil?
42
+ []
43
+ elsif node.begin_type?
44
+ node.children
45
+ elsif node.module_type? || node.class_type?
46
+ top_level_nodes(node.body)
34
47
  else
35
- [root_node]
48
+ [node]
36
49
  end
37
50
  end
38
51