Skip to content

Commit

Permalink
Add new Lint/RedundantWithIndex cop (#4708)
Browse files Browse the repository at this point in the history
  • Loading branch information
koic authored and bbatsov committed Sep 14, 2017
1 parent c46bf72 commit 99a5498
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
* [#4694](https://github.com/bbatsov/rubocop/pull/4694): Add new `Lint/UriRegexp` cop. ([@koic][])
* Add new `Style/MinMax` cop. ([@drenmi][])
* [#4720](https://github.com/bbatsov/rubocop/pull/4720): Add new `Bundler/InsecureProtocolSource` cop. ([@koic][])
* [#4708](https://github.com/bbatsov/rubocop/pull/4708): Add new `Lint/RedundantWithIndex` cop`. ([@koic][])

### Bug fixes

Expand Down
4 changes: 4 additions & 0 deletions config/enabled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1327,6 +1327,10 @@ Lint/RandOne:
and most likely a mistake.
Enabled: true

Lint/RedundantWithIndex:
Description: 'Checks for redundant `with_index`.'
Enabled: true

Lint/RequireParentheses:
Description: >-
Use parentheses in the method call to avoid confusion
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@
require 'rubocop/cop/lint/percent_string_array'
require 'rubocop/cop/lint/percent_symbol_array'
require 'rubocop/cop/lint/rand_one'
require 'rubocop/cop/lint/redundant_with_index'
require 'rubocop/cop/lint/require_parentheses'
require 'rubocop/cop/lint/rescue_exception'
require 'rubocop/cop/lint/rescue_type'
Expand Down
77 changes: 77 additions & 0 deletions lib/rubocop/cop/lint/redundant_with_index.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Lint
# This cop checks for redundant `with_index`.
#
# @example
# # bad
# ary.each_with_index do |v|
# v
# end
#
# # good
# ary.each do |v|
# v
# end
#
# # bad
# ary.each.with_index do |v|
# v
# end
#
# # good
# ary.each do |v|
# v
# end
#
class RedundantWithIndex < Cop
MSG_EACH_WITH_INDEX = 'Use `each` instead of `each_with_index`.'.freeze
MSG_WITH_INDEX = 'Remove redundant `with_index`.'.freeze

def_node_matcher :redundant_with_index?, <<-PATTERN
(block
$(send
_ {:each_with_index :with_index})
(args
(arg _))
...)
PATTERN

def on_block(node)
redundant_with_index?(node) do |send|
add_offense(node, with_index_range(send))
end
end

def autocorrect(node)
lambda do |corrector|
redundant_with_index?(node) do |send|
if send.method_name == :each_with_index
corrector.replace(send.loc.selector, 'each')
else
corrector.remove(send.loc.selector)
corrector.remove(send.loc.dot)
end
end
end
end

private

def message(node)
if node.method_name == :each_with_index
MSG_EACH_WITH_INDEX
else
MSG_WITH_INDEX
end
end

def with_index_range(send)
range_between(send.loc.selector.begin_pos, send.loc.selector.end_pos)
end
end
end
end
end
1 change: 1 addition & 0 deletions manual/cops.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ In the following section you find all available cops:
* [Lint/PercentStringArray](cops_lint.md#lintpercentstringarray)
* [Lint/PercentSymbolArray](cops_lint.md#lintpercentsymbolarray)
* [Lint/RandOne](cops_lint.md#lintrandone)
* [Lint/RedundantWithIndex](cops_lint.md#lintredundantwithindex)
* [Lint/RequireParentheses](cops_lint.md#lintrequireparentheses)
* [Lint/RescueException](cops_lint.md#lintrescueexception)
* [Lint/RescueType](cops_lint.md#lintrescuetype)
Expand Down
32 changes: 32 additions & 0 deletions manual/cops_lint.md
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,38 @@ rand(-1.0)
0 # just use 0 instead
```

## Lint/RedundantWithIndex

Enabled by default | Supports autocorrection
--- | ---
Enabled | Yes

This cop checks for redundant `with_index`.

### Example

```ruby
# bad
ary.each_with_index do |v|
v
end

# good
ary.each do |v|
v
end

# bad
ary.each.with_index do |v|
v
end

# good
ary.each do |v|
v
end
```

## Lint/RequireParentheses

Enabled by default | Supports autocorrection
Expand Down
50 changes: 50 additions & 0 deletions spec/rubocop/cop/lint/redundant_with_index_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

describe RuboCop::Cop::Lint::RedundantWithIndex do
let(:config) { RuboCop::Config.new }
subject(:cop) { described_class.new(config) }

it 'registers an offense when using `ary.each_with_index { |v| v }`' do
expect_offense(<<-RUBY.strip_indent)
ary.each_with_index { |v| v }
^^^^^^^^^^^^^^^ Use `each` instead of `each_with_index`.
RUBY
end

it 'registers an offense when using `ary.each.with_index { |v| v }`' do
expect_offense(<<-RUBY.strip_indent)
ary.each.with_index { |v| v }
^^^^^^^^^^ Remove redundant `with_index`.
RUBY
end

it 'registers an offense when using `ary.each_with_object([]).with_index ' \
'{ |v| v }`' do
expect_offense(<<-RUBY.strip_indent)
ary.each_with_object([]).with_index { |v| v }
^^^^^^^^^^ Remove redundant `with_index`.
RUBY
end

it 'autocorrects to ary.each from ary.each_with_index' do
new_source = autocorrect_source('ary.each_with_index { |v| v }')

expect(new_source).to eq 'ary.each { |v| v }'
end

it 'autocorrects to ary.each from ary.each.with_index' do
new_source = autocorrect_source('ary.each.with_index { |v| v }')

expect(new_source).to eq 'ary.each { |v| v }'
end

it 'autocorrects to ary.each from ary.each_with_object([]).with_index' do
new_source = autocorrect_source('ary.each_with_object([]) { |v| v }')

expect(new_source).to eq 'ary.each_with_object([]) { |v| v }'
end

it 'an index is used as a block argument' do
expect_no_offenses('ary.each_with_index { |v, i| v; i }')
end
end
2 changes: 1 addition & 1 deletion spec/rubocop/cop/rails/validation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
end
end

described_class::TYPES.each_with_index do |parameter|
described_class::TYPES.each do |parameter|
it "autocorrect validates_#{parameter}_of" do
new_source = autocorrect_source(
"validates_#{parameter}_of :full_name, :birth_date"
Expand Down

0 comments on commit 99a5498

Please sign in to comment.