rubocop-rspec 1.43.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -4
  3. data/README.md +4 -0
  4. data/config/default.yml +141 -25
  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 +1 -1
  9. data/lib/rubocop/cop/rspec/base.rb +7 -54
  10. data/lib/rubocop/cop/rspec/be.rb +1 -1
  11. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +2 -2
  12. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +3 -2
  13. data/lib/rubocop/cop/rspec/describe_class.rb +33 -14
  14. data/lib/rubocop/cop/rspec/describe_method.rb +1 -1
  15. data/lib/rubocop/cop/rspec/described_class.rb +1 -2
  16. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -2
  17. data/lib/rubocop/cop/rspec/dialect.rb +1 -1
  18. data/lib/rubocop/cop/rspec/empty_example_group.rb +33 -38
  19. data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
  20. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +1 -1
  21. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
  22. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +1 -1
  23. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +1 -1
  24. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -2
  25. data/lib/rubocop/cop/rspec/expect_actual.rb +1 -1
  26. data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
  27. data/lib/rubocop/cop/rspec/file_path.rb +2 -2
  28. data/lib/rubocop/cop/rspec/focus.rb +13 -7
  29. data/lib/rubocop/cop/rspec/hook_argument.rb +2 -4
  30. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +2 -2
  31. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -2
  32. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
  33. data/lib/rubocop/cop/rspec/instance_variable.rb +1 -1
  34. data/lib/rubocop/cop/rspec/leading_subject.rb +5 -1
  35. data/lib/rubocop/cop/rspec/let_before_examples.rb +2 -2
  36. data/lib/rubocop/cop/rspec/let_setup.rb +7 -4
  37. data/lib/rubocop/cop/rspec/message_spies.rb +1 -1
  38. data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +51 -0
  39. data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
  40. data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
  41. data/lib/rubocop/cop/rspec/mixin/variable.rb +20 -0
  42. data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
  43. data/lib/rubocop/cop/rspec/multiple_expectations.rb +1 -1
  44. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +3 -1
  45. data/lib/rubocop/cop/rspec/named_subject.rb +8 -12
  46. data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
  47. data/lib/rubocop/cop/rspec/overwriting_setup.rb +2 -1
  48. data/lib/rubocop/cop/rspec/pending.rb +13 -5
  49. data/lib/rubocop/cop/rspec/predicate_matcher.rb +3 -3
  50. data/lib/rubocop/cop/rspec/repeated_include_example.rb +104 -0
  51. data/lib/rubocop/cop/rspec/shared_context.rb +16 -6
  52. data/lib/rubocop/cop/rspec/shared_examples.rb +3 -1
  53. data/lib/rubocop/cop/rspec/stubbed_mock.rb +172 -0
  54. data/lib/rubocop/cop/rspec/subject_stub.rb +6 -6
  55. data/lib/rubocop/cop/rspec/variable_definition.rb +1 -1
  56. data/lib/rubocop/cop/rspec/variable_name.rb +1 -1
  57. data/lib/rubocop/cop/rspec_cops.rb +2 -1
  58. data/lib/rubocop/rspec/align_let_brace.rb +1 -1
  59. data/lib/rubocop/rspec/concept.rb +2 -2
  60. data/lib/rubocop/rspec/config_formatter.rb +3 -3
  61. data/lib/rubocop/rspec/corrector/move_node.rb +1 -1
  62. data/lib/rubocop/rspec/example_group.rb +15 -5
  63. data/lib/rubocop/rspec/hook.rb +2 -6
  64. data/lib/rubocop/rspec/inject.rb +4 -2
  65. data/lib/rubocop/rspec/language.rb +144 -105
  66. data/lib/rubocop/rspec/language/node_pattern.rb +7 -24
  67. data/lib/rubocop/rspec/version.rb +1 -1
  68. metadata +25 -13
  69. data/lib/rubocop/cop/rspec/cop.rb +0 -10
  70. data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +0 -41
  71. data/lib/rubocop/rspec.rb +0 -12
  72. data/lib/rubocop/rspec/empty_line_separation.rb +0 -48
  73. data/lib/rubocop/rspec/final_end_location.rb +0 -17
  74. data/lib/rubocop/rspec/top_level_describe.rb +0 -52
  75. data/lib/rubocop/rspec/top_level_group.rb +0 -57
  76. data/lib/rubocop/rspec/variable.rb +0 -16
