rubocop-rspec 2.0.0.pre → 2.3.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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -2
  3. data/README.md +7 -3
  4. data/config/default.yml +159 -73
  5. data/lib/rubocop-rspec.rb +8 -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/any_instance.rb +6 -10
  9. data/lib/rubocop/cop/rspec/around_block.rb +3 -1
  10. data/lib/rubocop/cop/rspec/base.rb +6 -55
  11. data/lib/rubocop/cop/rspec/be.rb +3 -2
  12. data/lib/rubocop/cop/rspec/be_eql.rb +2 -0
  13. data/lib/rubocop/cop/rspec/before_after_all.rb +6 -3
  14. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +7 -2
  15. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +6 -2
  16. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +4 -0
  17. data/lib/rubocop/cop/rspec/context_method.rb +1 -0
  18. data/lib/rubocop/cop/rspec/context_wording.rb +7 -1
  19. data/lib/rubocop/cop/rspec/describe_class.rb +5 -2
  20. data/lib/rubocop/cop/rspec/describe_method.rb +3 -2
  21. data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -0
  22. data/lib/rubocop/cop/rspec/described_class.rb +6 -2
  23. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +3 -3
  24. data/lib/rubocop/cop/rspec/dialect.rb +2 -1
  25. data/lib/rubocop/cop/rspec/empty_example_group.rb +6 -45
  26. data/lib/rubocop/cop/rspec/empty_hook.rb +2 -1
  27. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +1 -1
  28. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
  29. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +1 -1
  30. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +1 -1
  31. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -2
  32. data/lib/rubocop/cop/rspec/example_length.rb +26 -12
  33. data/lib/rubocop/cop/rspec/example_without_description.rb +1 -0
  34. data/lib/rubocop/cop/rspec/example_wording.rb +1 -0
  35. data/lib/rubocop/cop/rspec/expect_actual.rb +3 -1
  36. data/lib/rubocop/cop/rspec/expect_change.rb +3 -0
  37. data/lib/rubocop/cop/rspec/expect_in_hook.rb +2 -1
  38. data/lib/rubocop/cop/rspec/expect_output.rb +1 -1
  39. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +3 -0
  40. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +4 -0
  41. data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +2 -0
  42. data/lib/rubocop/cop/rspec/file_path.rb +26 -17
  43. data/lib/rubocop/cop/rspec/focus.rb +46 -8
  44. data/lib/rubocop/cop/rspec/hook_argument.rb +4 -4
  45. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +3 -2
  46. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +4 -0
  47. data/lib/rubocop/cop/rspec/implicit_expect.rb +2 -1
  48. data/lib/rubocop/cop/rspec/implicit_subject.rb +2 -0
  49. data/lib/rubocop/cop/rspec/instance_spy.rb +3 -1
  50. data/lib/rubocop/cop/rspec/instance_variable.rb +5 -1
  51. data/lib/rubocop/cop/rspec/it_behaves_like.rb +3 -1
  52. data/lib/rubocop/cop/rspec/iterated_expectation.rb +3 -1
  53. data/lib/rubocop/cop/rspec/let_before_examples.rb +3 -2
  54. data/lib/rubocop/cop/rspec/let_setup.rb +10 -4
  55. data/lib/rubocop/cop/rspec/message_chain.rb +4 -10
  56. data/lib/rubocop/cop/rspec/message_expectation.rb +3 -0
  57. data/lib/rubocop/cop/rspec/message_spies.rb +5 -3
  58. data/lib/rubocop/cop/rspec/mixin/comments_help.rb +38 -0
  59. data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +51 -0
  60. data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
  61. data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
  62. data/lib/rubocop/cop/rspec/mixin/variable.rb +21 -0
  63. data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -3
  64. data/lib/rubocop/cop/rspec/multiple_expectations.rb +4 -1
  65. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +3 -1
  66. data/lib/rubocop/cop/rspec/named_subject.rb +11 -12
  67. data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
  68. data/lib/rubocop/cop/rspec/not_to_not.rb +2 -0
  69. data/lib/rubocop/cop/rspec/overwriting_setup.rb +4 -1
  70. data/lib/rubocop/cop/rspec/pending.rb +17 -5
  71. data/lib/rubocop/cop/rspec/predicate_matcher.rb +8 -3
  72. data/lib/rubocop/cop/rspec/rails/http_status.rb +2 -0
  73. data/lib/rubocop/cop/rspec/receive_counts.rb +4 -0
  74. data/lib/rubocop/cop/rspec/receive_never.rb +2 -0
  75. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +8 -1
  76. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +4 -0
  77. data/lib/rubocop/cop/rspec/repeated_include_example.rb +6 -2
  78. data/lib/rubocop/cop/rspec/return_from_stub.rb +6 -0
  79. data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
  80. data/lib/rubocop/cop/rspec/shared_context.rb +22 -11
  81. data/lib/rubocop/cop/rspec/shared_examples.rb +4 -1
  82. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +4 -1
  83. data/lib/rubocop/cop/rspec/stubbed_mock.rb +2 -1
  84. data/lib/rubocop/cop/rspec/subject_stub.rb +17 -6
  85. data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -0
  86. data/lib/rubocop/cop/rspec/variable_definition.rb +1 -1
  87. data/lib/rubocop/cop/rspec/variable_name.rb +1 -1
  88. data/lib/rubocop/cop/rspec/verified_doubles.rb +2 -0
  89. data/lib/rubocop/cop/rspec/void_expect.rb +3 -0
  90. data/lib/rubocop/cop/rspec/yield.rb +3 -0
  91. data/lib/rubocop/cop/rspec_cops.rb +0 -1
  92. data/lib/rubocop/rspec/align_let_brace.rb +1 -1
  93. data/lib/rubocop/rspec/concept.rb +2 -2
  94. data/lib/rubocop/rspec/config_formatter.rb +5 -3
  95. data/lib/rubocop/rspec/corrector/move_node.rb +7 -10
  96. data/lib/rubocop/rspec/example.rb +5 -0
  97. data/lib/rubocop/rspec/example_group.rb +15 -5
  98. data/lib/rubocop/rspec/hook.rb +2 -1
  99. data/lib/rubocop/rspec/inject.rb +4 -2
  100. data/lib/rubocop/rspec/language.rb +159 -115
  101. data/lib/rubocop/rspec/language/node_pattern.rb +7 -24
  102. data/lib/rubocop/rspec/node.rb +1 -1
  103. data/lib/rubocop/rspec/version.rb +1 -1
  104. metadata +27 -16
  105. data/lib/rubocop/cop/rspec/cop.rb +0 -10
  106. data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +0 -41
  107. data/lib/rubocop/rspec.rb +0 -12
  108. data/lib/rubocop/rspec/empty_line_separation.rb +0 -48
  109. data/lib/rubocop/rspec/final_end_location.rb +0 -17
  110. data/lib/rubocop/rspec/top_level_describe.rb +0 -52
  111. data/lib/rubocop/rspec/top_level_group.rb +0 -57
  112. data/lib/rubocop/rspec/variable.rb +0 -16
