rubocop-rspec 1.42.0 → 1.44.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -2
  3. data/config/default.yml +41 -3
  4. data/lib/rubocop-rspec.rb +2 -1
  5. data/lib/rubocop/cop/rspec/align_left_let_brace.rb +1 -1
  6. data/lib/rubocop/cop/rspec/align_right_let_brace.rb +1 -1
  7. data/lib/rubocop/cop/rspec/any_instance.rb +1 -1
  8. data/lib/rubocop/cop/rspec/around_block.rb +2 -2
  9. data/lib/rubocop/cop/rspec/base.rb +76 -0
  10. data/lib/rubocop/cop/rspec/be.rb +1 -1
  11. data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
  12. data/lib/rubocop/cop/rspec/before_after_all.rb +1 -1
  13. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +1 -1
  14. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +6 -3
  15. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +1 -1
  16. data/lib/rubocop/cop/rspec/context_method.rb +2 -2
  17. data/lib/rubocop/cop/rspec/context_wording.rb +3 -3
  18. data/lib/rubocop/cop/rspec/cop.rb +2 -66
  19. data/lib/rubocop/cop/rspec/describe_class.rb +40 -30
  20. data/lib/rubocop/cop/rspec/describe_method.rb +14 -6
  21. data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -2
  22. data/lib/rubocop/cop/rspec/described_class.rb +2 -2
  23. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -1
  24. data/lib/rubocop/cop/rspec/dialect.rb +1 -1
  25. data/lib/rubocop/cop/rspec/empty_example_group.rb +124 -6
  26. data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
  27. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +4 -8
  28. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +4 -8
  29. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +7 -10
  30. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +4 -8
  31. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +5 -8
  32. data/lib/rubocop/cop/rspec/example_length.rb +1 -1
  33. data/lib/rubocop/cop/rspec/example_without_description.rb +1 -1
  34. data/lib/rubocop/cop/rspec/example_wording.rb +4 -4
  35. data/lib/rubocop/cop/rspec/expect_actual.rb +1 -1
  36. data/lib/rubocop/cop/rspec/expect_change.rb +1 -1
  37. data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -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 -3
  40. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +10 -6
  41. data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +1 -1
  42. data/lib/rubocop/cop/rspec/file_path.rb +25 -17
  43. data/lib/rubocop/cop/rspec/focus.rb +7 -11
  44. data/lib/rubocop/cop/rspec/hook_argument.rb +5 -6
  45. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
  46. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -3
  47. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
  48. data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -6
  49. data/lib/rubocop/cop/rspec/instance_spy.rb +1 -1
  50. data/lib/rubocop/cop/rspec/instance_variable.rb +1 -1
  51. data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +1 -1
  52. data/lib/rubocop/cop/rspec/it_behaves_like.rb +1 -1
  53. data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
  54. data/lib/rubocop/cop/rspec/leading_subject.rb +24 -17
  55. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
  56. data/lib/rubocop/cop/rspec/let_before_examples.rb +1 -1
  57. data/lib/rubocop/cop/rspec/let_setup.rb +6 -3
  58. data/lib/rubocop/cop/rspec/message_chain.rb +1 -1
  59. data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
  60. data/lib/rubocop/cop/rspec/message_spies.rb +1 -1
  61. data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +1 -1
  62. data/lib/rubocop/cop/rspec/multiple_describes.rb +11 -8
  63. data/lib/rubocop/cop/rspec/multiple_expectations.rb +7 -11
  64. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +148 -0
  65. data/lib/rubocop/cop/rspec/multiple_subjects.rb +1 -1
  66. data/lib/rubocop/cop/rspec/named_subject.rb +1 -1
  67. data/lib/rubocop/cop/rspec/nested_groups.rb +4 -4
  68. data/lib/rubocop/cop/rspec/not_to_not.rb +1 -1
  69. data/lib/rubocop/cop/rspec/overwriting_setup.rb +1 -1
  70. data/lib/rubocop/cop/rspec/pending.rb +1 -1
  71. data/lib/rubocop/cop/rspec/predicate_matcher.rb +7 -14
  72. data/lib/rubocop/cop/rspec/rails/http_status.rb +1 -1
  73. data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
  74. data/lib/rubocop/cop/rspec/receive_never.rb +2 -2
  75. data/lib/rubocop/cop/rspec/repeated_description.rb +1 -1
  76. data/lib/rubocop/cop/rspec/repeated_example.rb +2 -2
  77. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
  78. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +1 -1
  79. data/lib/rubocop/cop/rspec/repeated_include_example.rb +103 -0
  80. data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
  81. data/lib/rubocop/cop/rspec/scattered_let.rb +1 -1
  82. data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
  83. data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
  84. data/lib/rubocop/cop/rspec/shared_examples.rb +1 -1
  85. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +1 -1
  86. data/lib/rubocop/cop/rspec/stubbed_mock.rb +172 -0
  87. data/lib/rubocop/cop/rspec/subject_stub.rb +6 -6
  88. data/lib/rubocop/cop/rspec/unspecified_exception.rb +1 -1
  89. data/lib/rubocop/cop/rspec/variable_definition.rb +6 -6
  90. data/lib/rubocop/cop/rspec/variable_name.rb +28 -9
  91. data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
  92. data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
  93. data/lib/rubocop/cop/rspec/yield.rb +1 -1
  94. data/lib/rubocop/cop/rspec_cops.rb +3 -0
  95. data/lib/rubocop/rspec/corrector/move_node.rb +7 -5
  96. data/lib/rubocop/rspec/description_extractor.rb +1 -1
  97. data/lib/rubocop/rspec/{blank_line_separation.rb → empty_line_separation.rb} +13 -2
  98. data/lib/rubocop/rspec/example_group.rb +2 -2
  99. data/lib/rubocop/rspec/hook.rb +1 -5
  100. data/lib/rubocop/rspec/language.rb +12 -5
  101. data/lib/rubocop/rspec/language/node_pattern.rb +6 -1
  102. data/lib/rubocop/rspec/top_level_describe.rb +2 -2
  103. data/lib/rubocop/rspec/top_level_group.rb +26 -13
  104. data/lib/rubocop/rspec/variable.rb +1 -1
  105. data/lib/rubocop/rspec/version.rb +1 -1
  106. metadata +38 -6
