rubocop-rspec 1.43.1 → 2.0.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 (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