rubocop-rspec 1.43.2 → 2.0.1

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -4
  3. data/README.md +5 -1
  4. data/config/default.yml +183 -67
  5. data/lib/rubocop-rspec.rb +7 -8
  6. data/lib/rubocop/cop/rspec/align_left_let_brace.rb +7 -3
  7. data/lib/rubocop/cop/rspec/align_right_let_brace.rb +7 -3
  8. data/lib/rubocop/cop/rspec/around_block.rb +2 -2
  9. data/lib/rubocop/cop/rspec/base.rb +7 -54
  10. data/lib/rubocop/cop/rspec/be.rb +2 -2
  11. data/lib/rubocop/cop/rspec/before_after_all.rb +3 -3
  12. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +2 -2
  13. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +3 -2
  14. data/lib/rubocop/cop/rspec/describe_class.rb +34 -15
  15. data/lib/rubocop/cop/rspec/describe_method.rb +2 -2
  16. data/lib/rubocop/cop/rspec/described_class.rb +1 -2
  17. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -2
  18. data/lib/rubocop/cop/rspec/dialect.rb +1 -1
  19. data/lib/rubocop/cop/rspec/empty_example_group.rb +33 -38
  20. data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
  21. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +1 -1
  22. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
  23. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +1 -1
  24. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +1 -1
  25. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -2
  26. data/lib/rubocop/cop/rspec/expect_actual.rb +2 -1
  27. data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
  28. data/lib/rubocop/cop/rspec/expect_output.rb +1 -1
  29. data/lib/rubocop/cop/rspec/file_path.rb +1 -1
  30. data/lib/rubocop/cop/rspec/focus.rb +13 -7
  31. data/lib/rubocop/cop/rspec/hook_argument.rb +2 -4
  32. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +2 -2
  33. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -2
  34. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
  35. data/lib/rubocop/cop/rspec/instance_spy.rb +1 -1
  36. data/lib/rubocop/cop/rspec/instance_variable.rb +1 -1
  37. data/lib/rubocop/cop/rspec/it_behaves_like.rb +1 -1
  38. data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
  39. data/lib/rubocop/cop/rspec/let_before_examples.rb +2 -2
  40. data/lib/rubocop/cop/rspec/let_setup.rb +7 -4
  41. data/lib/rubocop/cop/rspec/message_spies.rb +3 -3
  42. data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +51 -0
  43. data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
  44. data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
  45. data/lib/rubocop/cop/rspec/mixin/variable.rb +20 -0
  46. data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -3
  47. data/lib/rubocop/cop/rspec/multiple_expectations.rb +1 -1
  48. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +3 -1
  49. data/lib/rubocop/cop/rspec/named_subject.rb +8 -12
  50. data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
  51. data/lib/rubocop/cop/rspec/overwriting_setup.rb +2 -1
  52. data/lib/rubocop/cop/rspec/pending.rb +13 -5
  53. data/lib/rubocop/cop/rspec/predicate_matcher.rb +3 -3
  54. data/lib/rubocop/cop/rspec/repeated_include_example.rb +104 -0
  55. data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
  56. data/lib/rubocop/cop/rspec/shared_context.rb +18 -11
  57. data/lib/rubocop/cop/rspec/shared_examples.rb +3 -1
  58. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +1 -1
  59. data/lib/rubocop/cop/rspec/stubbed_mock.rb +172 -0
  60. data/lib/rubocop/cop/rspec/subject_stub.rb +20 -10
  61. data/lib/rubocop/cop/rspec/variable_definition.rb +1 -1
  62. data/lib/rubocop/cop/rspec/variable_name.rb +1 -1
  63. data/lib/rubocop/cop/rspec_cops.rb +2 -1
  64. data/lib/rubocop/rspec/align_let_brace.rb +1 -1
  65. data/lib/rubocop/rspec/concept.rb +2 -2
  66. data/lib/rubocop/rspec/config_formatter.rb +5 -3
  67. data/lib/rubocop/rspec/corrector/move_node.rb +1 -1
  68. data/lib/rubocop/rspec/example_group.rb +15 -5
  69. data/lib/rubocop/rspec/hook.rb +2 -6
  70. data/lib/rubocop/rspec/inject.rb +4 -2
  71. data/lib/rubocop/rspec/language.rb +144 -105
  72. data/lib/rubocop/rspec/language/node_pattern.rb +7 -24
  73. data/lib/rubocop/rspec/node.rb +1 -1
  74. data/lib/rubocop/rspec/version.rb +1 -1
  75. metadata +25 -13
  76. data/lib/rubocop/cop/rspec/cop.rb +0 -10
  77. data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +0 -41
  78. data/lib/rubocop/rspec.rb +0 -12
  79. data/lib/rubocop/rspec/empty_line_separation.rb +0 -48
  80. data/lib/rubocop/rspec/final_end_location.rb +0 -17
  81. data/lib/rubocop/rspec/top_level_describe.rb +0 -52
  82. data/lib/rubocop/rspec/top_level_group.rb +0 -57
  83. data/lib/rubocop/rspec/variable.rb +0 -16