@@ -59,14 +59,24 @@ module RuboCop
59
59
  MSG_CONTEXT = "Use `shared_context` when you don't "\
60
60
  'define examples.'
61
61
 
62
- examples = (Examples::ALL + Includes::EXAMPLES)
63
- def_node_search :examples?, examples.send_pattern
62
+ def_node_search :examples?,
63
+ send_pattern('{#Includes.examples #Examples.all}')
64
64
 
65
- context = (Hooks::ALL + Helpers::ALL + Includes::CONTEXT + Subject::ALL)
66
- def_node_search :context?, context.send_pattern
65
+ def_node_search :context?, <<-PATTERN
66
+ (
67
+ send #rspec? {
68
+ #Subjects.all
69
+ #Helpers.all
70
+ #Includes.context
71
+ #Hooks.all
72
+ } ...
73
+ )
74
+ PATTERN
67
75
 
68
- def_node_matcher :shared_context, SharedGroups::CONTEXT.block_pattern
69
- def_node_matcher :shared_example, SharedGroups::EXAMPLES.block_pattern
76
+ def_node_matcher :shared_context,
77
+ block_pattern('#SharedGroups.context')
78
+ def_node_matcher :shared_example,
79
+ block_pattern('#SharedGroups.examples')
70
80
 
71
81
  def on_block(node)
72
82
  context_with_only_examples(node) do
@@ -24,7 +24,9 @@ module RuboCop
24
24
  extend AutoCorrector
25
25
 
26
26
  def_node_matcher :shared_examples,
27
- (SharedGroups::ALL + Includes::ALL).send_pattern
27
+ send_pattern(
28
+ '{#SharedGroups.all #Includes.all}'
29
+ )
28
30
 
29
31
  def on_send(node)
