class RubbyCop::Cop::Style::TernaryParentheses

This cop checks for the presence of parentheses around ternary conditions. It is configurable to enforce inclusion or omission of parentheses using `EnforcedStyle`. Omission is only enforced when removing the parentheses won't cause a different behavior.

@example

EnforcedStyle: require_no_parentheses (default)

@bad
foo = (bar?) ? a : b
foo = (bar.baz?) ? a : b
foo = (bar && baz) ? a : b

@good
foo = bar? ? a : b
foo = bar.baz? ? a : b
foo = bar && baz ? a : b

@example

EnforcedStyle: require_parentheses

@bad
foo = bar? ? a : b
foo = bar.baz? ? a : b
foo = bar && baz ? a : b

@good
foo = (bar?) ? a : b
foo = (bar.baz?) ? a : b
foo = (bar && baz) ? a : b

@example

EnforcedStyle: require_parentheses_when_complex

@bad
foo = (bar?) ? a : b
foo = (bar.baz?) ? a : b
foo = bar && baz ? a : b

@good
foo = bar? ? a : b
foo = bar.baz? ? a : b
foo = (bar && baz) ? a : b

Constants

MSG
MSG_COMPLEX

Public Instance Methods

on_if(node) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 61
def on_if(node)
  return unless node.ternary? && !infinite_loop? && offense?(node)

  add_offense(node, node.source_range, message(node))
end

Private Instance Methods

autocorrect(node) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 85
def autocorrect(node)
  condition = node.condition

  return nil if parenthesized?(condition) &&
                (safe_assignment?(condition) ||
                unsafe_autocorrect?(condition))

  if parenthesized?(condition)
    correct_parenthesized(condition)
  else
    correct_unparenthesized(condition)
  end
end
complex_condition?(condition) click to toggle source

If the condition is parenthesized we recurse and check for any complex expressions within it.

# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 101
def complex_condition?(condition)
  if condition.type == :begin
    condition.to_a.any? { |x| complex_condition?(x) }
  else
    non_complex_type?(condition) ? false : true
  end
end
correct_parenthesized(condition) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 171
def correct_parenthesized(condition)
  lambda do |corrector|
    corrector.remove(condition.loc.begin)
    corrector.remove(condition.loc.end)

    # Ruby allows no space between the question mark and parentheses.
    # If we remove the parentheses, we need to add a space or we'll
    # generate invalid code.
    unless whitespace_after?(condition)
      corrector.insert_after(condition.loc.end, ' ')
    end
  end
end
correct_unparenthesized(condition) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 185
def correct_unparenthesized(condition)
  lambda do |corrector|
    corrector.insert_before(condition.source_range, '(')
    corrector.insert_after(condition.source_range, ')')
  end
end
infinite_loop?() click to toggle source

When this cop is configured to enforce parentheses and the `RedundantParentheses` cop is enabled, it will cause an infinite loop as they compete to add and remove the parentheses respectively.

# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 147
def infinite_loop?
  require_parentheses? &&
    redundant_parentheses_enabled?
end
message(node) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 118
def message(node)
  if require_parentheses_when_complex?
    omit = parenthesized?(node.condition) ? 'Only use' : 'Use'
    format(MSG_COMPLEX, omit)
  else
    verb = require_parentheses? ? 'Use' : 'Omit'
    format(MSG, verb)
  end
end
non_complex_type?(condition) click to toggle source

Anything that is not a variable, constant, or method/.method call will be counted as a complex expression.

# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 111
def non_complex_type?(condition)
  condition.variable? || condition.const_type? ||
    (condition.send_type? && !operator?(condition.method_name)) ||
    condition.defined_type? || condition.yield_type? ||
    square_brackets?(condition)
end
offense?(node) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 69
def offense?(node)
  condition = node.condition

  if safe_assignment?(condition)
    !safe_assignment_allowed?
  else
    parens = parenthesized?(condition)
    case style
    when :require_parentheses_when_complex
      complex_condition?(condition) ? !parens : parens
    else
      require_parentheses? ? !parens : parens
    end
  end
end
parenthesized?(node) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 140
def parenthesized?(node)
  node.begin_type?
end
redundant_parentheses_enabled?() click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 136
def redundant_parentheses_enabled?
  @config.for_cop('Style/RedundantParentheses').fetch('Enabled')
end
require_parentheses?() click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 128
def require_parentheses?
  style == :require_parentheses
end
require_parentheses_when_complex?() click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 132
def require_parentheses_when_complex?
  style == :require_parentheses_when_complex
end
unparenthesized_method_call?(child) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 158
def unparenthesized_method_call?(child)
  argument = method_call_argument(child)
  argument && argument !~ /^\(/
end
unsafe_autocorrect?(condition) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 152
def unsafe_autocorrect?(condition)
  condition.children.any? do |child|
    unparenthesized_method_call?(child)
  end
end
whitespace_after?(node) click to toggle source
# File lib/rubbycop/cop/style/ternary_parentheses.rb, line 192
def whitespace_after?(node)
  index = index_of_last_token(node)
  last_token, next_token = processed_source.tokens[index, 2]
  space_between?(last_token, next_token)
end