@@ -5,26 +5,25 @@ require 'yaml'
5
5
 
6
6
  require 'rubocop'
7
7
 
8
- require_relative 'rubocop/rspec'
9
8
  require_relative 'rubocop/rspec/version'
10
9
  require_relative 'rubocop/rspec/inject'
11
10
  require_relative 'rubocop/rspec/node'
12
- require_relative 'rubocop/rspec/top_level_describe'
13
11
  require_relative 'rubocop/rspec/wording'
14
- require_relative 'rubocop/rspec/language'
15
12
  require_relative 'rubocop/rspec/language/node_pattern'
16
- require_relative 'rubocop/rspec/top_level_group'
13
+ require_relative 'rubocop/rspec/language'
14
+
15
+ require_relative 'rubocop/cop/rspec/mixin/top_level_group'
16
+ require_relative 'rubocop/cop/rspec/mixin/variable'
17
+ require_relative 'rubocop/cop/rspec/mixin/final_end_location'
18
+ require_relative 'rubocop/cop/rspec/mixin/empty_line_separation'
19
+
17
20
  require_relative 'rubocop/rspec/concept'
18
21
  require_relative 'rubocop/rspec/example_group'
19
22
  require_relative 'rubocop/rspec/example'
20
23
  require_relative 'rubocop/rspec/hook'
21
- require_relative 'rubocop/rspec/variable'
22
24
  require_relative 'rubocop/cop/rspec/base'
23
- require_relative 'rubocop/cop/rspec/cop'
24
25
  require_relative 'rubocop/rspec/align_let_brace'
25
26
  require_relative 'rubocop/rspec/factory_bot'
26
- require_relative 'rubocop/rspec/final_end_location'
27
- require_relative 'rubocop/rspec/empty_line_separation'
28
27
  require_relative 'rubocop/rspec/corrector/move_node'
29
28
 
30
29
  RuboCop::RSpec::Inject.defaults!
@@ -27,11 +27,9 @@ module RuboCop
27
27
  end
28
28
 
29
29
  def on_new_investigation
30
+ super
30
31
  return if processed_source.blank?
31
32
 
32
- token_aligner =
33
- RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)
34
-
35
33
  token_aligner.offending_tokens.each do |let|
36
34
  add_offense(let.loc.begin) do |corrector|
37
35
  corrector.insert_before(
@@ -40,6 +38,12 @@ module RuboCop
40
38
  end
41
39
  end
42
40
  end
41
+
42
+ private
43
+
44
+ def token_aligner
45
+ RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)
46
+ end
43
47
  end
44
48
  end
45
49
  end
@@ -27,11 +27,9 @@ module RuboCop
27
27
  end
28
28
 
29
29
  def on_new_investigation
30
+ super
30
31
  return if processed_source.blank?
31
32
 
32
- token_aligner =
33
- RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)
34
-
35
33
  token_aligner.offending_tokens.each do |let|
36
34
  add_offense(let.loc.end) do |corrector|
37
35
  corrector.insert_before(
@@ -40,6 +38,12 @@ module RuboCop
40
38
  end
41
39
  end
42
40
  end
41
+
42
+ private
43
+
44
+ def token_aligner
45
+ RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)
46
+ end
43
47
  end