30
32
  shared_examples(node) do
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks that message expectations do not have a configured response.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # expect(foo).to receive(:bar).with(42).and_return("hello world")
12
+ #
13
+ # # good (without spies)
14
+ # allow(foo).to receive(:bar).with(42).and_return("hello world")
15
+ # expect(foo).to receive(:bar).with(42)
16
+ #
17
+ class StubbedMock < Base
18
+ MSG = 'Prefer `%<replacement>s` over `%<method_name>s` when ' \
19
+ 'configuring a response.'
20
+
21
+ # @!method message_expectation?(node)
22
+ # Match message expectation matcher
23
+ #
24
+ # @example source that matches
25
+ # receive(:foo)
26
+ #
27
+ # @example source that matches
28
+ # receive_message_chain(:foo, :bar)
29
+ #
30
+ # @example source that matches
31
+ # receive(:foo).with('bar')
32
+ #
33
+ # @param node [RuboCop::AST::Node]
34
+ # @return [Array<RuboCop::AST::Node>] matching nodes
35
+ def_node_matcher :message_expectation?, <<-PATTERN
36
+ {
37
+ (send nil? { :receive :receive_message_chain } ...) # receive(:foo)
38
+ (send (send nil? :receive ...) :with ...) # receive(:foo).with('bar')
39
+ }
40
+ PATTERN
41
+
42
+ def_node_matcher :configured_response?, <<~PATTERN
43
+ { :and_return :and_raise :and_throw :and_yield
44
+ :and_call_original :and_wrap_original }
45
+ PATTERN
46
+
47
+ # @!method expectation(node)
48
+ # Match expectation
49
+ #
50
+ # @example source that matches
51
+ # is_expected.to be_in_the_bar
52
+ #
53
+ # @example source that matches
54
+ # expect(cocktail).to contain_exactly(:fresh_orange_juice, :campari)
55
+ #
56
+ # @example source that matches
57
+ # expect_any_instance_of(Officer).to be_alert
58
+ #
59
+ # @param node [RuboCop::AST::Node]
60
+ # @yield [RuboCop::AST::Node] expectation, method name, matcher
61
+ def_node_matcher :expectation, <<~PATTERN
62
+ (send
63
+ $(send nil? $#Expectations.all ...)
64
+ :to $_)
65
+ PATTERN
66
+
67
+ # @!method matcher_with_configured_response(node)
68
+ # Match matcher with a configured response
69
+ #
70
+ # @example source that matches
71
+ # receive(:foo).and_return('bar')
72
+ #
73
+ # @example source that matches
74
+ # receive(:lower).and_raise(SomeError)
75
+ #
76
+ # @example source that matches
77
+ # receive(:redirect).and_call_original
78
+ #
79
+ # @param node [RuboCop::AST::Node]
80
+ # @yield [RuboCop::AST::Node] matcher
81
+ def_node_matcher :matcher_with_configured_response, <<~PATTERN
82
+ (send #message_expectation? #configured_response? _)
83
+ PATTERN
84
+
85
+ # @!method matcher_with_return_block(node)
86
+ # Match matcher with a return block
87
+ #
88
+ # @example source that matches
89
+ # receive(:foo) { 'bar' }
90
+ #
91
+ # @param node [RuboCop::AST::Node]
92
+ # @yield [RuboCop::AST::Node] matcher
93
+ def_node_matcher :matcher_with_return_block, <<~PATTERN
94
+ (block #message_expectation? args _) # receive(:foo) { 'bar' }
95
+ PATTERN
96
+
97
+ # @!method matcher_with_hash(node)
98
+ # Match matcher with a configured response defined as a hash
99
+ #
100
+ # @example source that matches
101
+ # receive_messages(foo: 'bar', baz: 'qux')
102
+ #
103
+ # @example source that matches
104
+ # receive_message_chain(:foo, bar: 'baz')
105
+ #
106
+ # @param node [RuboCop::AST::Node]
107
+ # @yield [RuboCop::AST::Node] matcher
108
+ def_node_matcher :matcher_with_hash, <<~PATTERN
109
+ {
110
+ (send nil? :receive_messages hash) # receive_messages(foo: 'bar', baz: 'qux')
111
+ (send nil? :receive_message_chain ... hash) # receive_message_chain(:foo, bar: 'baz')
112
+ }
113
+ PATTERN
114
+
115
+ # @!method matcher_with_blockpass(node)
116
+ # Match matcher with a configured response in block-pass
117
+ #
118
+ # @example source that matches
119
+ # receive(:foo, &canned)
120
+ #
121
+ # @example source that matches
122
+ # receive_message_chain(:foo, :bar, &canned)
123
+ #
124
+ # @example source that matches
125
+ # receive(:foo).with('bar', &canned)
126
+ #
127
+ # @param node [RuboCop::AST::Node]
128
+ # @yield [RuboCop::AST::Node] matcher
129
+ def_node_matcher :matcher_with_blockpass, <<~PATTERN
130
+ {
131
+ (send nil? { :receive :receive_message_chain } ... block_pass) # receive(:foo, &canned)
132
+ (send (send nil? :receive ...) :with ... block_pass) # receive(:foo).with('foo', &canned)
133
+ }
134
+ PATTERN
135
+
136
+ def on_send(node)
137
+ expectation(node, &method(:on_expectation))
138
+ end
139
+
140
+ private
141
+
142
+ def on_expectation(expectation, method_name, matcher)
143
+ flag_expectation = lambda do
144
+ add_offense(expectation, message: msg(method_name))
145
+ end
146
+
147
+ matcher_with_configured_response(matcher, &flag_expectation)
148
+ matcher_with_return_block(matcher, &flag_expectation)
149
+ matcher_with_hash(matcher, &flag_expectation)
150
+ matcher_with_blockpass(matcher, &flag_expectation)
151
+ end
152
+
153
+ def msg(method_name)
154
+ format(MSG,
155
+ method_name: method_name,
156
+ replacement: replacement(method_name))
157
+ end
158
+
159
+ def replacement(method_name)
160
+ case method_name
161
+ when :expect
162
+ :allow
163
+ when :is_expected
164
+ 'allow(subject)'
165
+ when :expect_any_instance_of
166
+ :allow_any_instance_of
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -22,7 +22,7 @@ module RuboCop
22
22
  # end
23
23
  #
24
24
  class SubjectStub < Base
25
- include RuboCop::RSpec::TopLevelGroup
25
+ include TopLevelGroup
26
26
 
27
27
  MSG = 'Do not stub methods of the object under test.'
28
28
 
@@ -43,10 +43,10 @@ module RuboCop
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)
@@ -66,7 +66,7 @@ module RuboCop
66
66
  (send nil? { :expect :allow } (send nil? {% :subject}))
67
67
  (send nil? :is_expected)
68
68
  }
69
- #{Runners::ALL.node_pattern_union}
69
+ #Runners.all
70
70
  #message_expectation_matcher?
71
71
  )
