Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new Style/MultilineInPatternThen cop #9834

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1 @@
* [#9834](https://github.com/rubocop/rubocop/pull/9834): Add new `Style/MultilineInPatternThen` cop. ([@koic][])
6 changes: 6 additions & 0 deletions config/default.yml
Expand Up @@ -3836,6 +3836,12 @@ Style/MultilineIfThen:
VersionAdded: '0.9'
VersionChanged: '0.26'

Style/MultilineInPatternThen:
Description: 'Do not use `then` for multi-line `in` statement.'
StyleGuide: '#no-then'
Enabled: pending
VersionAdded: '<<next>>'

Style/MultilineMemoization:
Description: 'Wrap multiline memoizations in a `begin` and `end` block.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -502,6 +502,7 @@
require_relative 'rubocop/cop/style/line_end_concatenation'
require_relative 'rubocop/cop/style/method_call_without_args_parentheses'
require_relative 'rubocop/cop/style/method_call_with_args_parentheses'
require_relative 'rubocop/cop/style/multiline_in_pattern_then'
require_relative 'rubocop/cop/style/redundant_assignment'
require_relative 'rubocop/cop/style/redundant_fetch_block'
require_relative 'rubocop/cop/style/redundant_file_extension_in_require'
Expand Down
62 changes: 62 additions & 0 deletions lib/rubocop/cop/style/multiline_in_pattern_then.rb
@@ -0,0 +1,62 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Style
# This cop checks uses of the `then` keyword in multi-line `in` statement.
#
# @example
# # bad
# case expression
# in pattern then
# end
#
# # good
# case expression
# in pattern
# end
#
# # good
# case expression
# in pattern then do_something
# end
#
# # good
# case expression
# in pattern then do_something(arg1,
# arg2)
# end
#
class MultilineInPatternThen < Base
include RangeHelp
extend AutoCorrector
extend TargetRubyVersion

minimum_target_ruby_version 2.7

MSG = 'Do not use `then` for multiline `in` statement.'

def on_in_pattern(node)
return if !node.then? || require_then?(node)

range = node.loc.begin
add_offense(range) do |corrector|
corrector.remove(
range_with_surrounding_space(range: range, side: :left, newlines: false)
)
end
end

private

# Requires `then` for write `in` and its body on the same line.
def require_then?(in_pattern_node)
return true if in_pattern_node.pattern.first_line != in_pattern_node.pattern.last_line
return false unless in_pattern_node.body

in_pattern_node.loc.line == in_pattern_node.body.loc.line
end
end
end
end
end
2 changes: 1 addition & 1 deletion rubocop.gemspec
Expand Up @@ -35,7 +35,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency('rainbow', '>= 2.2.2', '< 4.0')
s.add_runtime_dependency('regexp_parser', '>= 1.8', '< 3.0')
s.add_runtime_dependency('rexml')
s.add_runtime_dependency('rubocop-ast', '>= 1.6.0', '< 2.0')
s.add_runtime_dependency('rubocop-ast', '>= 1.7.0', '< 2.0')
s.add_runtime_dependency('ruby-progressbar', '~> 1.7')
s.add_runtime_dependency('unicode-display_width', '>= 1.4.0', '< 3.0')

Expand Down
160 changes: 160 additions & 0 deletions spec/rubocop/cop/style/multiline_in_pattern_then_spec.rb
@@ -0,0 +1,160 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Style::MultilineInPatternThen, :config do
context '>= Ruby 2.7', :ruby27 do
it 'registers an offense for empty `in` statement with `then`' do
expect_offense(<<~RUBY)
case foo
in bar then
^^^^ Do not use `then` for multiline `in` statement.
end
RUBY

expect_correction(<<~RUBY)
case foo
in bar
end
RUBY
end

it 'registers an offense for multiline (one line in a body) `in` statement with `then`' do
expect_offense(<<~RUBY)
case foo
in bar then
^^^^ Do not use `then` for multiline `in` statement.
do_something
end
RUBY

expect_correction(<<~RUBY)
case foo
in bar
do_something
end
RUBY
end

it 'registers an offense for multiline (two lines in a body) `in` statement with `then`' do
expect_offense(<<~RUBY)
case foo
in bar then
^^^^ Do not use `then` for multiline `in` statement.
do_something1
do_something2
end
RUBY

expect_correction(<<~RUBY)
case foo
in bar
do_something1
do_something2
end
RUBY
end

it "doesn't register an offense for singleline `in` statement with `then`" do
expect_no_offenses(<<~RUBY)
case foo
in bar then do_something
end
RUBY
end

it "doesn't register an offense when `then` required for a body of `in` is used" do
expect_no_offenses(<<~RUBY)
case cond
in foo then do_something(arg1,
arg2)
end
RUBY
end

it "doesn't register an offense for multiline `in` statement with `then` followed by other lines" do
expect_no_offenses(<<~RUBY)
case foo
in bar then do_something
do_another_thing
end
RUBY
end

it "doesn't register an offense for empty `in` statement without `then`" do
expect_no_offenses(<<~RUBY)
case foo
in bar
end
RUBY
end

it "doesn't register an offense for multiline `in` statement without `then`" do
expect_no_offenses(<<~RUBY)
case foo
in bar
do_something
end
RUBY
end

it 'does not register an offense for hash `in` statement with `then`' do
expect_no_offenses(<<~RUBY)
case condition
in foo then {
key: 'value'
}
end
RUBY
end

it 'does not register an offense for array `when` statement with `then`' do
expect_no_offenses(<<~RUBY)
case condition
in foo then [
'element'
]
end
RUBY
end

it 'autocorrects when the body of `in` branch starts with `then`' do
expect_offense(<<~RUBY)
case foo
in bar
then do_something
^^^^ Do not use `then` for multiline `in` statement.
end
RUBY

expect_correction(<<~RUBY)
case foo
in bar
do_something
end
RUBY
end

it 'registers an offense when one line for multiple condidate values of `in`' do
expect_offense(<<~RUBY)
case foo
in bar, baz then
^^^^ Do not use `then` for multiline `in` statement.
end
RUBY

expect_correction(<<~RUBY)
case foo
in bar, baz
end
RUBY
end

it 'does not register an offense when line break for multiple condidate values of `in`' do
expect_no_offenses(<<~RUBY)
case foo
in bar,
baz then do_something
end
RUBY
end
end
end