44
48
  end
45
49
  end
@@ -27,11 +27,11 @@ module RuboCop
27
27
  # end
28
28
  class AroundBlock < Base
29
29
  MSG_NO_ARG = 'Test object should be passed to around block.'
30
- MSG_UNUSED_ARG = 'You should call `%<arg>s.call` '\
30
+ MSG_UNUSED_ARG = 'You should call `%<arg>s.call` ' \
31
31
  'or `%<arg>s.run`.'
32
32
 
33
33
  def_node_matcher :hook, <<-PATTERN
34
- (block {(send nil? :around) (send nil? :around sym)} (args $...) ...)
34
+ (block (send nil? :around sym ?) (args $...) ...)
35
35
  PATTERN
36
36
 
37
37
  def_node_search :find_arg_usage, <<-PATTERN
@@ -4,69 +4,22 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  # @abstract parent class to RSpec cops
7
- #
8
- # The criteria for whether rubocop-rspec analyzes a certain ruby file
9
- # is configured via `AllCops/RSpec`. For example, if you want to
10
- # customize your project to scan all files within a `test/` directory
11
- # then you could add this to your configuration:
12
- #
13
- # @example configuring analyzed paths
14
- # # .rubocop.yml
15
- # # AllCops:
16
- # # RSpec:
17
- # # Patterns:
18
- # # - '_test.rb$'
19
- # # - '(?:^|/)test/'
20
7
  class Base < ::RuboCop::Cop::Base
21
8
  include RuboCop::RSpec::Language
22
- include RuboCop::RSpec::Language::NodePattern
9
+ extend RuboCop::RSpec::Language::NodePattern
23
10
 
24
- DEFAULT_CONFIGURATION =
25
- RuboCop::RSpec::CONFIG.fetch('AllCops').fetch('RSpec')
26
-
27
- DEFAULT_PATTERN_RE = Regexp.union(
28
- DEFAULT_CONFIGURATION.fetch('Patterns')
29
- .map(&Regexp.public_method(:new))
30
- )
11
+ exclude_from_registry
31
12
 
32
13
  # Invoke the original inherited hook so our cops are recognized
33
14
  def self.inherited(subclass) # rubocop:disable Lint/MissingSuper
34
15
  RuboCop::Cop::Base.inherited(subclass)
35
16
  end
36
17
 
37
- def relevant_file?(file)
38
- relevant_rubocop_rspec_file?(file) && super
39
- end
40
-
41
- private
42
-
43
- def relevant_rubocop_rspec_file?(file)
44
- rspec_pattern.match?(file)
45
- end
46
-
47
- def rspec_pattern
48
- if rspec_pattern_config?
49
- Regexp.union(rspec_pattern_config.map(&Regexp.public_method(:new)))
50
- else
51
- DEFAULT_PATTERN_RE
52
- end
53
- end
54
-
55
- def all_cops_config
56
- config
57
- .for_all_cops
58
- end
59
-
60
- def rspec_pattern_config?
61
- return unless all_cops_config.key?('RSpec')
62
-
63
- all_cops_config.fetch('RSpec').key?('Patterns')
64
- end
65
-
66
- def rspec_pattern_config
67
- all_cops_config
68
- .fetch('RSpec', DEFAULT_CONFIGURATION)
69
- .fetch('Patterns')
18
+ # Set the config for dynamic DSL configuration-aware helpers
19
+ # that have no other means of accessing the configuration.
20
+ def on_new_investigation
21
+ super
22
+ RuboCop::RSpec::Language.config = config['RSpec']['Language']
70
23
  end
71
24
  end
72
25
  end
@@ -20,10 +20,10 @@ module RuboCop
20
20
  # expect(foo).to be(true)
21
21
  #
22
22
  class Be < Base
23
- MSG = 'Don\'t use `be` without an argument.'
23
+ MSG = "Don't use `be` without an argument."
24
24
 
25
25
  def_node_matcher :be_without_args, <<-PATTERN
