rubocop-rspec 2.0.0.pre → 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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -2
  3. data/README.md +4 -0
  4. data/config/default.yml +100 -18
  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/base.rb +6 -55
  9. data/lib/rubocop/cop/rspec/be.rb +1 -1
  10. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +2 -2
  11. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +3 -2
  12. data/lib/rubocop/cop/rspec/describe_class.rb +1 -1
  13. data/lib/rubocop/cop/rspec/describe_method.rb +1 -1
  14. data/lib/rubocop/cop/rspec/described_class.rb +1 -2
  15. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -2
  16. data/lib/rubocop/cop/rspec/dialect.rb +1 -1
  17. data/lib/rubocop/cop/rspec/empty_example_group.rb +6 -45
  18. data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
  19. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +1 -1
  20. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
  21. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +1 -1
  22. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +1 -1
  23. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -2
  24. data/lib/rubocop/cop/rspec/expect_actual.rb +1 -1
  25. data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
  26. data/lib/rubocop/cop/rspec/file_path.rb +1 -1
  27. data/lib/rubocop/cop/rspec/focus.rb +13 -7
  28. data/lib/rubocop/cop/rspec/hook_argument.rb +2 -4
  29. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +2 -2
  30. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
  31. data/lib/rubocop/cop/rspec/instance_variable.rb +1 -1
  32. data/lib/rubocop/cop/rspec/let_before_examples.rb +2 -2
  33. data/lib/rubocop/cop/rspec/let_setup.rb +7 -4
  34. data/lib/rubocop/cop/rspec/message_spies.rb +1 -1
  35. data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +51 -0
  36. data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
  37. data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
  38. data/lib/rubocop/cop/rspec/mixin/variable.rb +20 -0
  39. data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
  40. data/lib/rubocop/cop/rspec/multiple_expectations.rb +1 -1
  41. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +3 -1
  42. data/lib/rubocop/cop/rspec/named_subject.rb +8 -12
  43. data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
  44. data/lib/rubocop/cop/rspec/overwriting_setup.rb +2 -1
  45. data/lib/rubocop/cop/rspec/pending.rb +13 -5
  46. data/lib/rubocop/cop/rspec/predicate_matcher.rb +3 -3
  47. data/lib/rubocop/cop/rspec/repeated_include_example.rb +3 -2
  48. data/lib/rubocop/cop/rspec/shared_context.rb +16 -6
  49. data/lib/rubocop/cop/rspec/shared_examples.rb +3 -1
  50. data/lib/rubocop/cop/rspec/stubbed_mock.rb +1 -1
  51. data/lib/rubocop/cop/rspec/subject_stub.rb +2 -2
  52. data/lib/rubocop/cop/rspec/variable_definition.rb +1 -1
  53. data/lib/rubocop/cop/rspec/variable_name.rb +1 -1
  54. data/lib/rubocop/cop/rspec_cops.rb +0 -1
  55. data/lib/rubocop/rspec/align_let_brace.rb +1 -1
  56. data/lib/rubocop/rspec/concept.rb +2 -2
  57. data/lib/rubocop/rspec/config_formatter.rb +3 -3
  58. data/lib/rubocop/rspec/corrector/move_node.rb +1 -1
  59. data/lib/rubocop/rspec/example_group.rb +15 -5
  60. data/lib/rubocop/rspec/hook.rb +1 -1
  61. data/lib/rubocop/rspec/inject.rb +4 -2
  62. data/lib/rubocop/rspec/language.rb +143 -109
  63. data/lib/rubocop/rspec/language/node_pattern.rb +7 -24
  64. data/lib/rubocop/rspec/version.rb +1 -1
  65. metadata +22 -12
  66. data/lib/rubocop/cop/rspec/cop.rb +0 -10
  67. data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +0 -41
  68. data/lib/rubocop/rspec.rb +0 -12
  69. data/lib/rubocop/rspec/empty_line_separation.rb +0 -48
  70. data/lib/rubocop/rspec/final_end_location.rb +0 -17
  71. data/lib/rubocop/rspec/top_level_describe.rb +0 -52
  72. data/lib/rubocop/rspec/top_level_group.rb +0 -57
  73. data/lib/rubocop/rspec/variable.rb +0 -16