@@ -31,7 +31,7 @@ module RuboCop
31
31
  # # good
32
32
  # describe MyClass do
33
33
  # end
34
- class Pending < Cop
34
+ class Pending < Base
35
35
  MSG = 'Pending spec found.'
36
36
 
37
37
  PENDING = Examples::PENDING + Examples::SKIPPED + ExampleGroups::SKIPPED
@@ -208,18 +208,20 @@ module RuboCop
208
208
  'is_a?'
209
209
  when 'be_an_instance_of', 'be_instance_of', 'an_instance_of'
210
210
  'instance_of?'
211
- when 'include', 'respond_to'
212
- matcher + '?'
211
+ when 'include'
212
+ 'include?'
213
+ when 'respond_to'
214
+ 'respond_to?'
213
215
  when /^have_(.+)/
214
216
  "has_#{Regexp.last_match(1)}?"
215
217
  else
216
- matcher[/^be_(.+)/, 1] + '?'
218
+ "#{matcher[/^be_(.+)/, 1]}?"
217
219
  end
218
220
  end
219
221
  # rubocop:enable Metrics/MethodLength
220
222
 
221
223
  def replacement_matcher(node)
222
- case [cop_config['Strict'], node.method_name == :to]
224
+ case [cop_config['Strict'], node.method?(:to)]
223
225
  when [true, true]
224
226
  'be(true)'
225
227
  when [true, false]
@@ -269,7 +271,7 @@ module RuboCop
269
271
  #
270
272
  # # good - the above code is rewritten to it by this cop
271
273
  # expect(foo.something?).to be_truthy
272
- class PredicateMatcher < Cop
274
+ class PredicateMatcher < Base
273
275
  extend AutoCorrector
274
276
  include ConfigurableEnforcedStyle
275
277
  include InflectedHelper
@@ -288,15 +290,6 @@ module RuboCop
288
290
  check_explicit(node) if style == :explicit
289
291
  end
290
292
 
291
- def autocorrect(node)
292
- case style
293
- when :inflected
294
- autocorrect_inflected(node)
295
- when :explicit
296
- autocorrect_explicit(node)
297
- end
298
- end
299
-
300
293
  private
301
294
 
302
295
  # returns args location with whitespace
