Skip to content

Commit d0de0b7

Browse files
authored
Merge pull request #1251 from rubocop/configurable-be-nil
Make `RSpec/BeNil` cop configurable
2 parents b56d287 + 7949379 commit d0de0b7

File tree

5 files changed

+136
-34
lines changed

5 files changed

+136
-34
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# Changelog
22

33
## Master (Unreleased)
4-
* Add `RSpec/VerifiedDoubleReference` cop. ([@t3h2mas][])
54

65
* Fix a false positive for `RSpec/EmptyExampleGroup` when expectations in case statement. ([@ydah][])
6+
* Add `RSpec/VerifiedDoubleReference` cop. ([@t3h2mas][])
7+
* Make `RSpec/BeNil` cop configurable with a `be_nil` style and a `be` style. ([@bquorning][])
78

89
## 2.9.0 (2022-02-28)
910

config/default.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,14 @@ RSpec/BeEql:
155155
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEql
156156

157157
RSpec/BeNil:
158-
Description: Check that `be_nil` is used instead of `be(nil)`.
158+
Description: Ensures a consistent style is used when matching `nil`.
159159
Enabled: pending
160+
EnforcedStyle: be_nil
161+
SupportedStyles:
162+
- be
163+
- be_nil
160164
VersionAdded: 2.9.0
165+
VersionChanged: 2.10.0
161166
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeNil
162167

163168
RSpec/BeforeAfterAll:

docs/modules/ROOT/pages/cops_rspec.adoc

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,16 +283,20 @@ expect(foo).to be(nil)
283283
| Yes
284284
| Yes
285285
| 2.9.0
286-
| -
286+
| 2.10.0
287287
|===
288288

289-
Check that `be_nil` is used instead of `be(nil)`.
289+
Ensures a consistent style is used when matching `nil`.
290+
291+
You can either use the more specific `be_nil` matcher, or the more
292+
generic `be` matcher with a `nil` argument.
290293

291-
RSpec has a built-in `be_nil` matcher specifically for expecting `nil`.
292-
For consistent specs, we recommend using that instead of `be(nil)`.
294+
This cop can be configured using the `EnforcedStyle` option
293295

294296
=== Examples
295297

298+
==== `EnforcedStyle: be_nil` (default)
299+
296300
[source,ruby]
297301
----
298302
# bad
@@ -302,6 +306,27 @@ expect(foo).to be(nil)
302306
expect(foo).to be_nil
303307
----
304308

309+
==== `EnforcedStyle: be`
310+
311+
[source,ruby]
312+
----
313+
# bad
314+
expect(foo).to be_nil
315+
316+
# good
317+
expect(foo).to be(nil)
318+
----
319+
320+
=== Configurable attributes
321+
322+
|===
323+
| Name | Default value | Configurable values
324+
325+
| EnforcedStyle
326+
| `be_nil`
327+
| `be`, `be_nil`
328+
|===
329+
305330
=== References
306331

307332
* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeNil

lib/rubocop/cop/rspec/be_nil.rb

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,68 @@
33
module RuboCop
44
module Cop
55
module RSpec
6-
# Check that `be_nil` is used instead of `be(nil)`.
6+
# Ensures a consistent style is used when matching `nil`.
77
#
8-
# RSpec has a built-in `be_nil` matcher specifically for expecting `nil`.
9-
# For consistent specs, we recommend using that instead of `be(nil)`.
8+
# You can either use the more specific `be_nil` matcher, or the more
9+
# generic `be` matcher with a `nil` argument.
1010
#
11-
# @example
11+
# This cop can be configured using the `EnforcedStyle` option
1212
#
13+
# @example `EnforcedStyle: be_nil` (default)
1314
# # bad
1415
# expect(foo).to be(nil)
1516
#
1617
# # good
1718
# expect(foo).to be_nil
1819
#
20+
# @example `EnforcedStyle: be`
21+
# # bad
22+
# expect(foo).to be_nil
23+
#
24+
# # good
25+
# expect(foo).to be(nil)
26+
#
1927
class BeNil < Base
2028
extend AutoCorrector
29+
include ConfigurableEnforcedStyle
2130