@@ -23,8 +23,11 @@ module RuboCop
23
23
  class SharedExamples < Base
24
24
  extend AutoCorrector
25
25
 
26
+ # @!method shared_examples(node)
26
27
  def_node_matcher :shared_examples,
27
- (SharedGroups::ALL + Includes::ALL).send_pattern
28
+ send_pattern(
29
+ '{#SharedGroups.all #Includes.all}'
30
+ )
28
31
 
29
32
  def on_send(node)
30
33
  shared_examples(node) do
@@ -19,13 +19,16 @@ module RuboCop
19
19
  class SingleArgumentMessageChain < Base
20
20
  extend AutoCorrector
21
21
 
22
- MSG = 'Use `%<recommended>s` instead of calling '\
22
+ MSG = 'Use `%<recommended>s` instead of calling ' \
23
23
  '`%<called>s` with a single argument.'
24
+ RESTRICT_ON_SEND = %i[receive_message_chain stub_chain].freeze
24
25
 
26
+ # @!method message_chain(node)
25
27
  def_node_matcher :message_chain, <<-PATTERN
26
28
  (send _ {:receive_message_chain :stub_chain} $_)
27
29
  PATTERN
28
30
 
31
+ # @!method single_key_hash?(node)
29
32
  def_node_matcher :single_key_hash?, '(hash pair)'
30
33
 
31
34
  def on_send(node)
@@ -39,6 +39,7 @@ module RuboCop
39
39
  }
40
40
  PATTERN
41
41
 
42
+ # @!method configured_response?(node)
42
43
  def_node_matcher :configured_response?, <<~PATTERN