72
72
  PATTERN
@@ -24,7 +24,7 @@ module RuboCop
24
24
  # let('user_name') { 'Adam' }
25
25
  class VariableDefinition < Base
26
26
  include ConfigurableEnforcedStyle
27
- include RuboCop::RSpec::Variable
27
+ include Variable
28
28
 
29
29
  MSG = 'Use %<style>s for variable names.'
30
30
 
@@ -42,7 +42,7 @@ module RuboCop
42
42
  class VariableName < Base
43
43
  include ConfigurableNaming
44
44
  include IgnoredPattern
45
- include RuboCop::RSpec::Variable
45
+ include Variable
46
46
 
47
47
  MSG = 'Use %<style>s for variable names.'
48
48
 
@@ -52,7 +52,6 @@ require_relative 'rspec/implicit_expect'
52
52
  require_relative 'rspec/implicit_subject'
53
53
  require_relative 'rspec/instance_spy'
54
54
  require_relative 'rspec/instance_variable'
55
- require_relative 'rspec/invalid_predicate_matcher'
56
55
  require_relative 'rspec/it_behaves_like'
57
56
  require_relative 'rspec/iterated_expectation'
58
57
  require_relative 'rspec/leading_subject'
@@ -79,12 +78,14 @@ require_relative 'rspec/repeated_description'
79
78
  require_relative 'rspec/repeated_example'
80
79
  require_relative 'rspec/repeated_example_group_body'
81
80
  require_relative 'rspec/repeated_example_group_description'
81
+ require_relative 'rspec/repeated_include_example'
82
82
  require_relative 'rspec/return_from_stub'
83
83
  require_relative 'rspec/scattered_let'
84
84
  require_relative 'rspec/scattered_setup'
85
85
  require_relative 'rspec/shared_context'
86
86
  require_relative 'rspec/shared_examples'
87
87
  require_relative 'rspec/single_argument_message_chain'
88
+ require_relative 'rspec/stubbed_mock'
88
89
  require_relative 'rspec/subject_stub'
89
90
  require_relative 'rspec/unspecified_exception'
90
91
  require_relative 'rspec/variable_definition'
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Shared behavior for aligning braces for single line lets
6
6
  class AlignLetBrace
7
- include RuboCop::RSpec::Language::NodePattern
7
+ include RuboCop::RSpec::Language
8
8
 
9
9
  def initialize(root, token)
10
10
  @root = root
@@ -4,9 +4,9 @@ module RuboCop
4
4
  module RSpec
5
5
  # Wrapper for RSpec DSL methods
6
6
  class Concept
7
+ extend RuboCop::NodePattern::Macros
8
+ extend Language::NodePattern
7
9
  include Language
8
- include Language::NodePattern
9
- extend NodePattern::Macros
10
10
 
11
11
  def initialize(node)
12
12
  @node = node
@@ -6,7 +6,7 @@ module RuboCop
6
6
  module RSpec
7
7
  # Builds a YAML config file from two config hashes
8
8
  class ConfigFormatter
9
- NAMESPACES = /^(RSpec|Capybara|FactoryBot|Rails)/.freeze
9
+ EXTENSION_ROOT_DEPARTMENT = %r{^(RSpec/)}.freeze
10
10
  STYLE_GUIDE_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/'
11
11
 
12
12
  def initialize(config, descriptions)
@@ -15,7 +15,7 @@ module RuboCop
15
15
  end
16
16
 
17
17
  def dump
18
- YAML.dump(unified_config).gsub(NAMESPACES, "\n\\1")
18
+ YAML.dump(unified_config).gsub(EXTENSION_ROOT_DEPARTMENT, "\n\\1")
19
19
  end
20
20
 
21
21
  private
@@ -29,7 +29,7 @@ module RuboCop
29
29
  end
30
30
 
31
31
  def cops
32
- (descriptions.keys | config.keys).grep(NAMESPACES)
32
+ (descriptions.keys | config.keys).grep(EXTENSION_ROOT_DEPARTMENT)
33
33
  end
34
34
 
35
35
  attr_reader :config, :descriptions
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Helper methods to move a node
7
7
  class MoveNode
8
8
  include RuboCop::Cop::RangeHelp
