From 714b13d9af4d58fb545cd7d2a8269c759e59f389 Mon Sep 17 00:00:00 2001 From: fatkodima Date: Wed, 22 Jul 2020 18:05:23 +0300 Subject: [PATCH] Support autocorrect for `Lint/Loop` cop --- CHANGELOG.md | 1 + config/default.yml | 1 + docs/modules/ROOT/pages/cops_lint.adoc | 4 ++-- lib/rubocop/cop/lint/loop.rb | 23 ++++++++++++++++++++- spec/rubocop/cop/lint/loop_spec.rb | 28 +++++++++++++++++++++----- 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 120deeb36b9..34ad1fa511a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * [#8432](https://github.com/rubocop-hq/rubocop/pull/8432): Add new `Lint/FloatComparison` cop. ([@fatkodima][]) * [#8376](https://github.com/rubocop-hq/rubocop/pull/8376): Add new `Lint/MissingSuper` cop. ([@fatkodima][]) * [#8415](https://github.com/rubocop-hq/rubocop/pull/8415): Add new `Style/ExplicitBlockArgument` cop. ([@fatkodima][]) +* [#8383](https://github.com/rubocop-hq/rubocop/pull/8383): Support autocorrect for `Lint/Loop` cop. ([@fatkodima][]) * [#8339](https://github.com/rubocop-hq/rubocop/pull/8339): Add `Config#for_badge` as an efficient way to get a cop's config merged with its department's. ([@marcandre][]) * [#5067](https://github.com/rubocop-hq/rubocop/issues/5067): Add new `Style/StringConcatenation` cop. ([@fatkodima][]) * [#7425](https://github.com/rubocop-hq/rubocop/pull/7425): Add new `Lint/TopLevelReturnWithArgument` cop. ([@iamravitejag][]) diff --git a/config/default.yml b/config/default.yml index 10d1abc5640..32de0b76987 100644 --- a/config/default.yml +++ b/config/default.yml @@ -1559,6 +1559,7 @@ Lint/Loop: StyleGuide: '#loop-with-break' Enabled: true VersionAdded: '0.9' + VersionChanged: '0.89' Lint/MissingCopEnableDirective: Description: 'Checks for a `# rubocop:enable` after `# rubocop:disable`.' diff --git a/docs/modules/ROOT/pages/cops_lint.adoc b/docs/modules/ROOT/pages/cops_lint.adoc index 48e6d40e41e..8ae0fa273cb 100644 --- a/docs/modules/ROOT/pages/cops_lint.adoc +++ b/docs/modules/ROOT/pages/cops_lint.adoc @@ -1711,9 +1711,9 @@ This cop checks for interpolated literals. | Enabled | Yes -| No +| Yes | 0.9 -| - +| 0.89 |=== This cop checks for uses of `begin...end while/until something`. diff --git a/lib/rubocop/cop/lint/loop.rb b/lib/rubocop/cop/lint/loop.rb index 63674b67f34..b0cb38278a3 100644 --- a/lib/rubocop/cop/lint/loop.rb +++ b/lib/rubocop/cop/lint/loop.rb @@ -43,6 +43,8 @@ module Lint # break if some_condition # end class Loop < Base + extend AutoCorrector + MSG = 'Use `Kernel#loop` with `break` rather than ' \ '`begin/end/until`(or `while`).' @@ -57,7 +59,26 @@ def on_until_post(node) private def register_offense(node) - add_offense(node.loc.keyword) + body = node.body + + add_offense(node.loc.keyword) do |corrector| + corrector.replace(body.loc.begin, 'loop do') + corrector.remove(keyword_and_condition_range(node)) + corrector.insert_before(body.loc.end, build_break_line(node)) + end + end + + def keyword_and_condition_range(node) + node.body.loc.end.end.join(node.source_range.end) + end + + def build_break_line(node) + conditional_keyword = node.while_post_type? ? 'unless' : 'if' + "break #{conditional_keyword} #{node.condition.source}\n#{indent(node)}" + end + + def indent(node) + ' ' * node.loc.column end end end diff --git a/spec/rubocop/cop/lint/loop_spec.rb b/spec/rubocop/cop/lint/loop_spec.rb index 4333f563131..dc37b668bf8 100644 --- a/spec/rubocop/cop/lint/loop_spec.rb +++ b/spec/rubocop/cop/lint/loop_spec.rb @@ -3,17 +3,35 @@ RSpec.describe RuboCop::Cop::Lint::Loop do subject(:cop) { described_class.new } - it 'registers an offense for begin/end/while' do + it 'registers an offense and corrects for begin/end/while' do expect_offense(<<~RUBY) - begin something; top; end while test - ^^^^^ Use `Kernel#loop` with `break` rather than `begin/end/until`(or `while`). + begin + something + end while test + ^^^^^ Use `Kernel#loop` with `break` rather than `begin/end/until`(or `while`). + RUBY + + expect_correction(<<~RUBY) + loop do + something + break unless test + end RUBY end it 'registers an offense for begin/end/until' do expect_offense(<<~RUBY) - begin something; top; end until test - ^^^^^ Use `Kernel#loop` with `break` rather than `begin/end/until`(or `while`). + begin + something + end until test + ^^^^^ Use `Kernel#loop` with `break` rather than `begin/end/until`(or `while`). + RUBY + + expect_correction(<<~RUBY) + loop do + something + break if test + end RUBY end