43
44
  { :and_return :and_raise :and_throw :and_yield
44
45
  :and_call_original :and_wrap_original }
@@ -60,7 +61,7 @@ module RuboCop
60
61
  # @yield [RuboCop::AST::Node] expectation, method name, matcher
61
62
  def_node_matcher :expectation, <<~PATTERN
62
63
  (send
63
- $(send nil? $#{Expectations::ALL.node_pattern_union} ...)
64
+ $(send nil? $#Expectations.all ...)
64
65
  :to $_)
65
66
  PATTERN
66
67
 
@@ -13,16 +13,26 @@ module RuboCop
13
13
  #
14
14
  # @example
15
15
  # # bad
16
- # describe Foo do
17
- # subject(:bar) { baz }
16
+ # describe Article do
17
+ # subject(:article) { Article.new }
18
18
  #
19
- # before do
20
- # allow(bar).to receive(:qux?).and_return(true)
19
+ # it 'indicates that the author is unknown' do
20
+ # allow(article).to receive(:author).and_return(nil)
21
+ # expect(article.description).to include('by an unknown author')
22
+ # end
23
+ # end
24
+ #
25
+ # # good
26
+ # describe Article do
27
+ # subject(:article) { Article.new(author: nil) }
28
+ #
29
+ # it 'indicates that the author is unknown' do
30
+ # expect(article.description).to include('by an unknown author')
21
31
  # end
22
32
  # end
23
33
  #
24
34
  class SubjectStub < Base
25
- include RuboCop::RSpec::TopLevelGroup
35
+ include TopLevelGroup
26
36
 
27
37
  MSG = 'Do not stub methods of the object under test.'
28
38
 
@@ -66,11 +76,12 @@ module RuboCop
66
76
  (send nil? { :expect :allow } (send nil? {% :subject}))
67
77
  (send nil? :is_expected)
68
78
  }
69
- #{Runners::ALL.node_pattern_union}
79
+ #Runners.all
70
80
  #message_expectation_matcher?
71
81
  )
72
82
  PATTERN
73
83
 
84
+ # @!method message_expectation_matcher?(node)
74
85
  def_node_search :message_expectation_matcher?, <<-PATTERN
