rubocop-rspec 2.8.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
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