Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new
Lint/RequireRangeParentheses
cop
## Context It emulates the following Ruby warning. ```console % cat example.rb 1... 2 ``` ```consle % ruby example.rb example.rb:1: warning: ... at EOL, should be parenthesized? ``` So, this cop will detect case like #10789. ## Summary It checks that a range literal is enclosed in parentheses when the end of the range is at a line break. ### example ```ruby # bad - Represents `(1..42)`, not endless range. 1.. 42 # good - It's incompatible, but your intentions when using endless range may be: (1..) 42 # good 1..42 # good (1..42) # good (1.. 42) ``` NOTE: The following is maybe intended for `(42..)`. But, compatible is `42..do_something`. So, this cop does not provide autocorrection because it is left to user. ```ruby case condition when 42.. do_something end ```
- Loading branch information
Showing
5 changed files
with
124 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 @@ | ||
* [#10792](https://github.com/rubocop/rubocop/pull/10792): Add new `Lint/RequireRangeParentheses` cop. ([@koic][]) |
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
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,57 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Lint | ||
# Checks that a range literal is enclosed in parentheses when the end of the range is | ||
# at a line break. | ||
# | ||
# NOTE: The following is maybe intended for `(42..)`. But, compatible is `42..do_something`. | ||
# So, this cop does not provide autocorrection because it is left to user. | ||
# | ||
# [source,ruby] | ||
# ---- | ||
# case condition | ||
# when 42.. | ||
# do_something | ||
# end | ||
# ---- | ||
# | ||
# @example | ||
# | ||
# # bad - Represents `(1..42)`, not endless range. | ||
# 1.. | ||
# 42 | ||
# | ||
# # good - It's incompatible, but your intentions when using endless range may be: | ||
# (1..) | ||
# 42 | ||
# | ||
# # good | ||
# 1..42 | ||
# | ||
# # good | ||
# (1..42) | ||
# | ||
# # good | ||
# (1.. | ||
# 42) | ||
# | ||
class RequireRangeParentheses < Base | ||
MSG = 'Wrap the endless range literal `%<range>s` to avoid precedence ambiguity.' | ||
|
||
def on_irange(node) | ||
return if node.parent&.begin_type? | ||
return unless node.begin && node.end | ||
return if same_line?(node.begin, node.end) | ||
|
||
message = format(MSG, range: "#{node.begin.source}#{node.loc.operator.source}") | ||
|
||
add_offense(node, message: message) | ||
end | ||
|
||
alias on_erange on_irange | ||
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,60 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::Lint::RequireRangeParentheses, :config do | ||
it 'registers an offense when the end of the range (`..`) is line break' do | ||
expect_offense(<<~RUBY) | ||
42.. | ||
^^^^ Wrap the endless range literal `42..` to avoid precedence ambiguity. | ||
do_something | ||
RUBY | ||
end | ||
|
||
it 'registers an offense when the end of the range (`...`) is line break' do | ||
expect_offense(<<~RUBY) | ||
42... | ||
^^^^^ Wrap the endless range literal `42...` to avoid precedence ambiguity. | ||
do_something | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when the end of the range (`..`) is line break and is enclosed in parentheses' do | ||
expect_no_offenses(<<~RUBY) | ||
(42.. | ||
do_something) | ||
RUBY | ||
end | ||
|
||
context 'Ruby >= 2.6', :ruby26 do | ||
it 'does not register an offense when using endless range only' do | ||
expect_no_offenses(<<~RUBY) | ||
42.. | ||
RUBY | ||
end | ||
end | ||
|
||
context 'Ruby >= 2.7', :ruby27 do | ||
it 'does not register an offense when using beginless range only' do | ||
expect_no_offenses(<<~RUBY) | ||
..42 | ||
RUBY | ||
end | ||
end | ||
|
||
it 'does not register an offense when using `42..nil`' do | ||
expect_no_offenses(<<~RUBY) | ||
42..nil | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when using `nil..42`' do | ||
expect_no_offenses(<<~RUBY) | ||
nil..42 | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when begin and end of the range are on the same line' do | ||
expect_no_offenses(<<~RUBY) | ||
42..do_something | ||
RUBY | ||
end | ||
end |