@@ -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
@@ -37,31 +35,6 @@ module RuboCop
37
35
  # describe Bacon do
38
36
  # pending 'will add tests later'
39
37
  # end
40
- #
41
- # @example configuration
42
- #
43
- # # .rubocop.yml
44
- # # RSpec/EmptyExampleGroup:
45
- # # CustomIncludeMethods:
46
- # # - include_tests
47
- #
48
- # # spec_helper.rb
49
- # RSpec.configure do |config|
50
- # config.alias_it_behaves_like_to(:include_tests)
51
- # end
52
- #
53
- # # bacon_spec.rb
54
- # describe Bacon do
55
- # let(:bacon) { Bacon.new(chunkiness) }
56
- # let(:chunkiness) { false }
57
- #
58
- # context 'extra chunky' do # not flagged by rubocop
59
- # let(:chunkiness) { true }
60
- #
61
- # include_tests 'shared tests'
62
- # end
63
- # end
64
- #
65
38
  class EmptyExampleGroup < Base
66
39
  MSG = 'Empty example group detected.'
67
40
 
@@ -76,7 +49,7 @@ module RuboCop
76
49
  # @param node [RuboCop::AST::Node]
77
50
  # @yield [RuboCop::AST::Node] example group body
78
51
  def_node_matcher :example_group_body, <<~PATTERN