26
- (send _ #{Runners::ALL.node_pattern_union} $(send nil? :be))
26
+ (send _ #Runners.all $(send nil? :be))
27
27
  PATTERN
28
28
 
29
29
  def on_send(node)
@@ -24,9 +24,9 @@ module RuboCop
24
24
  # after(:each) { Widget.delete_all }
25
25
  # end
26
26
  class BeforeAfterAll < Base
27
- MSG = 'Beware of using `%<hook>s` as it may cause state to leak '\
28
- 'between tests. If you are using `rspec-rails`, and '\
29
- '`use_transactional_fixtures` is enabled, then records created '\
27
+ MSG = 'Beware of using `%<hook>s` as it may cause state to leak ' \
28
+ 'between tests. If you are using `rspec-rails`, and ' \
29
+ '`use_transactional_fixtures` is enabled, then records created ' \
30
30
  'in `%<hook>s` are not automatically rolled back.'
31
31
 
32
32
  def_node_matcher :before_or_after_all, <<-PATTERN
@@ -37,13 +37,13 @@ module RuboCop
37
37
  # Supported matchers: eq(...) / match(/regexp/) / match('regexp')
38
38
  def_node_matcher :as_is_matcher, <<-PATTERN
39
39
  (send
40
- #expectation_set_on_current_path $#{Runners::ALL.node_pattern_union}
40
+ #expectation_set_on_current_path $#Runners.all
41
41
  ${(send nil? :eq ...) (send nil? :match (regexp ...))})
42
42
  PATTERN
43
43
 
44
44
  def_node_matcher :regexp_str_matcher, <<-PATTERN
45
45
  (send
46
- #expectation_set_on_current_path $#{Runners::ALL.node_pattern_union}
46
+ #expectation_set_on_current_path $#Runners.all
47
47
  $(send nil? :match (str $_)))
48
48
  PATTERN
49
49
 
@@ -55,8 +55,9 @@ module RuboCop
55
55
  feature: :describe
56
56
  }.freeze
57
57
 
58
- def_node_matcher :capybara_speak,
59
- SelectorSet.new(MAP.keys).node_pattern_union
58
+ def_node_matcher :capybara_speak, <<-PATTERN
59
+ {#{MAP.keys.map(&:inspect).join(' ')}}
60
+ PATTERN
60
61
 
61
62
  def_node_matcher :spec?, <<-PATTERN
62
63
  (block
@@ -5,6 +5,19 @@ module RuboCop
5
5
  module RSpec
6
6
  # Check that the first argument to the top-level describe is a constant.
7
7
  #
8
+ # It can be configured to ignore strings when certain metadata is passed.
9
+ #
10
+ # Ignores Rails and Aruba `type` metadata by default.
11
+ #
12
+ # @example `IgnoredMetadata` configuration
13
+ #
14
+ # # .rubocop.yml
15
+ # # RSpec/DescribeClass:
16
+ # # IgnoredMetadata:
17
+ # # type:
18
+ # # - request
19
+ # # - controller
20
+ #
8
21
  # @example
9
22
  # # bad
10
23
  # describe 'Do something' do
@@ -22,41 +35,47 @@ module RuboCop
22
35
  # describe "A feature example", type: :feature do
23
36
  # end
24
37
  class DescribeClass < Base
25
- include RuboCop::RSpec::TopLevelGroup
38
+ include TopLevelGroup
26
39
 
27
- MSG = 'The first argument to describe should be '\
40
+ MSG = 'The first argument to describe should be ' \
28
41
  'the class or module being tested.'
29
42
 
30
- def_node_matcher :rails_metadata?, <<-PATTERN
31
- (pair
32
- (sym :type)
33
- (sym { :channel :controller :helper :job :mailer :model :request
34
- :routing :view :feature :system :mailbox })
35
- )
36
- PATTERN
37
-
38
- def_node_matcher :example_group_with_rails_metadata?, <<~PATTERN
39
- (send #rspec? :describe ... (hash <#rails_metadata? ...>))
43
+ def_node_matcher :example_group_with_ignored_metadata?, <<~PATTERN
44
+ (send #rspec? :describe ... (hash <#ignored_metadata? ...>))
40
45
  PATTERN
41
46
 
42
47
  def_node_matcher :not_a_const_described, <<~PATTERN
43
48
  (send #rspec? :describe $[!const !#string_constant?] ...)
44
49
  PATTERN
45
50
 
46
- def on_top_level_group(top_level_node)
47
- return if example_group_with_rails_metadata?(top_level_node.send_node)
51
+ def_node_matcher :sym_pair, <<~PATTERN
52
+ (pair $sym $sym)
53
+ PATTERN
48
54
 
49
- not_a_const_described(top_level_node.send_node) do |described|
55
+ def on_top_level_group(node)
56
+ return if example_group_with_ignored_metadata?(node.send_node)
57
+
58
+ not_a_const_described(node.send_node) do |described|
50
59
  add_offense(described)
51
60
  end
52
61
  end
53
62
 
54
63
  private
55
64
 
65
+ def ignored_metadata?(node)
66
+ sym_pair(node) do |key, value|
67
+ ignored_metadata[key.value.to_s].to_a.include?(value.value.to_s)
68
+ end
69
+ end
70
+
56
71
  def string_constant?(described)
57
72
  described.str_type? &&
58
73
  described.value.match?(/^(?:(?:::)?[A-Z]\w*)+$/)
59
74
  end
75
+
76
+ def ignored_metadata
77
+ cop_config['IgnoredMetadata'] || {}
78
+ end
60
79
  end
61
80
  end
62
81
  end
@@ -17,9 +17,9 @@ module RuboCop
17
17
  # describe MyClass, '.my_class_method' do
18
18
  # end
19
19
  class DescribeMethod < Base
20
- include RuboCop::RSpec::TopLevelGroup
20
+ include TopLevelGroup
21
21
 
22
- MSG = 'The second argument to describe should be the method '\
22
+ MSG = 'The second argument to describe should be the method ' \
23
23
  "being tested. '#instance' or '.class'."
24
24
 
25
25
  def_node_matcher :second_argument, <<~PATTERN
@@ -65,8 +65,7 @@ module RuboCop
65
65
  (block (send (const nil? {:Class :Module :Struct}) :new ...) ...)
66
66
  PATTERN
67
67
 
68
- def_node_matcher :rspec_block?,
69
- RuboCop::RSpec::Language::ALL.block_pattern
68
+ def_node_matcher :rspec_block?, block_pattern('#ALL.all')
70
69
 
71
70
  def_node_matcher :scope_changing_syntax?, '{def class module}'
72
71
 
@@ -22,8 +22,7 @@ module RuboCop
22
22
  class DescribedClassModuleWrapping < Base
23
23
  MSG = 'Avoid opening modules and defining specs within them.'
24
24
 
25
- def_node_search :find_rspec_blocks,
26
- ExampleGroups::ALL.block_pattern
25
+ def_node_search :find_rspec_blocks, block_pattern('#ExampleGroups.all')
27
26
 
28
27
  def on_module(node)
29
28
  find_rspec_blocks(node) do
@@ -47,7 +47,7 @@ module RuboCop
47
47
 
48
48
  MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
49
49
 
50
- def_node_matcher :rspec_method?, ALL.send_pattern
50
+ def_node_matcher :rspec_method?, send_pattern('#ALL.all')
51
51
 
52
52
  def on_send(node)
53
53
  return unless rspec_method?(node)
@@ -5,8 +5,6 @@ module RuboCop
5
5
  module RSpec
6
6
  # Checks if an example group does not include any tests.
7
7
  #
8
- # This cop is configurable using the `CustomIncludeMethods` option
9
- #
10
8
  # @example usage
11
9
  #
12
10
  # # bad
@@ -33,30 +31,10 @@ module RuboCop
33
31
  # end
34
32
  # end
35
33
  #
36
- # @example configuration
37
- #
38
- # # .rubocop.yml
39
- # # RSpec/EmptyExampleGroup:
40
- # # CustomIncludeMethods:
41
- # # - include_tests
42
- #
43
- # # spec_helper.rb
44
- # RSpec.configure do |config|
45
- # config.alias_it_behaves_like_to(:include_tests)
46
- # end
47
- #
48
- # # bacon_spec.rb
34
+ # # good
49
35
  # describe Bacon do
50
- # let(:bacon) { Bacon.new(chunkiness) }
51
- # let(:chunkiness) { false }
52
- #
53
- # context 'extra chunky' do # not flagged by rubocop
54
- # let(:chunkiness) { true }
55
- #
56
- # include_tests 'shared tests'
57
- # end
36
+ # pending 'will add tests later'
58
37
  # end
59
- #
60
38
  class EmptyExampleGroup < Base
61
39
  MSG = 'Empty example group detected.'
62
40
 
@@ -71,7 +49,7 @@ module RuboCop
71
49
  # @param node [RuboCop::AST::Node]
72
50
  # @yield [RuboCop::AST::Node] example group body
73
51
  def_node_matcher :example_group_body, <<~PATTERN
74
- (block #{ExampleGroups::ALL.send_pattern} args $_)
52
+ (block #{send_pattern('#ExampleGroups.all')} args $_)
75
53
  PATTERN
76
54
 
77
55
  # @!method example_or_group_or_include?(node)
@@ -83,16 +61,17 @@ module RuboCop
83
61
  # it_behaves_like 'an animal'
84
62
  # it_behaves_like('a cat') { let(:food) { 'milk' } }
85
63
  # it_has_root_access
64
+ # skip
65
+ # it 'will be implemented later'
86
66
  #
87
67
  # @param node [RuboCop::AST::Node]
88
68
  # @return [Array<RuboCop::AST::Node>] matching nodes
89
69
  def_node_matcher :example_or_group_or_include?, <<~PATTERN
90
70
  {
91
- #{Examples::ALL.block_pattern}
92
- #{ExampleGroups::ALL.block_pattern}
93
- #{Includes::ALL.send_pattern}
94
- #{Includes::ALL.block_pattern}
95
- (send nil? #custom_include? ...)
71
+ #{block_pattern(
72
+ '{#Examples.all #ExampleGroups.all #Includes.all}'
73
+ )}
74
+ #{send_pattern('{#Examples.all #Includes.all}')}
96
75
  }
97
76
  PATTERN
98
77
 
@@ -112,7 +91,7 @@ module RuboCop
112
91
  # @param node [RuboCop::AST::Node]
113
92
  # @return [Array<RuboCop::AST::Node>] matching nodes
114
93
  def_node_matcher :examples_inside_block?, <<~PATTERN
115
- (block !#{Hooks::ALL.send_pattern} _ #examples?)
94
+ (block !#{send_pattern('#Hooks.all')} _ #examples?)
116
95
  PATTERN
117
96
 
118
97
  # @!method examples_directly_or_in_block?(node)
@@ -152,21 +131,37 @@ module RuboCop
152
131
  PATTERN
153
132
 
154
133
  def on_block(node)
134
+ return if node.each_ancestor(:def, :defs).any?
135
+ return if node.each_ancestor(:block).any? { |block| example?(block) }
136
+
155
137
  example_group_body(node) do |body|
156
- add_offense(node.send_node) unless examples?(body)
138
+ add_offense(node.send_node) if offensive?(body)
157
139
  end
158
140
  end
159
141
 
160
142
  private
161
143
 
162
- def custom_include?(method_name)
163
- custom_include_methods.include?(method_name)
144
+ def offensive?(body)
145
+ return true unless body
146
+ return false if conditionals_with_examples?(body)
147
+
148
+ if body.if_type?
149
+ !examples_in_branches?(body)
150
+ else
151
+ !examples?(body)
152
+ end
153
+ end
154
+
155
+ def conditionals_with_examples?(body)
156
+ return unless body.begin_type?
157
+
158
+ body.each_descendant(:if).any? do |if_node|
159
+ examples_in_branches?(if_node)
160
+ end
164
161
  end
165
162
 
166
- def custom_include_methods
167
- cop_config
168
- .fetch('CustomIncludeMethods', [])
169
- .map(&:to_sym)
163
+ def examples_in_branches?(if_node)
164
+ if_node.branches.any? { |branch| examples?(branch) }
170
165
  end
171
166
  end
172
167
  end