rubocop-rspec 2.29.1 → 3.5.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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -3
  3. data/README.md +21 -5
  4. data/config/default.yml +64 -269
  5. data/config/obsoletion.yml +20 -21
  6. data/lib/rubocop/cop/rspec/around_block.rb +2 -4
  7. data/lib/rubocop/cop/rspec/base.rb +0 -1
  8. data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
  9. data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
  10. data/lib/rubocop/cop/rspec/be_nil.rb +4 -0
  11. data/lib/rubocop/cop/rspec/change_by_zero.rb +4 -5
  12. data/lib/rubocop/cop/rspec/contain_exactly.rb +1 -0
  13. data/lib/rubocop/cop/rspec/context_wording.rb +15 -9
  14. data/lib/rubocop/cop/rspec/dialect.rb +13 -0
  15. data/lib/rubocop/cop/rspec/empty_example_group.rb +2 -0
  16. data/lib/rubocop/cop/rspec/empty_metadata.rb +1 -0
  17. data/lib/rubocop/cop/rspec/example_wording.rb +3 -5
  18. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -1
  19. data/lib/rubocop/cop/rspec/expect_actual.rb +3 -3
  20. data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
  21. data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
  22. data/lib/rubocop/cop/rspec/focus.rb +14 -16
  23. data/lib/rubocop/cop/rspec/implicit_expect.rb +3 -3
  24. data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -0
  25. data/lib/rubocop/cop/rspec/indexed_let.rb +6 -3
  26. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
  27. data/lib/rubocop/cop/rspec/match_array.rb +1 -0
  28. data/lib/rubocop/cop/rspec/message_spies.rb +4 -0
  29. data/lib/rubocop/cop/rspec/metadata_style.rb +1 -6
  30. data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
  31. data/lib/rubocop/cop/rspec/mixin/metadata.rb +5 -8
  32. data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +7 -0
  33. data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
  34. data/lib/rubocop/cop/rspec/multiple_expectations.rb +4 -4
  35. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +4 -5
  36. data/lib/rubocop/cop/rspec/named_subject.rb +5 -2
  37. data/lib/rubocop/cop/rspec/nested_groups.rb +2 -1
  38. data/lib/rubocop/cop/rspec/pending_without_reason.rb +0 -5
  39. data/lib/rubocop/cop/rspec/predicate_matcher.rb +25 -11
  40. data/lib/rubocop/cop/rspec/remove_const.rb +0 -1
  41. data/lib/rubocop/cop/rspec/repeated_subject_call.rb +1 -0
  42. data/lib/rubocop/cop/rspec/return_from_stub.rb +5 -4
  43. data/lib/rubocop/cop/rspec/scattered_setup.rb +7 -1
  44. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +3 -4
  45. data/lib/rubocop/cop/rspec/sort_metadata.rb +22 -8
  46. data/lib/rubocop/cop/rspec/stubbed_mock.rb +15 -10
  47. data/lib/rubocop/cop/rspec/subject_stub.rb +2 -2
  48. data/lib/rubocop/cop/rspec/unspecified_exception.rb +21 -14
  49. data/lib/rubocop/cop/rspec/verified_double_reference.rb +14 -53
  50. data/lib/rubocop/cop/rspec/void_expect.rb +6 -1
  51. data/lib/rubocop/cop/rspec_cops.rb +2 -25
  52. data/lib/rubocop/rspec/concept.rb +0 -1
  53. data/lib/rubocop/rspec/config_formatter.rb +4 -32
  54. data/lib/rubocop/rspec/cop/generator.rb +25 -0
  55. data/lib/rubocop/rspec/description_extractor.rb +2 -2
  56. data/lib/rubocop/rspec/hook.rb +1 -1
  57. data/lib/rubocop/rspec/language.rb +0 -1
  58. data/lib/rubocop/rspec/node.rb +1 -1
  59. data/lib/rubocop/rspec/plugin.rb +37 -0
  60. data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +1 -1
  61. data/lib/rubocop/rspec/version.rb +1 -1
  62. data/lib/rubocop/rspec/wording.rb +2 -4
  63. data/lib/rubocop/rspec.rb +0 -7
  64. data/lib/rubocop-rspec.rb +2 -20
  65. metadata +18 -62
  66. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +0 -39
  67. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +0 -104
  68. data/lib/rubocop/cop/rspec/capybara/match_style.rb +0 -38
  69. data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +0 -33
  70. data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +0 -29
  71. data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +0 -24
  72. data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +0 -35
  73. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -36
  74. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +0 -35
  75. data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +0 -50
  76. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +0 -40
  77. data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +0 -29
  78. data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +0 -33
  79. data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +0 -55
  80. data/lib/rubocop/cop/rspec/file_path.rb +0 -179
  81. data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +0 -27
  82. data/lib/rubocop/cop/rspec/rails/have_http_status.rb +0 -35
  83. data/lib/rubocop/cop/rspec/rails/http_status.rb +0 -61
  84. data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +0 -62
  85. data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +0 -39
  86. data/lib/rubocop/cop/rspec/rails/negation_be_valid.rb +0 -39
  87. data/lib/rubocop/cop/rspec/rails/travel_around.rb +0 -34
  88. data/lib/rubocop/rspec/inject.rb +0 -18
  89. data/lib/rubocop/rspec/language/node_pattern.rb +0 -48
