From 39fcf1c5684915adad4a9ab8babb93f37367fba8 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 24 Jul 2021 01:37:30 +0900 Subject: [PATCH] Support Ruby 2.7's pattern matching for `Style/ConditionalAssignment` This PR supports Ruby 2.7's pattern matching for `Style/ConditionalAssignment`. This `Style/IdenticalConditionalBranches` cop is detecting for `if` and `case`. Therefore, I think about detecting `case-match` with the cop instead of a new cop. --- ...tching_for_style_conditional_assignment.md | 1 + .../cop/style/conditional_assignment.rb | 24 +++++++++++++---- ...nal_assignment_assign_in_condition_spec.rb | 27 +++++++++++++++++++ ...nal_assignment_assign_to_condition_spec.rb | 24 +++++++++++++++++ 4 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 changelog/new_support_pattern_matching_for_style_conditional_assignment.md diff --git a/changelog/new_support_pattern_matching_for_style_conditional_assignment.md b/changelog/new_support_pattern_matching_for_style_conditional_assignment.md new file mode 100644 index 00000000000..1f66f890a16 --- /dev/null +++ b/changelog/new_support_pattern_matching_for_style_conditional_assignment.md @@ -0,0 +1 @@ +* [#9948](https://github.com/rubocop/rubocop/pull/9948): Support Ruby 2.7's pattern matching for `Style/ConditionalAssignment` cop. ([@koic][]) diff --git a/lib/rubocop/cop/style/conditional_assignment.rb b/lib/rubocop/cop/style/conditional_assignment.rb index 64b774788dc..79bc3db1779 100644 --- a/lib/rubocop/cop/style/conditional_assignment.rb +++ b/lib/rubocop/cop/style/conditional_assignment.rb @@ -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) @@ -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) @@ -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? @@ -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) @@ -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) @@ -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 diff --git a/spec/rubocop/cop/style/conditional_assignment_assign_in_condition_spec.rb b/spec/rubocop/cop/style/conditional_assignment_assign_in_condition_spec.rb index 4f511bb1b4d..a83dfedeae8 100644 --- a/spec/rubocop/cop/style/conditional_assignment_assign_in_condition_spec.rb +++ b/spec/rubocop/cop/style/conditional_assignment_assign_in_condition_spec.rb @@ -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 diff --git a/spec/rubocop/cop/style/conditional_assignment_assign_to_condition_spec.rb b/spec/rubocop/cop/style/conditional_assignment_assign_to_condition_spec.rb index 6598633fa75..48a4d4fb7a4 100644 --- a/spec/rubocop/cop/style/conditional_assignment_assign_to_condition_spec.rb +++ b/spec/rubocop/cop/style/conditional_assignment_assign_to_condition_spec.rb @@ -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