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

Support Ruby 2.7's pattern matching for Style/ConditionalAssignment #9948

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 @@
* [#9948](https://github.com/rubocop/rubocop/pull/9948): Support Ruby 2.7's pattern matching for `Style/ConditionalAssignment` cop. ([@koic][])
24 changes: 19 additions & 5 deletions lib/rubocop/cop/style/conditional_assignment.rb
Expand Up @@ -26,7 +26,7 @@ def expand_elses(branch)
# `when` nodes contain the entire branch including the condition.
# We only need the contents of the branch, not the condition.
def expand_when_branches(when_branches)
when_branches.map { |branch| branch.children[1] }
when_branches.map(&:body)
end

def tail(branch)
Expand Down Expand Up @@ -272,6 +272,16 @@ def on_case(node)
check_node(node, branches)
end

def on_case_match(node)
return unless style == :assign_to_condition
return unless node.else_branch

in_pattern_branches = expand_when_branches(node.in_pattern_branches)
branches = [*in_pattern_branches, node.else_branch]

check_node(node, branches)
end

private

def check_assignment_to_condition(node)
Expand All @@ -297,7 +307,7 @@ def candidate_node?(node)
end

# @!method candidate_condition?(node)
def_node_matcher :candidate_condition?, '[{if case} !#allowed_ternary?]'
def_node_matcher :candidate_condition?, '[{if case case_match} !#allowed_ternary?]'

def allowed_ternary?(assignment)
assignment.if_type? && assignment.ternary? && !include_ternary?
Expand All @@ -319,7 +329,7 @@ def assignment_node(node)
end

def move_assignment_outside_condition(corrector, node)
if node.case_type?
if node.case_type? || node.case_match_type?
CaseCorrector.correct(corrector, self, node)
elsif node.ternary?
TernaryCorrector.correct(corrector, node)
Expand All @@ -333,7 +343,7 @@ def move_assignment_inside_condition(corrector, node)

if ternary_condition?(condition)
TernaryCorrector.move_assignment_inside_condition(corrector, node)
elsif condition.case_type?
elsif condition.case_type? || condition.case_match_type?
CaseCorrector.move_assignment_inside_condition(corrector, node)
elsif condition.if_type?
IfCorrector.move_assignment_inside_condition(corrector, node)
Expand Down Expand Up @@ -631,7 +641,11 @@ def extract_tail_branches(node)
end

def extract_branches(case_node)
when_branches = expand_when_branches(case_node.when_branches)
when_branches = if case_node.case_type?
expand_when_branches(case_node.when_branches)
else
expand_when_branches(case_node.in_pattern_branches)
end

[when_branches, case_node.else_branch]
end
Expand Down
Expand Up @@ -126,6 +126,33 @@
RUBY
end

context '>= Ruby 2.7', :ruby27 do
it 'registers an offense for assigning any variable type to case in' do
expect_offense(<<~RUBY, variable: variable)
%{variable} = case foo
^{variable}^^^^^^^^^^^ Assign variables inside of conditionals
in "a"
1
in "b"
2
else
3
end
RUBY

expect_correction(<<~RUBY)
case foo
in "a"
#{variable} = 1
in "b"
#{variable} = 2
else
#{variable} = 3
end
RUBY
end
end

it 'does not crash for rescue assignment' do
expect_no_offenses(<<~RUBY)
begin
Expand Down
Expand Up @@ -271,6 +271,30 @@
#{indent}end
RUBY
end

context '>= Ruby 2.7', :ruby27 do
it 'corrects comparison methods in case in' do
expect_offense(<<~RUBY)
case foo
^^^^^^^^ Use the return of the conditional for variable assignment and comparison.
in bar
a #{method} b
else
a #{method} d
end
RUBY

indent = ' ' * "a #{method} ".length if indent_end
expect_correction(<<~RUBY)
a #{method} case foo
in bar
b
else
d
#{indent}end
RUBY
end
end
end
end
end
Expand Down