@@ -94,11 +94,6 @@ module RuboCop
94
94
  (send #rspec? ${#ExampleGroups.skipped} ...)
95
95
  PATTERN
96
96
 
97
- # @!method pending_step_without_reason?(node)
98
- def_node_matcher :pending_step_without_reason?, <<~PATTERN
99
- (send nil? {:skip :pending})
100
- PATTERN
101
-
102
97
  def on_send(node)
103
98
  on_pending_by_metadata(node)
104
99
  return unless (parent = parent_node(node))
@@ -15,6 +15,8 @@ module RuboCop
15
15
 
16
16
  def check_inflected(node)
17
17
  predicate_in_actual?(node) do |predicate, to, matcher|
18
+ next if cannot_replace_predicate?(predicate)
19
+
18
20
  msg = message_inflected(predicate)
19
21
  add_offense(node, message: msg) do |corrector|
20
22
  remove_predicate(corrector, predicate)
@@ -32,12 +34,16 @@ module RuboCop
32
34
  (block $(send !nil? #predicate? ...) ...)
33
35
  $(send !nil? #predicate? ...)})
34
36
  $#Runners.all
35
- $#boolean_matcher?)
37
+ $#boolean_matcher? ...)
36
38
  PATTERN
37
39
 
40
+ def cannot_replace_predicate?(send_node)
41
+ send_node.method?(:respond_to?) && send_node.arguments.length > 1
42
+ end
43
+
38
44
  # @!method be_bool?(node)
39
45
  def_node_matcher :be_bool?, <<~PATTERN
40
- (send nil? {:be :eq :eql :equal} {true false})
46
+ (send nil? {:be :eq :eql :equal} boolean)
41
47
  PATTERN
42
48
 
43
49
  # @!method be_boolthy?(node)
@@ -63,7 +69,6 @@ module RuboCop
63
69
  matcher_name: to_predicate_matcher(predicate.method_name))
64
70
  end
65
71
 
66
- # rubocop:disable Metrics/MethodLength
67
72
  def to_predicate_matcher(name)
68
73
  case name = name.to_s
69
74
  when 'is_a?'
@@ -80,7 +85,6 @@ module RuboCop
80
85
  "be_#{name[0..-2]}"
81
86
  end
82
87
  end
83
- # rubocop:enable Metrics/MethodLength
84
88
 
85
89
  def remove_predicate(corrector, predicate)
86
90
  range = predicate.loc.dot.with(
@@ -106,12 +110,16 @@ module RuboCop
106
110
 
107
111
  def true?(to_symbol, matcher)
108
112
  result = case matcher.method_name
109
- when :be, :eq
113
+ when :be, :eq, :eql, :equal
110
114
  matcher.first_argument.true_type?
111
115
  when :be_truthy, :a_truthy_value
112
116
  true
113
117
  when :be_falsey, :be_falsy, :a_falsey_value, :a_falsy_value
114
118
  false
119
+ else
120
+ # :nocov:
121
+ :noop
122
+ # :nocov:
115
123
  end
116
124
  to_symbol == :to ? result : !result
117
125
  end
@@ -174,7 +182,7 @@ module RuboCop
174
182
 
175
183
  def heredoc_argument?(matcher)
176
184
  matcher.arguments.select do |arg|
177
- %i[str dstr xstr].include?(arg.type)
185
+ arg.str_type? || arg.dstr_type? || arg.xstr_type?
178
186
  end.any?(&:heredoc?)
179
187
  end
180
188
 
@@ -183,8 +191,12 @@ module RuboCop
183
191
  (send
184
192
  (send nil? :expect $!nil?)
185
193
  #Runners.all
186
- {$(send nil? #predicate_matcher_name? ...)
187
- (block $(send nil? #predicate_matcher_name? ...) ...)})
194
+ {
195
+ $(send nil? #predicate_matcher_name? ...)
196
+ (block $(send nil? #predicate_matcher_name? ...) ...)
197
+ }
198
+ ...
199
+ )
188
200
  PATTERN
189
201
 
190
202
  # @!method predicate_matcher_block?(node)
@@ -229,7 +241,6 @@ module RuboCop
229
241
  corrector.insert_after(actual, ".#{predicate}" + args + block)
230
242
  end
231
243
 
232
- # rubocop:disable Metrics/MethodLength
233
244
  def to_predicate_method(matcher)
234
245
  case matcher = matcher.to_s
235
246
  when 'be_a', 'be_an', 'be_a_kind_of', 'a_kind_of', 'be_kind_of'
@@ -246,7 +257,6 @@ module RuboCop
246
257
  "#{matcher[/\Abe_(.+)/, 1]}?"
247
258
  end
248
259
  end
249
- # rubocop:enable Metrics/MethodLength
250
260
 
251
261
  def replacement_matcher(node)
252
262
  case [cop_config['Strict'], node.method?(:to)]
@@ -256,7 +266,7 @@ module RuboCop
256
266
  'be(false)'
257
267
  when [false, true]
258
268
  'be_truthy'
259
- when [false, false]
269
+ else
260
270
  'be_falsey'
261
271
  end
262
272
  end
@@ -325,6 +335,10 @@ module RuboCop
325
335
  check_inflected(node)
326
336
  when :explicit
327
337
  check_explicit(node)
338
+ else
339
+ # :nocov:
340
+ :noop
341
+ # :nocov:
328
342
  end
329
343
  end
330
344
 
@@ -17,7 +17,6 @@ module RuboCop
17
17
  #
18
18
  class RemoveConst < Base
19
19
  include RuboCop::RSpec::Language
20
- extend RuboCop::RSpec::Language::NodePattern
21
20
 
22
21
  MSG = 'Do not use remove_const in specs. ' \
23
22
  'Consider using e.g. `stub_const`.'
@@ -72,6 +72,7 @@ module RuboCop
72
72
 
73
73
  def detect_offense(subject_node)
74
74
  return if subject_node.chained?
75
+ return if subject_node.parent.send_type?
75
76
  return unless (block_node = expect_block(subject_node))
76
77
 
77
78
  add_offense(block_node)
@@ -80,10 +80,10 @@ module RuboCop
80
80
 
81
81
  def check_block_body(block)
82
82
  body = block.body
83
- unless dynamic?(body) # rubocop:disable Style/GuardClause
84
- add_offense(block.loc.begin, message: MSG_AND_RETURN) do |corrector|
85
- BlockBodyCorrector.new(block).call(corrector)
86
- end
83
+ return if dynamic?(body)
84
+
85
+ add_offense(block.loc.begin, message: MSG_AND_RETURN) do |corrector|
86
+ BlockBodyCorrector.new(block).call(corrector)
87
87
  end
88
88
  end
89
89
 
@@ -162,6 +162,7 @@ module RuboCop
162
162
  end
163
163
 
164
164
  NULL_BLOCK_BODY = Struct.new(:loc, :source).new(nil, 'nil')
165
+ private_constant :NULL_BLOCK_BODY
165
166
  end
166
167
  end
167
168
  end
@@ -23,6 +23,7 @@ module RuboCop
23
23
  # end
24
24
  #
25
25
  class ScatteredSetup < Base
26
+ include FinalEndLocation
26
27
  include RangeHelp
27
28
  extend AutoCorrector
28
29
 
@@ -75,8 +76,13 @@ module RuboCop
75
76
  def autocorrect(corrector, first_occurrence, occurrence)
76
77
  return if first_occurrence == occurrence || !first_occurrence.body
77
78
 
79
+ # Take heredocs into account
80
+ body = occurrence.body&.source_range&.with(
81
+ end_pos: final_end_location(occurrence).begin_pos
82
+ )
83
+
78
84
  corrector.insert_after(first_occurrence.body,
79
- "\n#{occurrence.body.source}")
85
+ "\n#{body&.source}")
80
86
  corrector.remove(range_by_whole_lines(occurrence.source_range,
81
87
  include_final_newline: true))
82
88
  end
@@ -67,11 +67,10 @@ module RuboCop
67
67
  end
68
68
 
69
69
  def autocorrect_hash_arg(corrector, arg)
70
- key, value = *arg.children.first
71
-
72
- corrector.replace(arg, key_to_arg(key))
70
+ pair = arg.pairs.first
71
+ corrector.replace(arg, key_to_arg(pair.key))
73
72
  corrector.insert_after(arg.parent.loc.end,
74
- ".and_return(#{value.source})")
73
+ ".and_return(#{pair.value.source})")
75
74
  end
76
75
 
77
76
  def autocorrect_array_arg(corrector, arg)
@@ -5,6 +5,8 @@ module RuboCop
5
5
  module RSpec
6
6
  # Sort RSpec metadata alphabetically.
7
7
  #
8
+ # Only the trailing metadata is sorted.
9
+ #
8
10
  # @example
9
11
  # # bad
10
12
  # describe 'Something', :b, :a
@@ -16,6 +18,9 @@ module RuboCop
16
18
  # context 'Something', baz: true, foo: 'bar'
17
19
  # it 'works', :a, :b, baz: true, foo: 'bar'
18
20
  #
21
+ # # good, trailing metadata is sorted
22
+ # describe 'Something', 'description', :a, :b, :z
23
+ # context 'Something', :z, variable, :a, :b
19
24
  class SortMetadata < Base
20
25
  extend AutoCorrector
21
26
  include Metadata
@@ -23,8 +28,14 @@ module RuboCop
23
28
 
24
29
  MSG = 'Sort metadata alphabetically.'
25
30
 
26
- def on_metadata(symbols, hash)
31
+ # @!method match_ambiguous_trailing_metadata?(node)
32
+ def_node_matcher :match_ambiguous_trailing_metadata?, <<~PATTERN
33
+ (send _ _ _ ... !{hash sym str dstr xstr})
34
+ PATTERN
35
+
36
+ def on_metadata(args, hash)
27
37
  pairs = hash&.pairs || []
38
+ symbols = trailing_symbols(args)
28
39
  return if sorted?(symbols, pairs)
29
40
 
30
41
  crime_scene = crime_scene(symbols, pairs)
@@ -35,6 +46,15 @@ module RuboCop
35
46
 
36
47
  private
37
48
 
49
+ def trailing_symbols(args)
50
+ args = args[...-1] if last_arg_could_be_a_hash?(args)
51
+ args.reverse.take_while(&:sym_type?).reverse
52
+ end
53
+
54
+ def last_arg_could_be_a_hash?(args)
55
+ args.last && match_ambiguous_trailing_metadata?(args.last.parent)
56
+ end
57
+
38
58
  def crime_scene(symbols, pairs)
39
59
  metadata = symbols + pairs
40
60
 
@@ -57,13 +77,7 @@ module RuboCop
57
77
  end
58
78
 
59
79
  def sort_symbols(symbols)
60
- symbols.sort_by do |symbol|
61
- if %i[str sym].include?(symbol.type)
62
- symbol.value.to_s.downcase
63
- else
64
- symbol.source.downcase
65
- end
66
- end
80
+ symbols.sort_by { |symbol| symbol.value.to_s.downcase }
67
81
  end
68
82
  end
69
83
  end
@@ -14,8 +14,9 @@ module RuboCop
14
14
  # expect(foo).to receive(:bar).with(42)
15
15
  #
16
16
  class StubbedMock < Base
17
- MSG = 'Prefer `%<replacement>s` over `%<method_name>s` when ' \
17
+ MSG = 'Prefer %<replacement>s over `%<method_name>s` when ' \
18
18
  'configuring a response.'
19
+ RESTRICT_ON_SEND = %i[to].freeze
19
20
 
20
21
  # @!method message_expectation?(node)
21
22
  # Match message expectation matcher
@@ -133,10 +134,10 @@ module RuboCop
133
134
  }
134
135
  PATTERN
135
136
 
136
- RESTRICT_ON_SEND = %i[to].freeze
137
-
138
137
  def on_send(node)
139
- expectation(node, &method(:on_expectation))
138
+ expectation(node) do |expectation, method_name, matcher|
139
+ on_expectation(expectation, method_name, matcher)
140
+ end
140
141
  end
141
142
 
142
143
  private
@@ -153,19 +154,23 @@ module RuboCop
153
154
  end
154
155
 
155
156
  def msg(method_name)
156
- format(MSG,
157
- method_name: method_name,
158
- replacement: replacement(method_name))
157
+ format(
158
+ MSG,
159
+ method_name: method_name,
160
+ replacement: replacement(method_name)
161
+ )
159
162
  end
160
163
 
161
164
  def replacement(method_name)
162
165
  case method_name
163
166
  when :expect
164
- :allow
167
+ '`allow`'
165
168
  when :is_expected
166
- 'allow(subject)'
169
+ '`allow(subject)`'
167
170
  when :expect_any_instance_of
168
- :allow_any_instance_of
171
+ '`allow_any_instance_of`'
172
+ else
173
+ 'an allow statement'
169
174
  end
170
175
  end
171
176
  end
@@ -113,8 +113,8 @@ module RuboCop
113
113
  PATTERN
114
114
 
115
115
  def on_top_level_group(node)
116
- @explicit_subjects = find_all_explicit(node, &method(:subject?))
117
- @subject_overrides = find_all_explicit(node, &method(:let?))
116
+ @explicit_subjects = find_all_explicit(node) { |n| subject?(n) }
117
+ @subject_overrides = find_all_explicit(node) { |n| let?(n) }
118
118
 
119
119
  find_subject_expectations(node) do |stub|
120
120
  add_offense(stub)
@@ -32,34 +32,41 @@ module RuboCop
32
32
  #
33
33
  class UnspecifiedException < Base
34
34
  MSG = 'Specify the exception being captured'
35
- RESTRICT_ON_SEND = %i[to].freeze
36
35
 
37
- # @!method empty_raise_error_or_exception(node)
38
- def_node_matcher :empty_raise_error_or_exception, <<~PATTERN
39
- (send
40
- (block
41
- (send nil? :expect) ...)
42
- :to
43
- (send nil? {:raise_error :raise_exception})
44
- )
36
+ RESTRICT_ON_SEND = %i[
37
+ raise_exception
38
+ raise_error
39
+ ].freeze
40
+
41
+ # @!method expect_to?(node)
42
+ def_node_matcher :expect_to?, <<~PATTERN
43
+ (send (block (send nil? :expect) ...) :to ...)
45
44
  PATTERN
46
45
 
47
46
  def on_send(node)
48
47
  return unless empty_exception_matcher?(node)
49
48
 
50
- add_offense(node.children.last)
49
+ add_offense(node)
51
50
  end
52
51
 
53
52
  private
54
53
 
55
54
  def empty_exception_matcher?(node)
56
- empty_raise_error_or_exception(node) && !block_with_args?(node.parent)
55
+ return false if node.arguments? || node.block_literal?
56
+
57
+ expect_to = find_expect_to(node)
58
+ return false unless expect_to
59
+ return false if expect_to.block_node&.arguments?
60
+
61
+ true
57
62
  end
58
63
 
59
- def block_with_args?(node)
60
- return false unless node&.block_type?
64
+ def find_expect_to(node)
65
+ node.each_ancestor.find do |ancestor|
66
+ break if ancestor.block_type?
61
67
 
62
- node.arguments?
68
+ expect_to?(ancestor)
69
+ end
63
70
  end
64
71
  end
65
72
  end
@@ -5,14 +5,14 @@ module RuboCop
5
5
  module RSpec
6
6
  # Checks for consistent verified double reference style.
7
7
  #
8
- # Only investigates references that are one of the supported styles.
9
- #
10
8
  # @see https://rspec.info/features/3-12/rspec-mocks/verifying-doubles
11
9
  #
12
- # This cop can be configured in your configuration using the
13
- # `EnforcedStyle` option and supports `--auto-gen-config`.
10
+ # @safety
11
+ # This cop is unsafe because the correction requires loading the class.
12
+ # Loading before stubbing causes RSpec to only allow instance methods
13
+ # to be stubbed.
14
14
  #
15
- # @example `EnforcedStyle: constant` (default)
15
+ # @example
16
16
  # # bad
17
17
  # let(:foo) do
18
18
  # instance_double('ClassName', method_name: 'returned_value')
@@ -23,18 +23,7 @@ module RuboCop
23
23
  # instance_double(ClassName, method_name: 'returned_value')
24
24
  # end
25
25
  #
26
- # @example `EnforcedStyle: string`
27
- # # bad
28
- # let(:foo) do
29
- # instance_double(ClassName, method_name: 'returned_value')
30
- # end
31
- #
32
- # # good
33
- # let(:foo) do
34
- # instance_double('ClassName', method_name: 'returned_value')
35
- # end
36
- #
37
- # @example Reference is not in the supported style list. No enforcement
26
+ # @example Reference is any dynamic variable. No enforcement
38
27
  #
39
28
  # # good
40
29
  # let(:foo) do
@@ -42,9 +31,9 @@ module RuboCop
42
31
  # end
43
32
  class VerifiedDoubleReference < Base
44
33
  extend AutoCorrector
45
- include ConfigurableEnforcedStyle
46
34
 
47
- MSG = 'Use a %<style>s class reference for verified doubles.'
35
+ MSG = 'Use a constant class reference for verified doubles. ' \
36
+ 'String references are not verifying unless the class is loaded.'
48
37
 
49
38
  RESTRICT_ON_SEND = Set[
50
39
  :class_double,
@@ -57,53 +46,25 @@ module RuboCop
57
46
  :stub_model
58
47
  ].freeze
59
48
 
60
- REFERENCE_TYPE_STYLES = {
61
- str: :string,
62
- const: :constant
63
- }.freeze
64
-
65
49
  # @!method verified_double(node)
66
50
  def_node_matcher :verified_double, <<~PATTERN
67
51
  (send
68
52
  nil?
69
53
  RESTRICT_ON_SEND
70
- $_class_reference
54
+ $str
71
55
  ...)
72
56
  PATTERN
73
57
 
74
58
  def on_send(node)
75
- verified_double(node) do |class_reference|
76
- break correct_style_detected unless opposing_style?(class_reference)
77
-
78
- message = format(MSG, style: style)
79
- expression = class_reference.source_range
80
-
81
- add_offense(expression, message: message) do |corrector|
82
- offense = class_reference.source
83
- corrector.replace(expression, correct_style(offense))
84
-
85
- opposite_style_detected
59
+ verified_double(node) do |string_argument_node|
60
+ add_offense(string_argument_node) do |corrector|
61
+ autocorrect(corrector, string_argument_node)
86
62
  end
87
63
  end
88
64
  end
89
65
 
90
- private
91
-
92
- def opposing_style?(class_reference)
93
- class_reference_style = REFERENCE_TYPE_STYLES[class_reference.type]
94
-
95
- # Only enforce supported styles
96
- return false unless class_reference_style
97
-
98
- class_reference_style != style
99
- end
100
-
101
- def correct_style(offense)
102
- if style == :string
103
- "'#{offense}'"
104
- else
105
- offense.gsub(/^['"]|['"]$/, '')
106
- end
66
+ def autocorrect(corrector, node)
67
+ corrector.replace(node, node.value)
107
68
  end
108
69
  end
109
70
  end
@@ -29,12 +29,14 @@ module RuboCop
29
29
 
30
30
  def on_send(node)
31
31
  return unless expect?(node)
32
+ return unless inside_example?(node)
32
33
 
33
34
  check_expect(node)
34
35
  end
35
36
 
36
37
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
37
38
  return unless expect_block?(node)
39
+ return unless inside_example?(node)
38
40
 
39
41
  check_expect(node)
40
42
  end
@@ -49,11 +51,14 @@ module RuboCop
49
51
 
50
52
  def void?(expect)
51
53
  parent = expect.parent
52
- return true unless parent
53
54
  return true if parent.begin_type?
54
55
 
55
56
  parent.block_type? && parent.body == expect
56
57
  end
58
+
59
+ def inside_example?(node)
60
+ node.each_ancestor(:block).any? { |ancestor| example?(ancestor) }
61
+ end
57
62
  end
58
63
  end
59
64
  end
@@ -1,29 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'rspec/capybara/current_path_expectation'
4
- require_relative 'rspec/capybara/feature_methods'
5
- require_relative 'rspec/capybara/match_style'
6
- require_relative 'rspec/capybara/negation_matcher'
7
- require_relative 'rspec/capybara/specific_actions'
8
- require_relative 'rspec/capybara/specific_finders'
9
- require_relative 'rspec/capybara/specific_matcher'
10
- require_relative 'rspec/capybara/visibility_matcher'
11
-
12
- require_relative 'rspec/factory_bot/attribute_defined_statically'
13
- require_relative 'rspec/factory_bot/consistent_parentheses_style'
14
- require_relative 'rspec/factory_bot/create_list'
15
- require_relative 'rspec/factory_bot/factory_class_name'
16
- require_relative 'rspec/factory_bot/factory_name_style'
17
- require_relative 'rspec/factory_bot/syntax_methods'
18
-
19
- require_relative 'rspec/rails/avoid_setup_hook'
20
- require_relative 'rspec/rails/have_http_status'
21
- require_relative 'rspec/rails/http_status'
22
- require_relative 'rspec/rails/inferred_spec_type'
23
- require_relative 'rspec/rails/minitest_assertions'
24
- require_relative 'rspec/rails/negation_be_valid'
25
- require_relative 'rspec/rails/travel_around'
26
-
27
3
  require_relative 'rspec/align_left_let_brace'
28
4
  require_relative 'rspec/align_right_let_brace'
29
5
  require_relative 'rspec/any_instance'
@@ -63,8 +39,8 @@ require_relative 'rspec/excessive_docstring_spacing'
63
39
  require_relative 'rspec/expect_actual'
64
40
  require_relative 'rspec/expect_change'
65
41
  require_relative 'rspec/expect_in_hook'
42
+ require_relative 'rspec/expect_in_let'
66
43
  require_relative 'rspec/expect_output'
67
- require_relative 'rspec/file_path'
68
44
  require_relative 'rspec/focus'
69
45
  require_relative 'rspec/hook_argument'
70
46
  require_relative 'rspec/hooks_before_examples'
@@ -88,6 +64,7 @@ require_relative 'rspec/message_expectation'
88
64
  require_relative 'rspec/message_spies'
89
65
  require_relative 'rspec/metadata_style'
90
66
  require_relative 'rspec/missing_example_group_argument'
67
+ require_relative 'rspec/missing_expectation_target_method'
91
68
  require_relative 'rspec/multiple_describes'
92
69
  require_relative 'rspec/multiple_expectations'
93
70
  require_relative 'rspec/multiple_memoized_helpers'
@@ -5,7 +5,6 @@ module RuboCop
5
5
  # Wrapper for RSpec DSL methods
6
6
  class Concept
7
7
  extend RuboCop::NodePattern::Macros
8
- extend Language::NodePattern
9
8
  include Language
10
9
 
11
10
  def initialize(node)
@@ -6,31 +6,7 @@ module RuboCop
6
6
  module RSpec
7
7
  # Builds a YAML config file from two config hashes
8
8
  class ConfigFormatter
9
- EXTENSION_ROOT_DEPARTMENT = %r{^(RSpec/)}.freeze
10
- SUBDEPARTMENTS = %(RSpec/Capybara RSpec/FactoryBot RSpec/Rails)
11
- EXTRACTED_COPS = %(
12
- RSpec/Capybara/CurrentPathExpectation
13
- RSpec/Capybara/MatchStyle
14
- RSpec/Capybara/NegationMatcher
15
- RSpec/Capybara/SpecificActions
16
- RSpec/Capybara/SpecificFinders
17
- RSpec/Capybara/SpecificMatcher
18
- RSpec/Capybara/VisibilityMatcher
19
- RSpec/FactoryBot/AttributeDefinedStatically
20
- RSpec/FactoryBot/ConsistentParenthesesStyle
21
- RSpec/FactoryBot/CreateList
22
- RSpec/FactoryBot/FactoryClassName
23
- RSpec/FactoryBot/FactoryNameStyle
24
- RSpec/FactoryBot/SyntaxMethods
25
- RSpec/Rails/AvoidSetupHook
26
- RSpec/Rails/HaveHttpStatus
27
- RSpec/Rails/HttpStatus
28
- RSpec/Rails/InferredSpecType
29
- RSpec/Rails/MinitestAssertions
30
- RSpec/Rails/NegationBeValid
31
- RSpec/Rails/TravelAround
32
- )
33
- AMENDMENTS = %(Metrics/BlockLength)
9
+ EXTENSION_ROOT_DEPARTMENT = %r{^RSpec/}.freeze
34
10
  COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/'
35
11
 
36
12
  def initialize(config, descriptions)
@@ -40,19 +16,15 @@ module RuboCop
40
16
 
41
17
  def dump
42
18
  YAML.dump(unified_config)
43
- .gsub(EXTENSION_ROOT_DEPARTMENT, "\n\\1")
44
- .gsub(*AMENDMENTS, "\n\\0")
45
- .gsub(/^(\s+)- /, '\1 - ')
46
- .gsub('"~"', '~')
19
+ .gsub(%r{^\w+/}, "\n\\0") # Add an extra newline before each cop.
20
+ .gsub(/^(\s+)- /, '\1 - ') # Add 2 spaces before each array element.
21
+ .gsub('"~"', '~') # Don't quote tilde, YAML's null value.
47
22
  end
48
23
 
49
24
  private
50
25
 
51
26
  def unified_config
52
27
  cops.each_with_object(config.dup) do |cop, unified|
53
- next if SUBDEPARTMENTS.include?(cop) || AMENDMENTS.include?(cop)
54
- next if EXTRACTED_COPS.include?(cop)
55
-
56
28
  replace_nil(unified[cop])
57
29
  unified[cop].merge!(descriptions.fetch(cop))
58
30
  unified[cop]['Reference'] = reference(cop)