79
- (block #{ExampleGroups::ALL.send_pattern} args $_)
52
+ (block #{send_pattern('#ExampleGroups.all')} args $_)
80
53
  PATTERN
81
54
 
82
55
  # @!method example_or_group_or_include?(node)
@@ -95,12 +68,10 @@ module RuboCop
95
68
  # @return [Array<RuboCop::AST::Node>] matching nodes
96
69
  def_node_matcher :example_or_group_or_include?, <<~PATTERN
97
70
  {
98
- #{Examples::ALL.send_pattern}
99
- #{Examples::ALL.block_pattern}
100
- #{ExampleGroups::ALL.block_pattern}
101
- #{Includes::ALL.send_pattern}
102
- #{Includes::ALL.block_pattern}
103
- (send nil? #custom_include? ...)
71
+ #{block_pattern(
72
+ '{#Examples.all #ExampleGroups.all #Includes.all}'
73
+ )}
74
+ #{send_pattern('{#Examples.all #Includes.all}')}
104
75
  }
105
76
  PATTERN
106
77
 
@@ -120,7 +91,7 @@ module RuboCop
120
91
  # @param node [RuboCop::AST::Node]
121
92
  # @return [Array<RuboCop::AST::Node>] matching nodes
122
93
  def_node_matcher :examples_inside_block?, <<~PATTERN
123
- (block !#{Hooks::ALL.send_pattern} _ #examples?)
94
+ (block !#{send_pattern('#Hooks.all')} _ #examples?)
124
95
  PATTERN
125
96
 
126
97
  # @!method examples_directly_or_in_block?(node)
@@ -192,16 +163,6 @@ module RuboCop
192
163
  def examples_in_branches?(if_node)
193
164
  if_node.branches.any? { |branch| examples?(branch) }
194
165
  end
195
-
196
- def custom_include?(method_name)
197
- custom_include_methods.include?(method_name)
198
- end
199
-
200
- def custom_include_methods
201
- cop_config
202
- .fetch('CustomIncludeMethods', [])
203
- .map(&:to_sym)
204
- end
205
166
  end
206
167
  end
207
168
  end
@@ -29,7 +29,7 @@ module RuboCop
29
29
  MSG = 'Empty hook detected.'
30
30
 
31
31
  def_node_matcher :empty_hook?, <<~PATTERN
32
- (block $#{Hooks::ALL.send_pattern} _ nil?)
32
+ (block $#{send_pattern('#Hooks.all')} _ nil?)
33
33
  PATTERN
34
34
 
35
35
  def on_block(node)
@@ -43,7 +43,7 @@ module RuboCop
43
43
  #
44
44
  class EmptyLineAfterExample < Base
45
45
  extend AutoCorrector
46
- include RuboCop::RSpec::EmptyLineSeparation
46
+ include EmptyLineSeparation
47
47
 
48
48
  MSG = 'Add an empty line after `%<example>s`.'
49
49
 
@@ -25,7 +25,7 @@ module RuboCop
25
25
  #
26
26
  class EmptyLineAfterExampleGroup < Base
27
27
  extend AutoCorrector
28
- include RuboCop::RSpec::EmptyLineSeparation
28
+ include EmptyLineSeparation
29
29
 
30
30
  MSG = 'Add an empty line after `%<example_group>s`.'
31
31
 
@@ -18,7 +18,7 @@ module RuboCop
18
18
  # it { does_something }
19
19
  class EmptyLineAfterFinalLet < Base
20
20
  extend AutoCorrector
21
- include RuboCop::RSpec::EmptyLineSeparation
21
+ include EmptyLineSeparation
22
22
 
23
23
  MSG = 'Add an empty line after the last `%<let>s`.'
24
24
 
@@ -35,7 +35,7 @@ module RuboCop
35
35
  #
36
36
  class EmptyLineAfterHook < Base
37
37
  extend AutoCorrector
38
- include RuboCop::RSpec::EmptyLineSeparation
38
+ include EmptyLineSeparation
39
39
 
40
40
  MSG = 'Add an empty line after `%<hook>s`.'
41
41
 
@@ -16,7 +16,7 @@ module RuboCop
16
16
  # let(:foo) { bar }
17
17
  class EmptyLineAfterSubject < Base
18
18
  extend AutoCorrector
19
- include RuboCop::RSpec::EmptyLineSeparation
19
+ include EmptyLineSeparation
20
20
 
21
21
  MSG = 'Add an empty line after `%<subject>s`.'
22
22
 
@@ -32,7 +32,7 @@ module RuboCop
32
32
 
33
33
  def in_spec_block?(node)
34
34
  node.each_ancestor(:block).any? do |ancestor|
35
- Examples::ALL.include?(ancestor.method_name)
35
+ Examples.all(ancestor.method_name)
36
36
  end
37
37
  end
38
38
  end
@@ -48,7 +48,7 @@ module RuboCop
48
48
  def_node_matcher :expect_literal, <<~PATTERN
49
49
  (send
50
50
  (send nil? :expect $#literal?)
51
- #{Runners::ALL.node_pattern_union}
51
+ #Runners.all
52
52
  {
53
53
  (send (send nil? $:be) :== $_)
54
54
  (send nil? $_ $_ ...)
@@ -23,7 +23,7 @@ module RuboCop
23
23
  class ExpectInHook < Base
24
24
  MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'
25
25
 
26
- def_node_search :expectation, Expectations::ALL.send_pattern
26
+ def_node_search :expectation, send_pattern('#Expectations.all')
27
27
 
28
28
  def on_block(node)
29
29
  return unless hook?(node)
@@ -57,7 +57,7 @@ module RuboCop
57
57
  # my_class_spec.rb # describe MyClass, '#method'
58
58
  #
59
59
  class FilePath < Base
60
- include RuboCop::RSpec::TopLevelGroup
60
+ include TopLevelGroup
61
61
 
62
62
  MSG = 'Spec path should end with `%<suffix>s`.'
63
63
 
@@ -22,19 +22,25 @@ module RuboCop
22
22
  class Focus < Base
23
23
  MSG = 'Focused spec found.'
24
24
 
25
- focused = ExampleGroups::FOCUSED + Examples::FOCUSED
26
-
27
- def_node_matcher :focusable_selector?,
28
- (ExampleGroups::GROUPS + ExampleGroups::SKIPPED +
29
- Examples::EXAMPLES + Examples::SKIPPED +
30
- Examples::PENDING).node_pattern_union
25
+ def_node_matcher :focusable_selector?, <<-PATTERN
26
+ {
27
+ #ExampleGroups.regular
28
+ #ExampleGroups.skipped
29
+ #Examples.regular
30
+ #Examples.skipped
31
+ #Examples.pending
32
+ }
33
+ PATTERN
31
34
 
32
35
  def_node_matcher :metadata, <<-PATTERN
33
36
  {(send #rspec? #focusable_selector? <$(sym :focus) ...>)
34
37
  (send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))}
35
38
  PATTERN
36
39
 
37
- def_node_matcher :focused_block?, focused.send_pattern
40
+ def_node_matcher :focused_block?,
41
+ send_pattern(<<~PATTERN)
42
+ {#ExampleGroups.focused #Examples.focused}
43
+ PATTERN
38
44
 
39
45
  def on_send(node)
40
46
  focus_metadata(node) do |focus|
@@ -64,13 +64,11 @@ module RuboCop
64
64
  IMPLICIT_MSG = 'Omit the default `%<scope>p` argument for RSpec hooks.'
65
65
  EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'
66
66
 
67
- def_node_matcher :hook?, Hooks::ALL.node_pattern_union
68
-
69
67
  def_node_matcher :scoped_hook, <<-PATTERN
70
- (block $(send _ #hook? (sym ${:each :example})) ...)
68
+ (block $(send _ #Hooks.all (sym ${:each :example})) ...)
71
69
  PATTERN
72
70
 
73
- def_node_matcher :unscoped_hook, '(block $(send _ #hook?) ...)'
71
+ def_node_matcher :unscoped_hook, '(block $(send _ #Hooks.all) ...)'
74
72
 
75
73
  def on_block(node)
76
74
  hook(node) do |method_send, scope_name|
@@ -30,8 +30,8 @@ module RuboCop
30
30
 
31
31
  def_node_matcher :example_or_group?, <<-PATTERN
32
32
  {
33
- #{(Examples::ALL + ExampleGroups::ALL).block_pattern}
34
- #{Includes::EXAMPLES.send_pattern}
33
+ #{block_pattern('{#ExampleGroups.all #Examples.all}')}
34
+ #{send_pattern('#Includes.examples')}
35
35
  }
36
36
  PATTERN
37
37
 
@@ -33,7 +33,7 @@ module RuboCop
33
33
  def_node_matcher :implicit_expect, <<-PATTERN
34
34
  {
35
35
  (send nil? ${:should :should_not} ...)
36
- (send (send nil? $:is_expected) #{Runners::ALL.node_pattern_union} ...)
36
+ (send (send nil? $:is_expected) #Runners.all ...)
37
37
  }
38
38
  PATTERN
39
39
 
@@ -47,7 +47,7 @@ module RuboCop
47
47
  # end
48
48
  #
49
49
  class InstanceVariable < Base
50
- include RuboCop::RSpec::TopLevelGroup
50
+ include TopLevelGroup
51
51
 
52
52
  MSG = 'Avoid instance variables – use let, ' \
53
53
  'a method call, or a local variable (if possible).'
@@ -37,8 +37,8 @@ module RuboCop
37
37
 
38
38
  def_node_matcher :example_or_group?, <<-PATTERN
39
39
  {
40
- #{(Examples::ALL + ExampleGroups::ALL).block_pattern}
41
- #{Includes::EXAMPLES.send_pattern}
40
+ #{block_pattern('{#ExampleGroups.all #Examples.all}')}
41
+ #{send_pattern('#Includes.examples')}
42
42
  }
43
43
  PATTERN
44
44
 
@@ -29,10 +29,13 @@ module RuboCop
29
29
  MSG = 'Do not use `let!` to setup objects not referenced in tests.'
30
30
 
31
31
  def_node_matcher :example_or_shared_group_or_including?,
32
- (
33
- ExampleGroups::ALL + SharedGroups::ALL +
34
- Includes::ALL
35
- ).block_pattern
32
+ block_pattern(<<~PATTERN)
33
+ {
34
+ #SharedGroups.all
35
+ #ExampleGroups.all
36
+ #Includes.all
37
+ }
38
+ PATTERN
36
39
 
37
40
  def_node_matcher :let_bang, <<-PATTERN
38
41
  {
@@ -36,7 +36,7 @@ module RuboCop
36
36
  SUPPORTED_STYLES = %w[have_received receive].freeze
37
37
 
38
38
  def_node_matcher :message_expectation, %(
39
- (send (send nil? :expect $_) #{Runners::ALL.node_pattern_union} ...)
39
+ (send (send nil? :expect $_) #Runners.all ...)
40
40
  )
41
41
 
42
42
  def_node_search :receive_message, %(
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Helps determine the offending location if there is not an empty line
7
+ # following the node. Allows comments to follow directly after.
8
+ module EmptyLineSeparation
9
+ include FinalEndLocation
10
+ include RangeHelp
11
+
12
+ def missing_separating_line_offense(node)
13
+ return if last_child?(node)
14
+
15
+ missing_separating_line(node) do |location|
16
+ msg = yield(node.method_name)
17
+ add_offense(location, message: msg) do |corrector|
18
+ corrector.insert_after(location.end, "\n")
19
+ end
20
+ end
21
+ end
22
+
23
+ def missing_separating_line(node)
24
+ line = final_end_location(node).line
25
+
26
+ line += 1 while comment_line?(processed_source[line])
27
+
28
+ return if processed_source[line].blank?
29
+
30
+ yield offending_loc(line)
31
+ end
32
+
33
+ def offending_loc(last_line)
34
+ offending_line = processed_source[last_line - 1]
35
+
36
+ content_length = offending_line.lstrip.length
37
+ start = offending_line.length - content_length
38
+
39
+ source_range(processed_source.buffer,
40
+ last_line, start, content_length)
41
+ end
42
+
43
+ def last_child?(node)
44
+ return true unless node.parent&.begin_type?
45
+
46
+ node.equal?(node.parent.children.last)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Helps find the true end location of nodes which might contain heredocs.
7
+ module FinalEndLocation
8
+ def final_end_location(start_node)
9
+ heredoc_endings =
10
+ start_node.each_node(:str, :dstr, :xstr)
11
+ .select(&:heredoc?)
12
+ .map { |node| node.loc.heredoc_end }
13
+
14
+ [start_node.loc.end, *heredoc_endings].max_by(&:line)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Helper methods for top level example group cops
7
+ module TopLevelGroup
8
+ extend RuboCop::NodePattern::Macros
9
+
10
+ def on_new_investigation
11
+ super
12
+
13
+ top_level_groups.each do |node|
14
+ on_top_level_example_group(node) if example_group?(node)
15
+ on_top_level_group(node)
16
+ end
17
+ end
18
+
19
+ def top_level_groups
20
+ @top_level_groups ||=
21
+ top_level_nodes(root_node).select { |n| spec_group?(n) }
22
+ end
23
+
24
+ private
25
+
26
+ # Dummy methods to be overridden in the consumer
27
+ def on_top_level_example_group(_node); end
28
+
29
+ def on_top_level_group(_node); end
30
+
31
+ def top_level_group?(node)
32
+ top_level_groups.include?(node)
33
+ end
34
+
35
+ def top_level_nodes(node)
36
+ return [] if node.nil?
37
+
38
+ case node.type
39
+ when :begin
40
+ node.children
41
+ when :module, :class
42
+ top_level_nodes(node.body)
43
+ else
44
+ [node]
45
+ end
46
+ end
47
+
48
+ def root_node
49
+ processed_source.ast
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end