From 83d500fd4fe9b8942b49cc2486bd4b9dbad2ea8b Mon Sep 17 00:00:00 2001 From: Daniel Vandersluis Date: Wed, 22 Jun 2022 13:14:43 -0400 Subject: [PATCH] [Fix #10734] Handle `ClobberingError` in `Style/NestedTernaryOperator` when there are multiple nested ternaries. --- changelog/fix_handle_clobberingerror_in.md | 1 + .../cop/style/nested_ternary_operator.rb | 26 +++++++++++---- .../cop/style/nested_ternary_operator_spec.rb | 32 +++++++++++++++---- 3 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 changelog/fix_handle_clobberingerror_in.md diff --git a/changelog/fix_handle_clobberingerror_in.md b/changelog/fix_handle_clobberingerror_in.md new file mode 100644 index 00000000000..4d4f3ee30c9 --- /dev/null +++ b/changelog/fix_handle_clobberingerror_in.md @@ -0,0 +1 @@ +* [#10734](https://github.com/rubocop/rubocop/issues/10734): Handle `ClobberingError` in `Style/NestedTernaryOperator` when there are multiple nested ternaries. ([@dvandersluis][]) diff --git a/lib/rubocop/cop/style/nested_ternary_operator.rb b/lib/rubocop/cop/style/nested_ternary_operator.rb index 01657718c43..9ee729fd44b 100644 --- a/lib/rubocop/cop/style/nested_ternary_operator.rb +++ b/lib/rubocop/cop/style/nested_ternary_operator.rb @@ -17,6 +17,8 @@ module Style # end class NestedTernaryOperator < Base extend AutoCorrector + include RangeHelp + include IgnoredNode MSG = 'Ternary operators must not be nested. Prefer `if` or `else` constructs instead.' @@ -26,14 +28,10 @@ def on_if(node) node.each_descendant(:if).select(&:ternary?).each do |nested_ternary| add_offense(nested_ternary) do |corrector| if_node = if_node(nested_ternary) + next if part_of_ignored_node?(if_node) - corrector.replace(if_node, <<~RUBY.chop) - if #{if_node.condition.source} - #{remove_parentheses(if_node.if_branch.source)} - else - #{if_node.else_branch.source} - end - RUBY + autocorrect(corrector, if_node) + ignore_node(if_node) end end end @@ -47,11 +45,25 @@ def if_node(node) if_node(node) end + def autocorrect(corrector, if_node) + replace_loc_and_whitespace(corrector, if_node.loc.question, "\n") + replace_loc_and_whitespace(corrector, if_node.loc.colon, "\nelse\n") + corrector.replace(if_node.if_branch, remove_parentheses(if_node.if_branch.source)) + corrector.wrap(if_node, 'if ', "\nend") + end + def remove_parentheses(source) return source unless source.start_with?('(') source.delete_prefix('(').delete_suffix(')') end + + def replace_loc_and_whitespace(corrector, range, replacement) + corrector.replace( + range_with_surrounding_space(range: range, whitespace: true), + replacement + ) + end end end end diff --git a/spec/rubocop/cop/style/nested_ternary_operator_spec.rb b/spec/rubocop/cop/style/nested_ternary_operator_spec.rb index 9b5135cb2d1..c5983e9dce4 100644 --- a/spec/rubocop/cop/style/nested_ternary_operator_spec.rb +++ b/spec/rubocop/cop/style/nested_ternary_operator_spec.rb @@ -9,9 +9,9 @@ expect_correction(<<~RUBY) if a - b ? b1 : b2 + b ? b1 : b2 else - a2 + a2 end RUBY end @@ -25,9 +25,9 @@ expect_correction(<<~RUBY) if cond - foo + foo else - bar(foo.a ? foo.b : foo) { |e, k| e.nil? ? nil : e[k] } + bar(foo.a ? foo.b : foo) { |e, k| e.nil? ? nil : e[k] } end RUBY end @@ -40,9 +40,9 @@ expect_correction(<<~RUBY) if x - y + (z ? 1 : 0) + y + (z ? 1 : 0) else - nil + nil end RUBY end @@ -56,4 +56,24 @@ end RUBY end + + it 'can handle multiple nested ternaries' do + expect_offense(<<~RUBY) + a ? b : c ? d : e ? f : g + ^^^^^^^^^ Ternary operators must not be nested. Prefer `if` or `else` constructs instead. + ^^^^^^^^^^^^^^^^^ Ternary operators must not be nested. Prefer `if` or `else` constructs instead. + RUBY + + expect_correction(<<~RUBY) + if a + b + else + if c + d + else + e ? f : g + end + end + RUBY + end end