rubocop-rspec 2.8.0 → 2.11.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4786aaf8f829745dafce927499fd98671a0b8ab08a61a9c99eafc26fb7235926
4
- data.tar.gz: 38e23b1194fb915f42f4399fe6be1b6c950de10d367300a01226549e15747f93
3
+ metadata.gz: 8b1c8f65ec3429d357c99302f307f318750117e2329719e4cffc60123546a356
4
+ data.tar.gz: 178b52063271fe727162e196b6a364254e86a7343233ee8d15ad2d27f812367d
5
5
  SHA512:
6
- metadata.gz: 39bb13d4cfe09307955f392935c626fb8b920e2b38a33323464e15fb9a7248c88db27259cab8c118df4ebb5888c11973e04e2e5f3ce58e64e1f18486801ac3c7
7
- data.tar.gz: 51fa7212f5b0576b0fbfcf88c57cff79612934695f8f8f1b6c3106006b5e6dd1eff08c06cfe60fcd8a994e3eccd51810c61b208e398b708090f3e257d0bed3e8
6
+ metadata.gz: fdc010e5813ab0d100c50da5686ce10dfff440fb279c01a0f7c0a99f5066202cea53789cbee6d3792b75cc22ce1574e6f06f216822a7ebb960e39f8ad8994139
7
+ data.tar.gz: 055a453f761b8d6ebda211002f2d0265deb4cdc2f8b5567d71cf28d25bcba7d34a1be7f88bd3e7768e29671bb278aa9af4bb6bc910e42008ee083c4c33525cc4
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 2.11.0 (2022-05-18)
6
+
7
+ * Drop Ruby 2.5 support. ([@ydah][])
8
+ * Add new `RSpec/ChangeByZero` cop. ([@ydah][])
9
+ * Improve `RSpec/ExpectChange` to detect namespaced and top-level constants. ([@M-Yamashita01][])
10
+ * Introduce an amendment to `Metrics/BlockLength` to exclude spec files. ([@luke-hill][])
11
+
12
+ ## 2.10.0 (2022-04-19)
13
+
14
+ * Fix a false positive for `RSpec/EmptyExampleGroup` when expectations in case statement. ([@ydah][])
15
+ * Add `RSpec/VerifiedDoubleReference` cop. ([@t3h2mas][])
16
+ * Make `RSpec/BeNil` cop configurable with a `be_nil` style and a `be` style. ([@bquorning][])
17
+ * Fix `Capybara/CurrentPathExpectation` autocorrect incompatible with `Style/TrailingCommaInArguments` autocorrect. ([@ydah][])
18
+
19
+ ## 2.9.0 (2022-02-28)
20
+
21
+ * Add new `RSpec/BeNil` cop. ([@bquorning][])
22
+ * Add new `RSpec/BeEq` cop. ([@bquorning][])
23
+
5
24
  ## 2.8.0 (2022-01-24)
6
25
 
7
26
  * Fix `RSpec/FactoryBot/SyntaxMethods` and `RSpec/Capybara/FeatureMethods` to inspect shared groups. ([@pirj][])
@@ -667,3 +686,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
667
686
  [@leoarnold]: https://github.com/leoarnold
668
687
  [@harry-graham]: https://github.com/harry-graham
669
688
  [@oshiro3]: https://github.com/oshiro3
689
+ [@ydah]: https://github.com/ydah
690
+ [@t3h2mas]: https://github.com/t3h2mas
691
+ [@M-Yamashita01]: https://github.com/M-Yamashita01
692
+ [@luke-hill]: https://github.com/luke-hill
data/config/default.yml CHANGED
@@ -110,6 +110,14 @@ RSpec:
110
110
  - subject
111
111
  - subject!
112
112
 
113
+ Metrics/BlockLength:
114
+ inherit_mode:
115
+ merge:
116
+ - Exclude
117
+ Exclude:
118
+ - "**/*_spec.rb"
119
+ - "**/spec/**/*"
120
+
113
121
  RSpec/AlignLeftLetBrace:
114
122
  Description: Checks that left braces for adjacent single line lets are aligned.
115
123
  Enabled: false
@@ -142,12 +150,29 @@ RSpec/Be:
142
150
  StyleGuide: https://rspec.rubystyle.guide/#be-matcher
143
151
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Be
144
152
 