@@ -30,7 +30,7 @@ module RuboCop
30
30
  # it { is_expected.to have_http_status :success }
31
31
  # it { is_expected.to have_http_status :error }
32
32
  #
33
- class HttpStatus < Cop
33
+ class HttpStatus < Base
34
34
  extend AutoCorrector
35
35
  include ConfigurableEnforcedStyle
36
36
 
@@ -23,7 +23,7 @@ module RuboCop
23
23
  # expect(foo).to receive(:bar).at_most(:once)
24
24
  # expect(foo).to receive(:bar).at_most(:twice).times
25
25
  #
26
- class ReceiveCounts < Cop
26
+ class ReceiveCounts < Base
27
27
  extend AutoCorrector
28
28
 
29
29
  MSG = 'Use `%<alternative>s` instead of `%<original>s`.'
@@ -13,14 +13,14 @@ module RuboCop
13
13
  # # good
14
14
  # expect(foo).not_to receive(:bar)
15
15
  #
16
- class ReceiveNever < Cop
16
+ class ReceiveNever < Base
17
17
  extend AutoCorrector
18
18
  MSG = 'Use `not_to receive` instead of `never`.'
19
19
 
20
20
  def_node_search :method_on_stub?, '(send nil? :receive ...)'
21
21
 
22
22
  def on_send(node)
23
- return unless node.method_name == :never && method_on_stub?(node)
23
+ return unless node.method?(:never) && method_on_stub?(node)
24
24
 
25
25
  add_offense(node.loc.selector) do |corrector|
26
26
  autocorrect(corrector, node)
@@ -40,7 +40,7 @@ module RuboCop
40
40
  # end
41
41
  # end
42
42
  #
43
- class RepeatedDescription < Cop
43
+ class RepeatedDescription < Base
44
44
  MSG = "Don't repeat descriptions within an example group."
45
45
 
46
46
  def on_block(node)
@@ -15,7 +15,7 @@ module RuboCop
15
15
  # expect(user).to be_valid
16
16
  # end
17
17
  #
18
- class RepeatedExample < Cop
18
+ class RepeatedExample < Base
19
19
  MSG = "Don't repeat examples within an example group."
20
20
 
21
21
  def on_block(node)
@@ -41,7 +41,7 @@ module RuboCop
41
41
  def example_signature(example)
42
42
  key_parts = [example.metadata, example.implementation]
43
43
 
44
- if example.definition.method_name == :its
44
+ if example.definition.method?(:its)
45
45
  key_parts << example.definition.arguments
46
46
  end
47
47
 
@@ -43,7 +43,7 @@ module RuboCop
43
43
  # it { is_expected.to respond_to :each }
44
44
  # end
45
45
  #
46
- class RepeatedExampleGroupBody < Cop
46
+ class RepeatedExampleGroupBody < Base
47
47
  MSG = 'Repeated %<group>s block body on line(s) %<loc>s'
48
48
 
49
49
  def_node_matcher :several_example_groups?, <<-PATTERN
@@ -43,7 +43,7 @@ module RuboCop
43
43
  # # example group
44
44
  # end
45
45
  #
46
- class RepeatedExampleGroupDescription < Cop
46
+ class RepeatedExampleGroupDescription < Base
47
47
  MSG = 'Repeated %<group>s block description on line(s) %<loc>s'
48
48
 