9
- include RuboCop::RSpec::FinalEndLocation
9
+ include RuboCop::Cop::RSpec::FinalEndLocation
10
10
 
11
11
  attr_reader :original, :corrector, :processed_source
12
12
 
@@ -10,9 +10,14 @@ module RuboCop
10
10
  #
11
11
  # Selectors which indicate that we should stop searching
12
12
  #
13
- def_node_matcher :scope_change?, (
14
- ExampleGroups::ALL + SharedGroups::ALL + Includes::ALL
15
- ).block_pattern
13
+ def_node_matcher :scope_change?,
14
+ block_pattern(<<~PATTERN)
15
+ {
16
+ #SharedGroups.all
17
+ #ExampleGroups.all
18
+ #Includes.all
19
+ }
20
+ PATTERN
16
21
 
17
22
  def lets
18
23
  find_all_in_scope(node, :let?)
@@ -23,11 +28,15 @@ module RuboCop
23
28
  end
24
29
 
25
30
  def examples
26
- find_all_in_scope(node, :example?).map(&Example.public_method(:new))
31
+ find_all_in_scope(node, :example?).map do |node|
32
+ Example.new(node)
33
+ end
27
34
  end
28
35
 
29
36
  def hooks
30
- find_all_in_scope(node, :hook?).map(&Hook.public_method(:new))
37
+ find_all_in_scope(node, :hook?).map do |node|
38
+ Hook.new(node)
39
+ end
31
40
  end
32
41
 
33
42
  private
@@ -37,6 +46,7 @@ module RuboCop
37
46
  # Searches node and halts when a scope change is detected
38
47
  #
39
48
  # @param node [RuboCop::AST::Node] node to recursively search
49
+ # @param predicate [Symbol] method to call with node as argument
40
50
  #
41
51
  # @return [Array<RuboCop::AST::Node>] discovered nodes
