Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new
InternalAffairs/SingleLineComparison
cop.
- Loading branch information
1 parent
b976534
commit 9a2cb04
Showing
6 changed files
with
182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* [#10170](https://github.com/rubocop/rubocop/pull/10170): Add new `InternalAffairs/SingleLineComparison` cop. ([@dvandersluis][]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
lib/rubocop/cop/internal_affairs/single_line_comparison.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module InternalAffairs | ||
# Enforces the use of `node.single_line?` instead of | ||
# comparing `first_line` and `last_line` for equality. | ||
# | ||
# @example | ||
# # bad | ||
# node.loc.first_line == node.loc.last_line | ||
# | ||
# # bad | ||
# node.loc.last_line == node.loc.first_line | ||
# | ||
# # bad | ||
# node.loc.line == node.loc.last_line | ||
# | ||
# # bad | ||
# node.loc.last_line == node.loc.line | ||
# | ||
# # bad | ||
# node.first_line == node.last_line | ||
# | ||
# # good | ||
# node.single_line? | ||
# | ||
class SingleLineComparison < Base | ||
extend AutoCorrector | ||
|
||
MSG = 'Use `%<preferred>s`.' | ||
RESTRICT_ON_SEND = %i[==].freeze | ||
|
||
# @!method single_line_comparison(node) | ||
def_node_matcher :single_line_comparison, <<~PATTERN | ||
{ | ||
(send (send $_receiver {:line :first_line}) :== (send _receiver :last_line)) | ||
(send (send $_receiver :last_line) :== (send _receiver {:line :first_line})) | ||
} | ||
PATTERN | ||
|
||
def on_send(node) | ||
return unless (receiver = single_line_comparison(node)) | ||
|
||
preferred = "#{extract_receiver(receiver)}.single_line?" | ||
|
||
add_offense(node, message: format(MSG, preferred: preferred)) do |corrector| | ||
corrector.replace(node, preferred) | ||
end | ||
end | ||
|
||
private | ||
|
||
def extract_receiver(node) | ||
node = node.receiver if node.send_type? && %i[loc source_range].include?(node.method_name) | ||
node.source | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Ext | ||
# Extensions to Parser::Source::Range | ||
module Range | ||
# Adds `Range#single_line?` to parallel `Node#single_line?` | ||
def single_line? | ||
first_line == last_line | ||
end | ||
end | ||
end | ||
end | ||
|
||
Parser::Source::Range.include RuboCop::Ext::Range |
103 changes: 103 additions & 0 deletions
103
spec/rubocop/cop/internal_affairs/single_line_comparison_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::InternalAffairs::SingleLineComparison, :config do | ||
it 'registers and corrects an offense when comparing `loc.first_line` with `loc.last_line`' do | ||
expect_offense(<<~RUBY) | ||
node.loc.first_line == node.loc.last_line | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `node.single_line?`. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
node.single_line? | ||
RUBY | ||
end | ||
|
||
it 'registers and corrects an offense when comparing `loc.last_line` with `loc.first_line`' do | ||
expect_offense(<<~RUBY) | ||
node.loc.last_line == node.loc.first_line | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `node.single_line?`. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
node.single_line? | ||
RUBY | ||
end | ||
|
||
it 'registers and corrects an offense when comparing `loc.line` with `loc.last_line`' do | ||
expect_offense(<<~RUBY) | ||
node.loc.line == node.loc.last_line | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `node.single_line?`. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
node.single_line? | ||
RUBY | ||
end | ||
|
||
it 'registers and corrects an offense when comparing `loc.last_line` with `loc.line`' do | ||
expect_offense(<<~RUBY) | ||
node.loc.last_line == node.loc.line | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `node.single_line?`. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
node.single_line? | ||
RUBY | ||
end | ||
|
||
it 'registers and corrects an offense when comparing `source_range.first_line` with `source_range.last_line`' do | ||
expect_offense(<<~RUBY) | ||
node.source_range.first_line == node.source_range.last_line | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `node.single_line?`. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
node.single_line? | ||
RUBY | ||
end | ||
|
||
it 'registers and corrects an offense when comparing `source_range.last_line` with `source_range.first_line`' do | ||
expect_offense(<<~RUBY) | ||
node.source_range.last_line == node.source_range.first_line | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `node.single_line?`. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
node.single_line? | ||
RUBY | ||
end | ||
|
||
it 'registers and corrects an offense when comparing `first_line` with `last_line`' do | ||
expect_offense(<<~RUBY) | ||
node.first_line == node.last_line | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `node.single_line?`. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
node.single_line? | ||
RUBY | ||
end | ||
|
||
it 'registers and corrects an offense when comparing `last_line` with `first_line`' do | ||
expect_offense(<<~RUBY) | ||
node.last_line == node.first_line | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `node.single_line?`. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
node.single_line? | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when comparing the same line' do | ||
expect_no_offenses(<<~RUBY) | ||
node.loc.first_line == node.loc.line | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when the receivers are not a match' do | ||
expect_no_offenses(<<~RUBY) | ||
nodes.first.first_line == nodes.last.last_line | ||
RUBY | ||
end | ||
end |