49
49
  def_node_matcher :several_example_groups?, <<-PATTERN
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Check for repeated include of shared examples.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # describe 'foo' do
12
+ # include_examples 'cool stuff'
13
+ # include_examples 'cool stuff'
14
+ # end
15
+ #
16
+ # # bad
17
+ # describe 'foo' do
18
+ # it_behaves_like 'a cool', 'thing'
19
+ # it_behaves_like 'a cool', 'thing'
20
+ # end
21
+ #
22
+ # # bad
23
+ # context 'foo' do
24
+ # it_should_behave_like 'a duck'
25
+ # it_should_behave_like 'a duck'
26
+ # end
27
+ #
28
+ # # good
29
+ # describe 'foo' do
30
+ # include_examples 'cool stuff'
31
+ # end
32
+ #
33
+ # describe 'bar' do
34
+ # include_examples 'cool stuff'
35
+ # end
36
+ #
37
+ # # good
38
+ # describe 'foo' do
39
+ # it_behaves_like 'a cool', 'thing'
40
+ # it_behaves_like 'a cool', 'person'
41
+ # end
42
+ #
43
+ # # good
44
+ # context 'foo' do
45
+ # it_should_behave_like 'a duck'
46
+ # it_should_behave_like 'a goose'
47
+ # end
48
+ #
49
+ class RepeatedIncludeExample < Base
50
+ MSG = 'Repeated include of shared_examples %<name>s ' \
51
+ 'on line(s) %<repeat>s'
52
+
53
+ def_node_matcher :several_include_examples?, <<-PATTERN
54
+ (begin <#include_examples? #include_examples? ...>)
55
+ PATTERN
56
+
57
+ def_node_matcher :include_examples?, Includes::EXAMPLES.send_pattern
58
+
59
+ def_node_matcher :shared_examples_name, <<-PATTERN
60
+ (send _ #{Includes::EXAMPLES.node_pattern_union} $_ ...)
61
+ PATTERN
62
+
63
+ def on_begin(node)
64
+ return unless several_include_examples?(node)
65
+
66
+ repeated_include_examples(node).each do |item, repeats|
67
+ add_offense(item, message: message(item, repeats))
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def repeated_include_examples(node)
74
+ node
75
+ .children
76
+ .select { |child| literal_include_examples?(child) }
77
+ .group_by { |child| signature_keys(child) }
78
+ .values
79
+ .reject(&:one?)
80
+ .flat_map { |items| add_repeated_lines(items) }
81
+ end
82
+
83
+ def literal_include_examples?(node)
84
+ include_examples?(node) &&
85
+ node.arguments.all?(&:recursive_literal_or_const?)
86
+ end
87
+
88
+ def add_repeated_lines(items)
89
+ repeated_lines = items.map(&:first_line)
90
+ items.map { |item| [item, repeated_lines - [item.first_line]] }
91
+ end
92
+
93
+ def signature_keys(item)
94
+ item.arguments
95
+ end
96
+
97
+ def message(item, repeats)
98
+ format(MSG, name: shared_examples_name(item).source, repeat: repeats)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -33,7 +33,7 @@ module RuboCop
33
33
  # # also good as the returned value is dynamic
34
34
  # allow(Foo).to receive(:bar) { bar.baz }
35
35
  #
36
- class ReturnFromStub < Cop
36
+ class ReturnFromStub < Base
37
37
  extend AutoCorrector
38
38
  include ConfigurableEnforcedStyle
39
39
 
@@ -26,7 +26,7 @@ module RuboCop
26
26
  # let!(:baz) { 3 }
27
27
  # end
28
28
  #
29
- class ScatteredLet < Cop
29
+ class ScatteredLet < Base
30
30
  extend AutoCorrector
31
31
 
32
32
  MSG = 'Group all let/let! blocks in the example group together.'
@@ -22,7 +22,7 @@ module RuboCop
22
22
  # end
23
23
  # end
24
24
  #
25
- class ScatteredSetup < Cop
25
+ class ScatteredSetup < Base
26
26
  MSG = 'Do not define multiple `%<hook_name>s` hooks in the same '\
27
27
  'example group (also defined on %<lines>s).'
28
28
 
@@ -50,7 +50,7 @@ module RuboCop
50
50
  # end
51
51
  # end
52
52
  #
53
- class SharedContext < Cop
53
+ class SharedContext < Base
54
54
  extend AutoCorrector
55
55
 
56
56
  MSG_EXAMPLES = "Use `shared_examples` when you don't "\
@@ -20,7 +20,7 @@ module RuboCop
20
20
  # shared_examples_for 'foo bar baz'
21
21
  # include_examples 'foo bar baz'
22
22
  #
23
- class SharedExamples < Cop
23
+ class SharedExamples < Base
24
24
  extend AutoCorrector
25
25
 
26
26
  def_node_matcher :shared_examples,
@@ -16,7 +16,7 @@ module RuboCop
16
16
  # allow(foo).to receive(:bar, :baz)
17
17
  # allow(foo).to receive("bar.baz")
18
18
  #
19
- class SingleArgumentMessageChain < Cop
19
+ class SingleArgumentMessageChain < Base
20
20
  extend AutoCorrector
21
21
 
22
22
  MSG = 'Use `%<recommended>s` instead of calling '\
@@ -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.node_pattern_union} ...)
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