42
52
  def find_all_in_scope(node, 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
 
@@ -48,7 +44,7 @@ module RuboCop
48
44
  private
49
45
 
50
46
  def valid_scope?(node)
51
- node&.sym_type? && Hooks::Scopes::ALL.include?(node.value)
47
+ node&.sym_type? && Language::HookScopes.all(node.value)
52
48
  end
53
49
 
54
50
  def transform_metadata(meta)
@@ -6,9 +6,11 @@ module RuboCop
6
6
  # bit of our configuration.
7
7
  module Inject
8
8
  def self.defaults!
9
- path = CONFIG_DEFAULT.to_s
9
+ project_root = Pathname.new(__dir__).parent.parent.parent.expand_path
10
+ config_default = project_root.join('config', 'default.yml')
11
+ path = config_default.to_s
10
12
  hash = ConfigLoader.send(:load_yaml_configuration, path)
11
- config = Config.new(hash, path)
13
+ config = RuboCop::Config.new(hash, path)
12
14
  puts "configuration from #{path}" if ConfigLoader.debug?
13
15
  config = ConfigLoader.merge_with_default(config, path)
14
16
  ConfigLoader.instance_variable_set(:@default_configuration, config)
@@ -2,147 +2,186 @@
2
2
 
3
3
  module RuboCop
4
4
  module RSpec
5
- # RSpec public API methods that are commonly used in cops
5
+ # Contains node matchers for common RSpec DSL.
6
+ #
7
+ # RSpec allows for configuring aliases for commonly used DSL elements, e.g.
8
+ # example groups and hooks. It is possible to configure RuboCop RSpec to
9
+ # be able to properly detect these elements in the `RSpec/Language` section
10
+ # of the RuboCop YAML configuration file.
11
+ #
12
+ # In addition to providing useful matchers, this class is responsible for
13
+ # using the configured aliases.
6
14
  module Language
7
- # Set of method selectors
8
- class SelectorSet
9
- def initialize(selectors)
10
- @selectors = selectors
11
- end
15
+ extend RuboCop::NodePattern::Macros
16
+ extend NodePattern
12
17
 
13
- def ==(other)
14
- selectors.eql?(other.selectors)
15
- end
18
+ class << self
19
+ attr_accessor :config
20
+ end
16
21
 
17
- def +(other)
18
- self.class.new(selectors + other.selectors)
19
- end
22
+ def_node_matcher :rspec?, '{(const {nil? cbase} :RSpec) nil?}'
20
23
 
21
- def include?(selector)
22
- selectors.include?(selector)
23
- end
24
+ def_node_matcher :example_group?, block_pattern('#ExampleGroups.all')
24
25
 
25
- def block_pattern
26
- "(block #{send_pattern} ...)"
27
- end
26
+ def_node_matcher :shared_group?, block_pattern('#SharedGroups.all')
28
27
 
29
- def block_pass_pattern
30
- "(send #rspec? #{node_pattern_union} _ block_pass)"
31
- end
28
+ def_node_matcher :spec_group?,
29
+ block_pattern('{#SharedGroups.all #ExampleGroups.all}')
32
30
 
33
- def block_or_block_pass_pattern
34
- "{#{block_pattern} #{block_pass_pattern}}"
35
- end
31
+ def_node_matcher :example_group_with_body?, <<-PATTERN
32
+ (block #{send_pattern('#ExampleGroups.all')} args !nil?)
33
+ PATTERN
36
34
 
37
- def send_pattern
38
- "(send #rspec? #{node_pattern_union} ...)"
39
- end
35
+ def_node_matcher :example?, block_pattern('#Examples.all')
40
36
 
41
- def send_or_block_or_block_pass_pattern
42
- "{#{send_pattern} #{block_pattern} #{block_pass_pattern}}"
43
- end
37
+ def_node_matcher :hook?, block_pattern('#Hooks.all')
44
38
 
45
- def node_pattern_union
46
- "{#{node_pattern}}"
47
- end
39
+ def_node_matcher :let?, <<-PATTERN
40
+ {
41
+ #{block_pattern('#Helpers.all')}
42
+ (send #rspec? #Helpers.all _ block_pass)
43
+ }
44
+ PATTERN
48
45
 
49
- def node_pattern
50
- selectors.map(&:inspect).join(' ')
51
- end
46
+ def_node_matcher :include?, <<-PATTERN
47
+ {
48
+ #{send_pattern('#Includes.all')}
49
+ #{block_pattern('#Includes.all')}
50
+ }
51
+ PATTERN
52
52
 
53
- protected
53
+ def_node_matcher :subject?, block_pattern('#Subjects.all')
54
54
 
55
- attr_reader :selectors
56
- end
55
+ module ExampleGroups # :nodoc:
56
+ class << self
57
+ def all(element)
58
+ regular(element) ||
59
+ skipped(element) ||
60
+ focused(element)
61
+ end
62
+
63
+ def regular(element)
64
+ Language.config['ExampleGroups']['Regular'].include?(element.to_s)
65
+ end
57
66
 
58
- module ExampleGroups
59
- GROUPS = SelectorSet.new(%i[describe context feature example_group])
60
- SKIPPED = SelectorSet.new(%i[xdescribe xcontext xfeature])
61
- FOCUSED = SelectorSet.new(%i[fdescribe fcontext ffeature])
67
+ def focused(element)
68
+ Language.config['ExampleGroups']['Focused'].include?(element.to_s)
69
+ end
62
70
 
63
- ALL = GROUPS + SKIPPED + FOCUSED
71
+ def skipped(element)
72
+ Language.config['ExampleGroups']['Skipped'].include?(element.to_s)
73
+ end
74
+ end
64
75
  end
65
76
 
66
- module SharedGroups
67
- EXAMPLES = SelectorSet.new(%i[shared_examples shared_examples_for])
68
- CONTEXT = SelectorSet.new(%i[shared_context])
77
+ module Examples # :nodoc:
78
+ class << self
79
+ def all(element)
80
+ regular(element) ||
81
+ focused(element) ||
82
+ skipped(element) ||
83
+ pending(element)
84
+ end
85
+
86
+ def regular(element)
87
+ Language.config['Examples']['Regular'].include?(element.to_s)
88
+ end
89
+
90
+ def focused(element)
91
+ Language.config['Examples']['Focused'].include?(element.to_s)
92
+ end
93
+
94
+ def skipped(element)
95
+ Language.config['Examples']['Skipped'].include?(element.to_s)
96
+ end
97
+
98
+ def pending(element)
99
+ Language.config['Examples']['Pending'].include?(element.to_s)
100
+ end
101
+ end
102
+ end
69
103
 
70
- ALL = EXAMPLES + CONTEXT
104
+ module Expectations # :nodoc:
105
+ def self.all(element)
106
+ Language.config['Expectations'].include?(element.to_s)
107
+ end
71
108
  end
72
109
 
73
- module Includes
74
- EXAMPLES = SelectorSet.new(
75
- %i[
76
- it_behaves_like
77
- it_should_behave_like
78
- include_examples
79
- ]
80
- )
81
- CONTEXT = SelectorSet.new(%i[include_context])
82
-
83
- ALL = EXAMPLES + CONTEXT
110
+ module Helpers # :nodoc:
111
+ def self.all(element)
112
+ Language.config['Helpers'].include?(element.to_s)
113
+ end
84
114
  end
85
115
 
86
- module Examples
87
- EXAMPLES = SelectorSet.new(%i[it specify example scenario its])
88
- FOCUSED = SelectorSet.new(%i[fit fspecify fexample fscenario focus])
89
- SKIPPED = SelectorSet.new(%i[xit xspecify xexample xscenario skip])
90
- PENDING = SelectorSet.new(%i[pending])
116
+ module Hooks # :nodoc:
117
+ def self.all(element)
118
+ Language.config['Hooks'].include?(element.to_s)
119
+ end
120
+ end
91
121
 
92
- ALL = EXAMPLES + FOCUSED + SKIPPED + PENDING
122
+ module HookScopes # :nodoc:
123
+ def self.all(element)
124
+ Language.config['HookScopes'].include?(element.to_s)
125
+ end
93
126
  end
94
127
 
95
- module Hooks
96
- ALL = SelectorSet.new(
97
- %i[
98
- prepend_before
99
- before
100
- append_before
101
- around
102
- prepend_after
103
- after
104
- append_after
105
- ]
106
- )
107
-
108
- module Scopes
109
- ALL = SelectorSet.new(
110
- %i[
111
- each
112
- example
113
- context
114
- all
115
- suite
116
- ]
117
- )
128
+ module Includes # :nodoc:
129
+ class << self
130
+ def all(element)
131
+ examples(element) ||
132
+ context(element)
133
+ end
134
+
135
+ def examples(element)
136
+ Language.config['Includes']['Examples'].include?(element.to_s)
137
+ end
138
+
139
+ def context(element)
140
+ Language.config['Includes']['Context'].include?(element.to_s)
141
+ end
118
142
  end
119
143
  end
120
144
 
121
- module Helpers
122
- ALL = SelectorSet.new(%i[let let!])
145
+ module Runners # :nodoc:
146
+ def self.all(element)
147
+ Language.config['Runners'].include?(element.to_s)
148
+ end
123
149
  end
124
150
 
125
- module Subject
126
- ALL = SelectorSet.new(%i[subject subject!])
151
+ module SharedGroups # :nodoc:
152
+ class << self
153
+ def all(element)
154
+ examples(element) ||
155
+ context(element)
156
+ end
157
+
158
+ def examples(element)
159
+ Language.config['SharedGroups']['Examples'].include?(element.to_s)
160
+ end
161
+
162
+ def context(element)
163
+ Language.config['SharedGroups']['Context'].include?(element.to_s)
164
+ end
165
+ end
127
166
  end
128
167
 
129
- module Expectations
130
- ALL = SelectorSet.new(%i[expect is_expected expect_any_instance_of])
168
+ module Subjects # :nodoc:
169
+ def self.all(element)
170
+ Language.config['Subjects'].include?(element.to_s)
171
+ end
131
172
  end
132
173
 
133
- module Runners
134
- ALL = SelectorSet.new(%i[to to_not not_to])
174
+ # This is used in Dialect and DescribeClass cops to detect RSpec blocks.
175
+ module ALL # :nodoc:
176
+ def self.all(element)
177
+ [ExampleGroups, Examples, Expectations, Helpers, Hooks, Includes,
178
+ Runners, SharedGroups, Subjects]
179
+ .find { |concept| concept.all(element) }
180
+ end
135
181
  end
136
182
 
137
- ALL =
138
- ExampleGroups::ALL +
139
- SharedGroups::ALL +
140
- Examples::ALL +
141
- Hooks::ALL +
142
- Helpers::ALL +
143
- Subject::ALL +
144
- Expectations::ALL +
145
- Runners::ALL
183
+ private_constant :ExampleGroups, :Examples, :Expectations, :Hooks,
184
+ :Includes, :Runners, :SharedGroups, :ALL
146
185
  end
147
186
  end
148
187
  end