Skip to content

Commit

Permalink
Support autocorrect for Style/CaseEquality cop
Browse files Browse the repository at this point in the history
  • Loading branch information
fatkodima authored and bbatsov committed Jul 18, 2020
1 parent 0117efb commit 994fe7c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 28 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,10 @@

## master (unreleased)

### New features

* [#8322](https://github.com/rubocop-hq/rubocop/pull/8322): Support autocorrect for `Style/CaseEquality` cop. ([@fatkodima][])

### Bug fixes

* [#8346](https://github.com/rubocop-hq/rubocop/pull/8346): Allow parentheses in single-line inheritance with `Style/MethodCallWithArgsParentheses` `EnforcedStyle: omit_parentheses` to fix invalid Ruby auto-correction. ([@gsamokovarov][])
Expand Down
1 change: 1 addition & 0 deletions config/default.yml
Expand Up @@ -2527,6 +2527,7 @@ Style/CaseEquality:
StyleGuide: '#no-case-equality'
Enabled: true
VersionAdded: '0.9'
VersionChanged: '0.89'
# If AllowOnConstant is enabled, the cop will ignore violations when the receiver of
# the case equality operator is a constant.
#
Expand Down
4 changes: 2 additions & 2 deletions docs/modules/ROOT/pages/cops_style.adoc
Expand Up @@ -806,9 +806,9 @@ end

| Enabled
| Yes
| No
| Yes
| 0.9
| -
| 0.89
|===

This cop checks for uses of the case equality operator(===).
Expand Down
25 changes: 22 additions & 3 deletions lib/rubocop/cop/style/case_equality.rb
Expand Up @@ -29,13 +29,20 @@ module Style
# (1..100).include?(7)
# some_string =~ /something/
#
class CaseEquality < Cop
class CaseEquality < Base
extend AutoCorrector

MSG = 'Avoid the use of the case equality operator `===`.'

def_node_matcher :case_equality?, '(send #const? :=== _)'
def_node_matcher :case_equality?, '(send $#const? :=== $_)'

def on_send(node)
case_equality?(node) { add_offense(node, location: :selector) }
case_equality?(node) do |lhs, rhs|
add_offense(node.loc.selector) do |corrector|
replacement = replacement(lhs, rhs)
corrector.replace(node, replacement) if replacement
end
end
end

private
Expand All @@ -47,6 +54,18 @@ def const?(node)
true
end
end

def replacement(lhs, rhs)
case lhs.type
when :regexp
"#{rhs.source} =~ #{lhs.source}"
when :begin
child = lhs.children.first
"#{lhs.source}.include?(#{rhs.source})" if child&.range_type?
when :const
"#{rhs.source}.is_a?(#{lhs.source})"
end
end
end
end
end
Expand Down
78 changes: 55 additions & 23 deletions spec/rubocop/cop/style/case_equality_spec.rb
@@ -1,43 +1,75 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Style::CaseEquality do
subject(:cop) { described_class.new(config) }
RSpec.describe RuboCop::Cop::Style::CaseEquality, :config do
shared_examples 'offenses' do
it 'does not fail when the receiver is implicit' do
expect_no_offenses(<<~RUBY)
puts "No offense"
RUBY
end

let(:config) { RuboCop::Config.new }
it 'registers an offense and corrects for === when the receiver is a regexp' do
expect_offense(<<~RUBY)
/OMG/ === var
^^^ Avoid the use of the case equality operator `===`.
RUBY

it 'registers an offense for ===' do
expect_offense(<<~RUBY)
Array === var
expect_correction(<<~RUBY)
var =~ /OMG/
RUBY
end

it 'registers an offense and corrects for === when the receiver is a range' do
expect_offense(<<~RUBY)
(1..10) === var
^^^ Avoid the use of the case equality operator `===`.
RUBY

expect_correction(<<~RUBY)
(1..10).include?(var)
RUBY
end

it 'registers an offense and does not correct for === when receiver is of some other type' do
expect_offense(<<~RUBY)
foo === var
^^^ Avoid the use of the case equality operator `===`.
RUBY
RUBY

expect_no_corrections
end
end

context 'when constant checks are allowed' do
let(:config) do
RuboCop::Config.new(
'Style/CaseEquality' => {
'AllowOnConstant' => true
}
)
context 'when AllowOnConstant is false' do
let(:cop_config) do
{ 'AllowOnConstant' => false }
end

it 'does not fail when the receiver is implicit' do
expect_no_offenses(<<~RUBY)
puts "No offense"
it 'registers an offense and corrects for === when the receiver is a constant' do
expect_offense(<<~RUBY)
Array === var
^^^ Avoid the use of the case equality operator `===`.
RUBY

expect_correction(<<~RUBY)
var.is_a?(Array)
RUBY
end

include_examples 'offenses'
end

context 'when AllowOnConstant is true' do
let(:cop_config) do
{ 'AllowOnConstant' => true }
end

it 'does not register an offense for === when the receiver is a constant' do
expect_no_offenses(<<~RUBY)
Array === var
RUBY
end

it 'registers an offense for === when the receiver is not a constant' do
expect_offense(<<~RUBY)
/OMG/ === "OMG"
^^^ Avoid the use of the case equality operator `===`.
RUBY
end
include_examples 'offenses'
end
end

0 comments on commit 994fe7c

Please sign in to comment.