22-
MSG = 'Prefer `be_nil` over `be(nil)`.'
23-
RESTRICT_ON_SEND = %i[be].freeze
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
2439

2540
# @!method nil_value_expectation?(node)
2641
def_node_matcher :nil_value_expectation?, <<-PATTERN
2742
(send nil? :be nil)
2843
PATTERN
2944

3045
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)
3165
return unless nil_value_expectation?(node)
3266

33-
add_offense(node) do |corrector|
67+
add_offense(node, message: BE_NIL_MSG) do |corrector|
3468
corrector.replace(node.loc.expression, 'be_nil')
3569
end
3670
end

spec/rubocop/cop/rspec/be_nil_spec.rb

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,67 @@
11
# frozen_string_literal: true
22

33
RSpec.describe RuboCop::Cop::RSpec::BeNil do
4-
it 'registers an offense when using `#be` for `nil` value' do
5-
expect_offense(<<~RUBY)
6-
expect(foo).to be(nil)
7-
^^^^^^^ Prefer `be_nil` over `be(nil)`.
8-
RUBY
9-
10-
expect_correction(<<~RUBY)
11-
expect(foo).to be_nil
12-
RUBY
4+
let(:cop_config) do
5+
{ 'EnforcedStyle' => enforced_style }
136
end
147

15-
it 'does not register an offense when using `#be_nil`' do
16-
expect_no_offenses(<<~RUBY)
17-
expect(foo).to be_nil
18-
RUBY
8+
context 'with EnforcedStyle `be_nil`' do
9+
let(:enforced_style) { 'be_nil' }
10+
11+
it 'registers an offense when using `#be` for `nil` value' do
12+
expect_offense(<<~RUBY)
13+
expect(foo).to be(nil)
14+
^^^^^^^ Prefer `be_nil` over `be(nil)`.
15+
RUBY
16+
17+
expect_correction(<<~RUBY)
18+
expect(foo).to be_nil
19+
RUBY
20+
end
21+
22+
it 'does not register an offense when using `#be_nil`' do
23+
expect_no_offenses(<<~RUBY)
24+
expect(foo).to be_nil
25+
RUBY
26+
end
27+
28+
it 'does not register an offense when using `#be` with other values' do
29+
expect_no_offenses(<<~RUBY)
30+
expect(foo).to be(true)
31+
expect(foo).to be(false)
32+
expect(foo).to be(1)
33+
expect(foo).to be("yes")
34+
expect(foo).to be(Class.new)
35+
RUBY
36+
end
1937
end
2038

21-
it 'does not register an offense when using `#be` with other values' do
22-
expect_no_offenses(<<~RUBY)
23-
expect(foo).to be(true)
24-
expect(foo).to be(false)
25-
expect(foo).to be(1)
26-
expect(foo).to be("yes")
27-
expect(foo).to be(Class.new)
28-
RUBY
39+
context 'with EnforcedStyle `be`' do
40+
let(:enforced_style) { 'be' }
41+
42+
it 'does not register an offense when using `#be` for `nil` value' do
43+
expect_no_offenses(<<~RUBY)
44+
expect(foo).to be(nil)
45+
RUBY
46+
end
47+
48+
it 'registers an offense when using `#be_nil`' do
49+
expect_offense(<<~RUBY)
50+
expect(foo).to be_nil
51+
^^^^^^ Prefer `be(nil)` over `be_nil`.
52+
RUBY
53+
54+
expect_correction(<<~RUBY)
55+
expect(foo).to be(nil)
56+
RUBY
57+
end
58+
59+
it 'does not register an offense when using other `#be_*` methods' do
60+
expect_no_offenses(<<~RUBY)
61+
expect(foo).to be_truthy
62+
expect(foo).to be_falsey
63+
expect(foo).to be_fooish
64+
RUBY
65+
end
2966
end
3067
end

0 commit comments

Comments
 (0)