diff --git a/changelog/fix_an_incorrect_autocorrect_for_style_multiline_ternary_operator.md b/changelog/fix_an_incorrect_autocorrect_for_style_multiline_ternary_operator.md new file mode 100644 index 00000000000..a705628312b --- /dev/null +++ b/changelog/fix_an_incorrect_autocorrect_for_style_multiline_ternary_operator.md @@ -0,0 +1 @@ +* [#10537](https://github.com/rubocop/rubocop/pull/10537): Fix an incorrect auto-correct for `Style/MultilineTernaryOperator` when returning a multiline ternary operator expression with `break`, `next`, or method call. ([@koic][]) diff --git a/lib/rubocop/cop/style/multiline_ternary_operator.rb b/lib/rubocop/cop/style/multiline_ternary_operator.rb index 81cf41467e6..7d1bdbf57e6 100644 --- a/lib/rubocop/cop/style/multiline_ternary_operator.rb +++ b/lib/rubocop/cop/style/multiline_ternary_operator.rb @@ -6,7 +6,8 @@ module Style # This cop checks for multi-line ternary op expressions. # # NOTE: `return if ... else ... end` is syntax error. If `return` is used before - # multiline ternary operator expression, it cannot be auto-corrected. + # multiline ternary operator expression, it will be auto-corrected to single-line + # ternary operator. The same is true for `break`, `next`, and method call. # # @example # # bad @@ -18,6 +19,10 @@ module Style # b : # c # + # return cond ? + # b : + # c + # # # good # a = cond ? b : c # a = if cond @@ -25,20 +30,39 @@ module Style # else # c # end + # + # return cond ? b : c + # class MultilineTernaryOperator < Base extend AutoCorrector - MSG = 'Avoid multi-line ternary operators, use `if` or `unless` instead.' + MSG_IF = 'Avoid multi-line ternary operators, use `if` or `unless` instead.' + MSG_SINGLE_LINE = 'Avoid multi-line ternary operators, use single-line instead.' + SINGLE_LINE_TYPES = %i[return break next send].freeze def on_if(node) return unless offense?(node) - add_offense(node) do |corrector| - # `return if ... else ... end` is syntax error. If `return` is used before - # multiline ternary operator expression, it cannot be auto-corrected. - next unless offense?(node) && !node.parent.return_type? + message = enforce_single_line_ternary_operator?(node) ? MSG_SINGLE_LINE : MSG_IF + + add_offense(node, message: message) do |corrector| + next unless offense?(node) + + corrector.replace(node, replacement(node)) + end + end + + private - corrector.replace(node, <<~RUBY.chop) + def offense?(node) + node.ternary? && node.multiline? + end + + def replacement(node) + if enforce_single_line_ternary_operator?(node) + "#{node.condition.source} ? #{node.if_branch.source} : #{node.else_branch.source}" + else + <<~RUBY.chop if #{node.condition.source} #{node.if_branch.source} else @@ -48,10 +72,8 @@ def on_if(node) end end - private - - def offense?(node) - node.ternary? && node.multiline? + def enforce_single_line_ternary_operator?(node) + SINGLE_LINE_TYPES.include?(node.parent.type) end end end diff --git a/spec/rubocop/cop/style/multiline_ternary_operator_spec.rb b/spec/rubocop/cop/style/multiline_ternary_operator_spec.rb index b00c5b9a5e3..30ad1edbef5 100644 --- a/spec/rubocop/cop/style/multiline_ternary_operator_spec.rb +++ b/spec/rubocop/cop/style/multiline_ternary_operator_spec.rb @@ -51,15 +51,56 @@ RUBY end - it 'register an offense and does not auto-correct when returning a multiline ternary operator expression' do + it 'register an offense and corrects when returning a multiline ternary operator expression with `return`' do expect_offense(<<~RUBY) return cond ? - ^^^^^^ Avoid multi-line ternary operators, use `if` or `unless` instead. + ^^^^^^ Avoid multi-line ternary operators, use single-line instead. foo : bar RUBY - expect_no_corrections + expect_correction(<<~RUBY) + return cond ? foo : bar + RUBY + end + + it 'register an offense and corrects when returning a multiline ternary operator expression with `break`' do + expect_offense(<<~RUBY) + break cond ? + ^^^^^^ Avoid multi-line ternary operators, use single-line instead. + foo : + bar + RUBY + + expect_correction(<<~RUBY) + break cond ? foo : bar + RUBY + end + + it 'register an offense and corrects when returning a multiline ternary operator expression with `next`' do + expect_offense(<<~RUBY) + next cond ? + ^^^^^^ Avoid multi-line ternary operators, use single-line instead. + foo : + bar + RUBY + + expect_correction(<<~RUBY) + next cond ? foo : bar + RUBY + end + + it 'register an offense and corrects when returning a multiline ternary operator expression with method call' do + expect_offense(<<~RUBY) + do_something cond ? + ^^^^^^ Avoid multi-line ternary operators, use single-line instead. + foo : + bar + RUBY + + expect_correction(<<~RUBY) + do_something cond ? foo : bar + RUBY end it 'accepts a single line ternary operator expression' do