153
+ RSpec/BeEq:
154
+ Description: Check for expectations where `be(...)` can replace `eq(...)`.
155
+ Enabled: pending
156
+ VersionAdded: 2.9.0
157
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEq
158
+
145
159
  RSpec/BeEql:
146
160
  Description: Check for expectations where `be(...)` can replace `eql(...)`.
147
161
  Enabled: true
148
162
  VersionAdded: '1.7'
149
163
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEql
150
164
 
165
+ RSpec/BeNil:
166
+ Description: Ensures a consistent style is used when matching `nil`.
167
+ Enabled: pending
168
+ EnforcedStyle: be_nil
169
+ SupportedStyles:
170
+ - be
171
+ - be_nil
172
+ VersionAdded: 2.9.0
173
+ VersionChanged: 2.10.0
174
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeNil
175
+
151
176
  RSpec/BeforeAfterAll:
152
177
  Description: Check that before/after(:all) isn't being used.
153
178
  Enabled: true
@@ -159,6 +184,12 @@ RSpec/BeforeAfterAll:
159
184
  StyleGuide: https://rspec.rubystyle.guide/#avoid-hooks-with-context-scope
160
185
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeforeAfterAll
161
186
 
187
+ RSpec/ChangeByZero:
188
+ Description: Prefer negated matchers over `to change.by(0)`.
189
+ Enabled: pending
190
+ VersionAdded: 2.11.0
191
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero
192
+
162
193
  RSpec/ContextMethod:
163
194
  Description: "`context` should not be used for specifying methods."
164
195
  Enabled: true
@@ -239,7 +270,7 @@ RSpec/DescribedClassModuleWrapping:
239
270
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClassModuleWrapping
240
271
 
241
272
  RSpec/Dialect:
242
- Description: This cop enforces custom RSpec dialects.
273
+ Description: Enforces custom RSpec dialects.
243
274
  Enabled: false
244
275
  PreferredMethods: {}
245
276
  VersionAdded: '1.33'
@@ -749,6 +780,16 @@ RSpec/VariableName:
749
780
  VersionChanged: '1.43'
750
781
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName
751
782
 
783
+ RSpec/VerifiedDoubleReference:
784
+ Description: Checks for consistent verified double reference style.
785
+ Enabled: pending
786
+ EnforcedStyle: constant
787
+ SupportedStyles:
788
+ - constant
789
+ - string
790
+ VersionAdded: 2.10.0
791
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference
792
+
752
793
  RSpec/VerifiedDoubles:
753
794
  Description: Prefer using verifying doubles over normal doubles.
754
795
  Enabled: true
@@ -760,13 +801,13 @@ RSpec/VerifiedDoubles:
760
801
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubles
761
802
 
762
803
  RSpec/VoidExpect:
763
- Description: This cop checks void `expect()`.
804
+ Description: Checks void `expect()`.
764
805
  Enabled: true
765
806
  VersionAdded: '1.16'
766
807
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VoidExpect
767
808
 
768
809
  RSpec/Yield:
769
- Description: This cop checks for calling a block within a stub.
810
+ Description: Checks for calling a block within a stub.
770
811
  Enabled: true
771
812
  VersionAdded: '1.32'
772
813
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Yield
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Check for expectations where `be(...)` can replace `eq(...)`.
7
+ #
8
+ # The `be` matcher compares by identity while the `eq` matcher compares
9
+ # using `==`. Booleans and nil can be compared by identity and therefore
10
+ # the `be` matcher is preferable as it is a more strict test.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # expect(foo).to eq(true)
16
+ # expect(foo).to eq(false)
17
+ # expect(foo).to eq(nil)
18
+ #
19
+ # # good
20
+ # expect(foo).to be(true)
21
+ # expect(foo).to be(false)
22
+ # expect(foo).to be(nil)
23
+ #
24
+ class BeEq < Base
25
+ extend AutoCorrector
26
+
27
+ MSG = 'Prefer `be` over `eq`.'
28
+ RESTRICT_ON_SEND = %i[eq].freeze
29
+
30
+ # @!method eq_type_with_identity?(node)
31
+ def_node_matcher :eq_type_with_identity?, <<-PATTERN
32
+ (send nil? :eq {true false nil})
33
+ PATTERN
34
+
35
+ def on_send(node)
36
+ return unless eq_type_with_identity?(node)
37
+
38
+ add_offense(node.loc.selector) do |corrector|
39
+ corrector.replace(node.loc.selector, 'be')
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -43,7 +43,7 @@ module RuboCop
43
43
 
