Skip to content

Commit

Permalink
Merge pull request #10928 from r7kamura/feature/each
Browse files Browse the repository at this point in the history
Add more autocorrect support on `Style/EachForSimpleLoop`
  • Loading branch information
koic authored Aug 30, 2022
2 parents 3088078 + 03574fa commit 65cec7c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 12 deletions.
1 change: 1 addition & 0 deletions changelog/change_autocorrect_0origin_range_with_block.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#10928](https://github.com/rubocop/rubocop/pull/10928): Add more autocorrect support on `Style/EachForSimpleLoop`. ([@r7kamura][])
45 changes: 40 additions & 5 deletions lib/rubocop/cop/style/each_for_simple_loop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ class EachForSimpleLoop < Base
MSG = 'Use `Integer#times` for a simple loop which iterates a fixed number of times.'

def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless offending_each_range(node)
return unless offending?(node)

send_node = node.send_node

range = send_node.receiver.source_range.join(send_node.loc.selector)

add_offense(range) do |corrector|
range_type, min, max = offending_each_range(node)
range_type, min, max = each_range(node)

max += 1 if range_type == :irange

Expand All @@ -45,9 +45,44 @@ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler

private

# @!method offending_each_range(node)
def_node_matcher :offending_each_range, <<~PATTERN
(block (send (begin (${irange erange} (int $_) (int $_))) :each) (args) ...)
def offending?(node)
each_range_with_zero_origin?(node) || each_range_without_block_argument?(node)
end

# @!method each_range(node)
def_node_matcher :each_range, <<~PATTERN
(block
(send
(begin
(${irange erange}
(int $_) (int $_)))
:each)
(args ...)
...)
PATTERN

# @!method each_range_with_zero_origin?(node)
def_node_matcher :each_range_with_zero_origin?, <<~PATTERN
(block
(send
(begin
({irange erange}
(int 0) (int _)))
:each)
(args ...)
...)
PATTERN

# @!method each_range_without_block_argument?(node)
def_node_matcher :each_range_without_block_argument?, <<~PATTERN
(block
(send
(begin
({irange erange}
(int _) (int _)))
:each)
(args)
...)
PATTERN
end
end
Expand Down
31 changes: 24 additions & 7 deletions spec/rubocop/cop/style/each_for_simple_loop_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,32 @@
expect_no_offenses('(0..b).each {}')
end

it 'does not register offense for inline block with parameters' do
expect_no_offenses('(0..10).each { |n| puts n }')
context 'with inline block with parameters' do
it 'autocorrects an offense' do
expect_offense(<<~RUBY)
(0...10).each { |n| }
^^^^^^^^^^^^^ Use `Integer#times` for a simple loop which iterates a fixed number of times.
RUBY

expect_correction(<<~RUBY)
10.times { |n| }
RUBY
end
end

it 'does not register offense for multiline block with parameters' do
expect_no_offenses(<<~RUBY)
(0..10).each do |n|
end
RUBY
context 'with multiline block with parameters' do
it 'autocorrects an offense' do
expect_offense(<<~RUBY)
(0...10).each do |n|
^^^^^^^^^^^^^ Use `Integer#times` for a simple loop which iterates a fixed number of times.
end
RUBY

expect_correction(<<~RUBY)
10.times do |n|
end
RUBY
end
end

it 'does not register offense for character range' do
Expand Down

0 comments on commit 65cec7c

Please sign in to comment.