75
86
  (send nil? {
76
87
  :receive :receive_messages :receive_message_chain :have_received
@@ -32,7 +32,9 @@ module RuboCop
32
32
  # expect { do_something }.not_to raise_error
33
33
  class UnspecifiedException < Base
34
34
  MSG = 'Specify the exception being captured'
35
+ RESTRICT_ON_SEND = %i[to].freeze
35
36
 
37
+ # @!method empty_raise_error_or_exception(node)
36
38
  def_node_matcher :empty_raise_error_or_exception, <<-PATTERN
37
39
  (send
38
40
  (block
@@ -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
 
@@ -24,7 +24,9 @@ module RuboCop
24
24
  # end
25
25
  class VerifiedDoubles < Base
26
26
  MSG = 'Prefer using verifying doubles over normal doubles.'
27
+ RESTRICT_ON_SEND = %i[double spy].freeze
27
28
 
29
+ # @!method unverified_double(node)
28
30
  def_node_matcher :unverified_double, <<-PATTERN
29
31
  {(send nil? {:double :spy} $...)}
30
32
  PATTERN
@@ -14,11 +14,14 @@ module RuboCop
14
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
+ RESTRICT_ON_SEND = %i[expect].freeze
17
18
 
19
+ # @!method expect?(node)
18
20
  def_node_matcher :expect?, <<-PATTERN
19
21
  (send nil? :expect ...)
20
22
  PATTERN
21
23
 
24
+ # @!method expect_block?(node)
22
25
  def_node_matcher :expect_block?, <<-PATTERN
23
26
  (block #expect? (args) _body)
24
27
  PATTERN
@@ -17,10 +17,13 @@ module RuboCop
17
17
 
18
18
  MSG = 'Use `.and_yield`.'
19
19
 
20
+ # @!method method_on_stub?(node)
20
21
  def_node_search :method_on_stub?, '(send nil? :receive ...)'
21
22
 
23
+ # @!method block_arg(node)
22
24
  def_node_matcher :block_arg, '(args (blockarg $_))'
23
25
 
26
+ # @!method block_call?(node)
24
27
  def_node_matcher :block_call?, '(send (lvar %) :call ...)'
25
28
 
26
29
  def on_block(node)
@@ -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'
@@ -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,9 @@ 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)
19
+ .gsub(EXTENSION_ROOT_DEPARTMENT, "\n\\1")
20
+ .gsub(/^(\s+)- /, '\1 - ')
19
21
  end
20
22
 
21
23
  private
@@ -29,7 +31,7 @@ module RuboCop
29
31
  end
30
32
 
31
33
  def cops
32
- (descriptions.keys | config.keys).grep(NAMESPACES)
34
+ (descriptions.keys | config.keys).grep(EXTENSION_ROOT_DEPARTMENT)
33
35
  end
34
36
 
35
37
  attr_reader :config, :descriptions
@@ -6,7 +6,8 @@ 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::CommentsHelp
10
+ include RuboCop::Cop::RSpec::FinalEndLocation
10
11
 
11
12
  attr_reader :original, :corrector, :processed_source
12
13
 
@@ -17,20 +18,16 @@ module RuboCop
17
18
  end
18
19
 
19
20
  def move_before(other)
20
- position = other.loc.expression
21
- indent = ' ' * other.loc.column
22
- newline_indent = "\n#{indent}"
21
+ position = start_line_position(other)
23
22
 
24
- corrector.insert_before(position, source(original) + newline_indent)
23
+ corrector.insert_before(position, "#{source(original)}\n")
25
24
  corrector.remove(node_range_with_surrounding_space(original))
26
25
  end
27
26
 
28
27
  def move_after(other)
29
- position = final_end_location(other)
30
- indent = ' ' * other.loc.column
31
- newline_indent = "\n#{indent}"
28
+ position = end_line_position(other)
32
29
 
33
- corrector.insert_after(position, newline_indent + source(original))
30
+ corrector.insert_after(position, "\n#{source(original)}")
34
31
  corrector.remove(node_range_with_surrounding_space(original))
35
32
  end
36
33
 
@@ -41,7 +38,7 @@ module RuboCop
41
38
  end
42
39
 
43
40
  def node_range(node)
44
- node.loc.expression.with(end_pos: final_end_location(node).end_pos)
41
+ source_range_with_comment(node)
45
42
  end
46
43
 
47
44
  def node_range_with_surrounding_space(node)
@@ -4,8 +4,13 @@ module RuboCop
4
4
  module RSpec
5
5
  # Wrapper for RSpec examples
6
6
  class Example < Concept
7
+ # @!method extract_doc_string(node)
7
8
  def_node_matcher :extract_doc_string, '(send _ _ $_ ...)'
9
+
10
+ # @!method extract_metadata(node)
8
11
  def_node_matcher :extract_metadata, '(send _ _ _ $...)'
12
+
13
+ # @!method extract_implementation(node)
9
14
  def_node_matcher :extract_implementation, '(block send args $_)'
10
15
 
11
16
  def doc_string
@@ -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)
@@ -4,6 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Wrapper for RSpec hook
6
6
  class Hook < Concept
7
+ # @!method extract_metadata(node)
7
8
  def_node_matcher :extract_metadata, <<~PATTERN
8
9
  (block
9
10
  (send _ _ #valid_scope? ? $...) ...
@@ -44,7 +45,7 @@ module RuboCop
44
45
  private
45
46
 
46
47
  def valid_scope?(node)
47
- node&.sym_type? && Hooks::Scopes::ALL.include?(node.value)
48
+ node&.sym_type? && Language::HookScopes.all(node.value)
48
49
  end
49
50
 
50
51
  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,152 +2,196 @@
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.freeze
11
- freeze
12
- end
13
-
14
- def ==(other)
15
- selectors.eql?(other.selectors)
16
- end
17
-
18
- def +(other)
19
- self.class.new(selectors + other.selectors)
20
- end
21
-
22
- def include?(selector)
23
- selectors.include?(selector)
24
- end
15
+ extend RuboCop::NodePattern::Macros
16
+ extend NodePattern
25
17
 
26
- def block_pattern
27
- "(block #{send_pattern} ...)"
28
- end
29
-
30
- def block_pass_pattern
31
- "(send #rspec? #{node_pattern_union} _ block_pass)"
32
- end
18
+ class << self
19
+ attr_accessor :config
20
+ end
33
21
 
34
- def block_or_block_pass_pattern
35
- "{#{block_pattern} #{block_pass_pattern}}"
22
+ # @!method rspec?(node)
23
+ def_node_matcher :rspec?, '{(const {nil? cbase} :RSpec) nil?}'
24
+
25
+ # @!method example_group?(node)
26
+ def_node_matcher :example_group?, block_pattern('#ExampleGroups.all')
27
+
28
+ # @!method shared_group?(node)
29
+ def_node_matcher :shared_group?, block_pattern('#SharedGroups.all')
30
+
31
+ # @!method spec_group?(node)
32
+ def_node_matcher :spec_group?,
33
+ block_pattern('{#SharedGroups.all #ExampleGroups.all}')
34
+
35
+ # @!method example_group_with_body?(node)
36
+ def_node_matcher :example_group_with_body?, <<-PATTERN
37
+ (block #{send_pattern('#ExampleGroups.all')} args !nil?)
38
+ PATTERN
39
+
40
+ # @!method example?(node)
41
+ def_node_matcher :example?, block_pattern('#Examples.all')
42
+
43
+ # @!method hook?(node)
44
+ def_node_matcher :hook?, block_pattern('#Hooks.all')
45
+
46
+ # @!method let?(node)
47
+ def_node_matcher :let?, <<-PATTERN
48
+ {
49
+ #{block_pattern('#Helpers.all')}
50
+ (send #rspec? #Helpers.all _ block_pass)
51
+ }
52
+ PATTERN
53
+
54
+ # @!method include?(node)
55
+ def_node_matcher :include?, <<-PATTERN
56
+ {
57
+ #{send_pattern('#Includes.all')}
58
+ #{block_pattern('#Includes.all')}
59
+ }
60
+ PATTERN
61
+
62
+ # @!method subject?(node)
63
+ def_node_matcher :subject?, block_pattern('#Subjects.all')
64
+
65
+ module ExampleGroups # :nodoc:
66
+ class << self
67
+ def all(element)
68
+ regular(element) ||
69
+ skipped(element) ||
70
+ focused(element)
71
+ end
72
+
73
+ def regular(element)
74
+ Language.config['ExampleGroups']['Regular'].include?(element.to_s)
75
+ end
76
+
77
+ def focused(element)
78
+ Language.config['ExampleGroups']['Focused'].include?(element.to_s)
79
+ end
80
+
81
+ def skipped(element)
82
+ Language.config['ExampleGroups']['Skipped'].include?(element.to_s)
83
+ end
36
84
  end
85
+ end
37
86
 
38
- def send_pattern
39
- "(send #rspec? #{node_pattern_union} ...)"
87
+ module Examples # :nodoc:
88
+ class << self
89
+ def all(element)
90
+ regular(element) ||
91
+ focused(element) ||
92
+ skipped(element) ||
93
+ pending(element)
94
+ end
95
+
96
+ def regular(element)
97
+ Language.config['Examples']['Regular'].include?(element.to_s)
98
+ end
99
+
100
+ def focused(element)
101
+ Language.config['Examples']['Focused'].include?(element.to_s)
102
+ end
103
+
104
+ def skipped(element)
105
+ Language.config['Examples']['Skipped'].include?(element.to_s)
106
+ end
107
+
108
+ def pending(element)
109
+ Language.config['Examples']['Pending'].include?(element.to_s)
110
+ end
40
111
  end
112
+ end
41
113
 
42
- def send_or_block_or_block_pass_pattern
43
- "{#{send_pattern} #{block_pattern} #{block_pass_pattern}}"
114
+ module Expectations # :nodoc:
115
+ def self.all(element)
116
+ Language.config['Expectations'].include?(element.to_s)
44
117
  end
118
+ end
45
119
 
46
- def node_pattern_union
47
- "{#{node_pattern}}"
120
+ module Helpers # :nodoc:
121
+ def self.all(element)
122
+ Language.config['Helpers'].include?(element.to_s)
48
123
  end
124
+ end
49
125
 
50
- def node_pattern
51
- selectors.map(&:inspect).join(' ')
126
+ module Hooks # :nodoc:
127
+ def self.all(element)
128
+ Language.config['Hooks'].include?(element.to_s)
52
129
  end
130
+ end
53
131
 
54
- def to_a
55
- selectors
132
+ module HookScopes # :nodoc:
133
+ def self.all(element)
134
+ Language.config['HookScopes'].include?(element.to_s)
56
135
  end
57
-
58
- protected
59
-
60
- attr_reader :selectors
61
136
  end
62
137
 
63
- module ExampleGroups
64
- GROUPS = SelectorSet.new(%i[describe context feature example_group])
65
- SKIPPED = SelectorSet.new(%i[xdescribe xcontext xfeature])
66
- FOCUSED = SelectorSet.new(%i[fdescribe fcontext ffeature])
138
+ module Includes # :nodoc:
139
+ class << self
140
+ def all(element)
141
+ examples(element) ||
142
+ context(element)
143
+ end
67
144
 
68
- ALL = GROUPS + SKIPPED + FOCUSED
69
- end
145
+ def examples(element)
146
+ Language.config['Includes']['Examples'].include?(element.to_s)
147
+ end
70
148
 
71
- module SharedGroups
72
- EXAMPLES = SelectorSet.new(%i[shared_examples shared_examples_for])
73
- CONTEXT = SelectorSet.new(%i[shared_context])
74
-
75
- ALL = EXAMPLES + CONTEXT
149
+ def context(element)
150
+ Language.config['Includes']['Context'].include?(element.to_s)
151
+ end
152
+ end
76
153
  end
77
154
 
78
- module Includes
79
- EXAMPLES = SelectorSet.new(
80
- %i[
81
- it_behaves_like
82
- it_should_behave_like
83
- include_examples
84
- ]
85
- )
86
- CONTEXT = SelectorSet.new(%i[include_context])
87
-
88
- ALL = EXAMPLES + CONTEXT
155
+ module Runners # :nodoc:
156
+ def self.all(element)
157
+ Language.config['Runners'].include?(element.to_s)
158
+ end
89
159
  end
90
160
 
91
- module Examples
92
- EXAMPLES = SelectorSet.new(%i[it specify example scenario its])
93
- FOCUSED = SelectorSet.new(%i[fit fspecify fexample fscenario focus])
94
- SKIPPED = SelectorSet.new(%i[xit xspecify xexample xscenario skip])
95
- PENDING = SelectorSet.new(%i[pending])
161
+ module SharedGroups # :nodoc:
162
+ class << self
163
+ def all(element)
164
+ examples(element) ||
165
+ context(element)
166
+ end
96
167
 
97
- ALL = EXAMPLES + FOCUSED + SKIPPED + PENDING
98
- end
168
+ def examples(element)
169
+ Language.config['SharedGroups']['Examples'].include?(element.to_s)
170
+ end
99
171
 
100
- module Hooks
101
- ALL = SelectorSet.new(
102
- %i[
103
- prepend_before
104
- before
105
- append_before
106
- around
107
- prepend_after
108
- after
109
- append_after
110
- ]
111
- )
112
-
113
- module Scopes
114
- ALL = SelectorSet.new(
115
- %i[
116
- each
117
- example
118
- context
119
- all
120
- suite
121
- ]
122
- )
172
+ def context(element)
173
+ Language.config['SharedGroups']['Context'].include?(element.to_s)
174
+ end
123
175
  end
124
176
  end
125
177
 
126
- module Helpers
127
- ALL = SelectorSet.new(%i[let let!])
128
- end
129
-
130
- module Subject
131
- ALL = SelectorSet.new(%i[subject subject!])
132
- end
133
-
134
- module Expectations
135
- ALL = SelectorSet.new(%i[expect is_expected expect_any_instance_of])
178
+ module Subjects # :nodoc:
179
+ def self.all(element)
180
+ Language.config['Subjects'].include?(element.to_s)
181
+ end
136
182
  end
137
183
 
138
- module Runners
139
- ALL = SelectorSet.new(%i[to to_not not_to])
184
+ # This is used in Dialect and DescribeClass cops to detect RSpec blocks.
185
+ module ALL # :nodoc:
186
+ def self.all(element)
187
+ [ExampleGroups, Examples, Expectations, Helpers, Hooks, Includes,
188
+ Runners, SharedGroups, Subjects]
189
+ .find { |concept| concept.all(element) }
190
+ end
140
191
  end
141
192
 
142
- ALL =
143
- ExampleGroups::ALL +
144
- SharedGroups::ALL +
145
- Examples::ALL +
146
- Hooks::ALL +
147
- Helpers::ALL +
148
- Subject::ALL +
149
- Expectations::ALL +
150
- Runners::ALL
193
+ private_constant :ExampleGroups, :Examples, :Expectations, :Hooks,
194
+ :Includes, :Runners, :SharedGroups, :ALL
151
195
  end
152
196
  end
153
197
  end