44
44
  # @!method eql_type_with_identity(node)
45
45
  def_node_matcher :eql_type_with_identity, <<-PATTERN
46
- (send _ :to $(send nil? :eql {true false int float sym nil_type?}))
46
+ (send _ :to $(send nil? :eql {true false int float sym nil}))
47
47
  PATTERN
48
48
 
49
49
  def on_send(node)
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Ensures a consistent style is used when matching `nil`.
7
+ #
8
+ # You can either use the more specific `be_nil` matcher, or the more
9
+ # generic `be` matcher with a `nil` argument.
10
+ #
11
+ # This cop can be configured using the `EnforcedStyle` option
12
+ #
13
+ # @example `EnforcedStyle: be_nil` (default)
14
+ # # bad
15
+ # expect(foo).to be(nil)
16
+ #
17
+ # # good
18
+ # expect(foo).to be_nil
19
+ #
20
+ # @example `EnforcedStyle: be`
21
+ # # bad
22
+ # expect(foo).to be_nil
23
+ #
24
+ # # good
25
+ # expect(foo).to be(nil)
26
+ #
27
+ class BeNil < Base
28
+ extend AutoCorrector
29
+ include ConfigurableEnforcedStyle
30
+
31
+ BE_MSG = 'Prefer `be(nil)` over `be_nil`.'
32
+ BE_NIL_MSG = 'Prefer `be_nil` over `be(nil)`.'
33
+ RESTRICT_ON_SEND = %i[be be_nil].freeze
34
+
35
+ # @!method be_nil_matcher?(node)
36
+ def_node_matcher :be_nil_matcher?, <<-PATTERN
37
+ (send nil? :be_nil)
38
+ PATTERN
39
+
40
+ # @!method nil_value_expectation?(node)
41
+ def_node_matcher :nil_value_expectation?, <<-PATTERN
42
+ (send nil? :be nil)
43
+ PATTERN
44
+
45
+ def on_send(node)
46
+ case style
47
+ when :be
48
+ check_be_style(node)
49
+ when :be_nil
50
+ check_be_nil_style(node)
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def check_be_style(node)
57
+ return unless be_nil_matcher?(node)
58
+
59
+ add_offense(node, message: BE_MSG) do |corrector|
60
+ corrector.replace(node.loc.expression, 'be(nil)')
61
+ end
62
+ end
63
+
64
+ def check_be_nil_style(node)
65
+ return unless nil_value_expectation?(node)
66
+
67
+ add_offense(node, message: BE_NIL_MSG) do |corrector|
68
+ corrector.replace(node.loc.expression, 'be_nil')
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -52,6 +52,10 @@ module RuboCop
52
52
  $(send nil? :match (str $_)))
53
53
  PATTERN
54
54
 
55
+ def self.autocorrect_incompatible_with
56
+ [Style::TrailingCommaInArguments]
57
+ end
58
+
55
59
  def on_send(node)
56
60
  expectation_set_on_current_path(node) do
57
61
  add_offense(node.loc.selector) do |corrector|
@@ -46,7 +46,7 @@ module RuboCop
46
46
 
47
47
  MSG = 'Use `%<replacement>s` instead of `%<method>s`.'
48
48
 
49
- # https://git.io/v7Kwr
49
+ # https://github.com/teamcapybara/capybara/blob/e283c1aeaa72441f5403963577e16333bf111a81/lib/capybara/rspec/features.rb#L31-L36
50
50
  MAP = {
51
51
  background: :before,
52
52
  scenario: :it,
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Prefer negated matchers over `to change.by(0)`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # expect { run }.to change(Foo, :bar).by(0)
11
+ # expect { run }.to change { Foo.bar }.by(0)
12
+ # expect { run }
13
+ # .to change(Foo, :bar).by(0)
14
+ # .and change(Foo, :baz).by(0)
15
+ # expect { run }
16
+ # .to change { Foo.bar }.by(0)
17
+ # .and change { Foo.baz }.by(0)
18
+ #
19
+ # # good
20
+ # expect { run }.not_to change(Foo, :bar)
21
+ # expect { run }.not_to change { Foo.bar }
22
+ # expect { run }
23
+ # .to not_change(Foo, :bar)
24
+ # .and not_change(Foo, :baz)
25
+ # expect { run }
26
+ # .to not_change { Foo.bar }
27
+ # .and not_change { Foo.baz }
28
+ #
29
+ class ChangeByZero < Base
30
+ extend AutoCorrector
31
+ MSG = 'Prefer `not_to change` over `to change.by(0)`.'
32
+ MSG_COMPOUND = 'Prefer negated matchers with compound expectations ' \
33
+ 'over `change.by(0)`.'
34
+ RESTRICT_ON_SEND = %i[change].freeze
35
+
36
+ # @!method expect_change_with_arguments(node)
37
+ def_node_matcher :expect_change_with_arguments, <<-PATTERN
38
+ (send
39
+ (send nil? :change ...) :by
40
+ (int 0))
41
+ PATTERN
42
+
43
+ # @!method expect_change_with_block(node)
44
+ def_node_matcher :expect_change_with_block, <<-PATTERN
45
+ (send
46
+ (block
47
+ (send nil? :change)
48
+ (args)
49
+ (send (...) $_)) :by
50
+ (int 0))
51
+ PATTERN
52
+
53
+ def on_send(node)
54
+ expect_change_with_arguments(node.parent) do
55
+ check_offence(node.parent)
56
+ end
57
+
58
+ expect_change_with_block(node.parent.parent) do
59
+ check_offence(node.parent.parent)
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def check_offence(node)
66
+ expression = node.loc.expression
67
+ if compound_expectations?(node)
68
+ add_offense(expression, message: MSG_COMPOUND)
69
+ else
70
+ add_offense(expression) do |corrector|
71
+ autocorrect(corrector, node)
72
+ end
73
+ end
74
+ end
75
+
76
+ def compound_expectations?(node)
77
+ %i[and or].include?(node.parent.method_name)
78
+ end
79
+
80
+ def autocorrect(corrector, node)
81
+ corrector.replace(node.parent.loc.selector, 'not_to')
82
+ range = node.loc.dot.with(end_pos: node.loc.expression.end_pos)
83
+ corrector.remove(range)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -78,9 +78,8 @@ module RuboCop
78
78
  PATTERN
79
79
 
80
80
  # @!method contains_described_class?(node)
81
- def_node_search :contains_described_class?, <<-PATTERN
82
- (send nil? :described_class)
83
- PATTERN
81
+ def_node_search :contains_described_class?,
82
+ '(send nil? :described_class)'
84
83
 
85
84
  def on_block(node)
86
85
  # In case the explicit style is used, we need to remember what's
@@ -129,17 +128,13 @@ module RuboCop
129
128
  end
130
129
 
131
130
  def scope_change?(node)
132
- scope_changing_syntax?(node) ||
131
+ scope_changing_syntax?(node) ||
133
132
  common_instance_exec_closure?(node) ||
134
133
  skippable_block?(node)
135
134
  end
136
135
 
137
136
  def skippable_block?(node)
138
- node.block_type? && !rspec_block?(node) && skip_blocks?
139
- end
140
-
141
- def skip_blocks?
142
- cop_config['SkipBlocks']
137
+ node.block_type? && !rspec_block?(node) && cop_config['SkipBlocks']
143
138
  end
144
139
 
145
140
  def offensive?(node)
@@ -152,6 +147,7 @@ module RuboCop
152
147
 
153
148
  def offensive_described_class?(node)
154
149
  return unless node.const_type?
150
+
155
151
  # E.g. `described_class::CONSTANT`
156
152
  return if contains_described_class?(node)
157
153
 
@@ -172,14 +168,13 @@ module RuboCop
172
168
  # @return [Array<Symbol>]
173
169
  # @example
174
170
  # # nil represents base constant
175
- # collapse_namespace([], :C) # => [:C]
176
- # collapse_namespace([:A, :B], [:C) # => [:A, :B, :C]
177
- # collapse_namespace([:A, :B], [:B, :C) # => [:A, :B, :C]
178
- # collapse_namespace([:A, :B], [nil, :C) # => [nil, :C]
179
- # collapse_namespace([:A, :B], [nil, :B, :C) # => [nil, :B, :C]
171
+ # collapse_namespace([], [:C]) # => [:C]
172
+ # collapse_namespace([:A, :B], [:C]) # => [:A, :B, :C]
173
+ # collapse_namespace([:A, :B], [:B, :C]) # => [:A, :B, :C]
174
+ # collapse_namespace([:A, :B], [nil, :C]) # => [nil, :C]
175
+ # collapse_namespace([:A, :B], [nil, :B, :C]) # => [nil, :B, :C]
180
176
  def collapse_namespace(namespace, const)
181
- return const if namespace.empty?
182
- return const if const.first.nil?
177
+ return const if namespace.empty? || const.first.nil?
183
178
 
184
179
  start = [0, (namespace.length - const.length)].max
185
180
  max = namespace.length
@@ -196,9 +191,7 @@ module RuboCop
196
191
  # const_name(s(:const, s(:const, nil, :M), :C)) # => [:M, :C]
197
192
  # const_name(s(:const, s(:cbase), :C)) # => [nil, :C]
198
193
  def const_name(node)
199
- # rubocop:disable InternalAffairs/NodeDestructuring
200
- namespace, name = *node
201
- # rubocop:enable InternalAffairs/NodeDestructuring
194
+ namespace, name = *node # rubocop:disable InternalAffairs/NodeDestructuring
202
195
  if !namespace
203
196
  [name]
204
197
  elsif namespace.const_type?
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- # This cop enforces custom RSpec dialects.
6
+ # Enforces custom RSpec dialects.
7
7
  #
8
8
  # A dialect can be based on the following RSpec methods:
9
9
  #
@@ -145,7 +145,7 @@ module RuboCop
145
145
  return true unless body
146
146
  return false if conditionals_with_examples?(body)
147
147
 
148
- if body.if_type?
148
+ if body.if_type? || body.case_type?
149
149
  !examples_in_branches?(body)
150
150
  else
151
151
  !examples?(body)
@@ -153,15 +153,15 @@ module RuboCop
153
153
  end
154
154
 
155
155
  def conditionals_with_examples?(body)
156
- return unless body.begin_type?
156
+ return unless body.begin_type? || body.case_type?
157
157
 
158
- body.each_descendant(:if).any? do |if_node|
159
- examples_in_branches?(if_node)
158
+ body.each_descendant(:if, :case).any? do |condition_node|
159
+ examples_in_branches?(condition_node)
160
160
  end
161
161
  end
162
162
 
163
- def examples_in_branches?(if_node)
164
- if_node.branches.any? { |branch| examples?(branch) }
163
+ def examples_in_branches?(condition_node)
164
+ condition_node.branches.any? { |branch| examples?(branch) }
165
165
  end
166
166
  end
167
167
  end
@@ -39,7 +39,7 @@ module RuboCop
39
39
 
40
40
  # @!method expect_change_with_arguments(node)
41
41
  def_node_matcher :expect_change_with_arguments, <<-PATTERN
42
- (send nil? :change $_ (sym $_))
42
+ (send nil? :change $_ ({sym str} $_))
43
43
  PATTERN
44
44
 
45
45
  # @!method expect_change_with_block(node)
@@ -47,7 +47,7 @@ module RuboCop
47
47
  (block
48
48
  (send nil? :change)
49
49
  (args)
50
- (send ({const send} nil? $_) $_)
50
+ (send $_ $_)
51
51
  )
52
52
  PATTERN
53
53
 
@@ -67,9 +67,9 @@ module RuboCop
67
67
  return unless style == :method_call
68
68
 
69
69
  expect_change_with_block(node) do |receiver, message|
70
- msg = format(MSG_BLOCK, obj: receiver, attr: message)
70
+ msg = format(MSG_BLOCK, obj: receiver.source, attr: message)
71
71
  add_offense(node, message: msg) do |corrector|
72
- replacement = "change(#{receiver}, :#{message})"
72
+ replacement = "change(#{receiver.source}, :#{message})"
73
73
  corrector.replace(node, replacement)
74
74
  end
75
75
  end
@@ -24,7 +24,7 @@ module RuboCop
24
24
  # rubocop:disable InternalAffairs/NodeDestructuring
25
25
  variable_name, _rhs = *node
26
26
  # rubocop:enable InternalAffairs/NodeDestructuring
27
- name = variable_name[1..-1]
27
+ name = variable_name[1..]
28
28
  return unless name.eql?('stdout') || name.eql?('stderr')
29
29
 
30
30
  add_offense(node.loc.name, message: format(MSG, name: name))
@@ -47,7 +47,7 @@ module RuboCop
47
47
  def correct_variable(variable)
48
48
  case variable.type
49
49
  when :dsym
50
- variable.source[1..-1]
50
+ variable.source[1..]
51
51
  when :sym
52
52
  variable.value.to_s.inspect
53
53
  else
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for consistent verified double reference style.
7
+ #
8
+ # Only investigates references that are one of the supported styles.
9
+ #
10
+ # @see https://relishapp.com/rspec/rspec-mocks/docs/verifying-doubles
11
+ #
12
+ # This cop can be configured in your configuration using the
13
+ # `EnforcedStyle` option and supports `--auto-gen-config`.
14
+ #
15
+ # @example `EnforcedStyle: constant` (default)
16
+ # # bad
17
+ # let(:foo) do
18
+ # instance_double('ClassName', method_name: 'returned_value')
19
+ # end
20
+ #
21
+ # # good
22
+ # let(:foo) do
23
+ # instance_double(ClassName, method_name: 'returned_value')
24
+ # end
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
38
+ #
39
+ # # good
40
+ # let(:foo) do
41
+ # instance_double(@klass, method_name: 'returned_value')
42
+ # end
43
+ class VerifiedDoubleReference < Base
44
+ extend AutoCorrector
45
+ include ConfigurableEnforcedStyle
46
+
47
+ MSG = 'Use a %<style>s class reference for verified doubles.'
48
+
49
+ RESTRICT_ON_SEND = Set[
50
+ :class_double,
51
+ :class_spy,
52
+ :instance_double,
53
+ :instance_spy,
54
+ :mock_model,
55
+ :object_double,
56
+ :object_spy,
57
+ :stub_model
58
+ ].freeze
59
+
60
+ REFERENCE_TYPE_STYLES = {
61
+ str: :string,
62
+ const: :constant
63
+ }.freeze
64
+
65
+ # @!method verified_double(node)
66
+ def_node_matcher :verified_double, <<~PATTERN
67
+ (send
68
+ nil?
69
+ RESTRICT_ON_SEND
70
+ $_class_reference
71
+ ...)
72
+ PATTERN
73
+
74
+ 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.loc.expression
80
+
81
+ add_offense(expression, message: message) do |corrector|
82
+ violation = class_reference.children.last.to_s
83
+ corrector.replace(expression, correct_style(violation))
84
+
85
+ opposite_style_detected
86
+ end
87
+ end
88
+ end
89
+
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(violation)
102
+ if style == :string
103
+ "'#{violation}'"
104
+ else
105
+ violation
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- # This cop checks void `expect()`.
6
+ # Checks void `expect()`.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- # This cop checks for calling a block within a stub.
6
+ # Checks for calling a block within a stub.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -21,8 +21,11 @@ require_relative 'rspec/align_right_let_brace'
21
21
  require_relative 'rspec/any_instance'
22
22
  require_relative 'rspec/around_block'
23
23
  require_relative 'rspec/be'
24
+ require_relative 'rspec/be_eq'
24
25
  require_relative 'rspec/be_eql'
26
+ require_relative 'rspec/be_nil'
25
27
  require_relative 'rspec/before_after_all'
28
+ require_relative 'rspec/change_by_zero'
26
29
  require_relative 'rspec/context_method'
27
30
  require_relative 'rspec/context_wording'
28
31
  require_relative 'rspec/describe_class'
@@ -95,6 +98,7 @@ require_relative 'rspec/subject_stub'
95
98
  require_relative 'rspec/unspecified_exception'
96
99
  require_relative 'rspec/variable_definition'
97
100
  require_relative 'rspec/variable_name'
101
+ require_relative 'rspec/verified_double_reference'
98
102
  require_relative 'rspec/verified_doubles'
99
103
  require_relative 'rspec/void_expect'
100
104
  require_relative 'rspec/yield'
@@ -8,6 +8,7 @@ module RuboCop
8
8
  class ConfigFormatter
9
9
  EXTENSION_ROOT_DEPARTMENT = %r{^(RSpec/)}.freeze
10
10
  SUBDEPARTMENTS = %(RSpec/Capybara RSpec/FactoryBot RSpec/Rails)
11
+ AMENDMENTS = %(Metrics/BlockLength)
11
12
  COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/'
12
13
 
13
14
  def initialize(config, descriptions)
@@ -18,6 +19,7 @@ module RuboCop
18
19
  def dump
19
20
  YAML.dump(unified_config)
20
21
  .gsub(EXTENSION_ROOT_DEPARTMENT, "\n\\1")
22
+ .gsub(*AMENDMENTS, "\n\\0")
21
23
  .gsub(/^(\s+)- /, '\1 - ')
22
24
  end
23
25
 
@@ -26,6 +28,7 @@ module RuboCop
26
28
  def unified_config
27
29
  cops.each_with_object(config.dup) do |cop, unified|
28
30
  next if SUBDEPARTMENTS.include?(cop)
31
+ next if AMENDMENTS.include?(cop)
29
32
 
30
33
  unified[cop].merge!(descriptions.fetch(cop))
31
34
  unified[cop]['Reference'] = COP_DOC_BASE_URL + cop.sub('RSpec/', '')
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '2.8.0'
7
+ STRING = '2.11.0'
8
8
  end
9
9
  end
10
10
  end
data/lib/rubocop-rspec.rb CHANGED
@@ -37,16 +37,21 @@ require_relative 'rubocop/cop/rspec_cops'
37
37
  # We have to register our autocorrect incompatibilities in RuboCop's cops
38
38
  # as well so we do not hit infinite loops
39
39
 
40
- module RuboCop
41
- module Cop
42
- module Layout
43
- class ExtraSpacing # rubocop:disable Style/Documentation
44
- def self.autocorrect_incompatible_with
45
- [RSpec::AlignLeftLetBrace, RSpec::AlignRightLetBrace]
46
- end
47
- end
40
+ RuboCop::Cop::Layout::ExtraSpacing.singleton_class.prepend(
41
+ Module.new do
42
+ def autocorrect_incompatible_with
43
+ super.push(RuboCop::Cop::RSpec::AlignLeftLetBrace)
44
+ .push(RuboCop::Cop::RSpec::AlignRightLetBrace)
48
45
  end
49
46
  end
50
- end
47
+ )
48
+
49
+ RuboCop::Cop::Style::TrailingCommaInArguments.singleton_class.prepend(
50
+ Module.new do
51
+ def autocorrect_incompatible_with
52
+ super.push(RuboCop::Cop::RSpec::Capybara::CurrentPathExpectation)
53
+ end
54
+ end
55
+ )
51
56
 
52
57
  RuboCop::AST::Node.include(RuboCop::RSpec::Node)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Backus
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-01-24 00:00:00.000000000 Z
13
+ date: 2022-05-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -135,11 +135,14 @@ files:
135
135
  - lib/rubocop/cop/rspec/around_block.rb
136
136
  - lib/rubocop/cop/rspec/base.rb
137
137
  - lib/rubocop/cop/rspec/be.rb
138
+ - lib/rubocop/cop/rspec/be_eq.rb
138
139
  - lib/rubocop/cop/rspec/be_eql.rb
140
+ - lib/rubocop/cop/rspec/be_nil.rb
139
141
  - lib/rubocop/cop/rspec/before_after_all.rb
140
142
  - lib/rubocop/cop/rspec/capybara/current_path_expectation.rb
141
143
  - lib/rubocop/cop/rspec/capybara/feature_methods.rb
142
144
  - lib/rubocop/cop/rspec/capybara/visibility_matcher.rb
145
+ - lib/rubocop/cop/rspec/change_by_zero.rb
143
146
  - lib/rubocop/cop/rspec/context_method.rb
144
147
  - lib/rubocop/cop/rspec/context_wording.rb
145
148
  - lib/rubocop/cop/rspec/describe_class.rb
@@ -224,6 +227,7 @@ files:
224
227
  - lib/rubocop/cop/rspec/unspecified_exception.rb
225
228
  - lib/rubocop/cop/rspec/variable_definition.rb
226
229
  - lib/rubocop/cop/rspec/variable_name.rb
230
+ - lib/rubocop/cop/rspec/verified_double_reference.rb
227
231
  - lib/rubocop/cop/rspec/verified_doubles.rb
228
232
  - lib/rubocop/cop/rspec/void_expect.rb
229
233
  - lib/rubocop/cop/rspec/yield.rb
@@ -259,14 +263,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
259
263
  requirements:
260
264
  - - ">="
261
265
  - !ruby/object:Gem::Version
262
- version: 2.5.0
266
+ version: 2.6.0
263
267
  required_rubygems_version: !ruby/object:Gem::Requirement
264
268
  requirements:
265
269
  - - ">="
266
270
  - !ruby/object:Gem::Version
267
271
  version: '0'
268
272
  requirements: []
269
- rubygems_version: 3.3.1
273
+ rubygems_version: 3.1.6
270
274
  signing_key:
271
275
  specification_version: 4
272
276
  summary: Code style checking for RSpec files