class RuboCop::Cop::Style::UnlessLogicalOperators

Checks for the use of logical operators in an `unless` condition. It discourages such code, as the condition becomes more difficult to read and understand.

This cop supports two styles:

`forbid_mixed_logical_operators` style forbids the use of more than one type of logical operators. This makes the `unless` condition easier to read because either all conditions need to be met or any condition need to be met in order for the expression to be truthy or falsey.

`forbid_logical_operators` style forbids any use of logical operator. This makes it even more easy to read the `unless` condition as there is only one condition in the expression.

@example EnforcedStyle: forbid_mixed_logical_operators (default)

# bad
return unless a || b && c
return unless a && b || c
return unless a && b and c
return unless a || b or c
return unless a && b or c
return unless a || b and c

# good
return unless a && b && c
return unless a || b || c
return unless a and b and c
return unless a or b or c
return unless a?

@example EnforcedStyle: forbid_logical_operators

# bad
return unless a || b
return unless a && b
return unless a or b
return unless a and b

# good
return unless a
return unless a?

Constants

FORBID_LOGICAL_OPERATORS
FORBID_MIXED_LOGICAL_OPERATORS

Public Instance Methods

on_if(node) click to toggle source
# File lib/rubocop/cop/style/unless_logical_operators.rb, line 70
def on_if(node)
  return unless node.unless?

  if style == :forbid_mixed_logical_operators && mixed_logical_operator?(node)
    add_offense(node, message: FORBID_MIXED_LOGICAL_OPERATORS)
  elsif style == :forbid_logical_operators && logical_operator?(node)
    add_offense(node, message: FORBID_LOGICAL_OPERATORS)
  end
end

Private Instance Methods

mixed_logical_operator?(node) click to toggle source
# File lib/rubocop/cop/style/unless_logical_operators.rb, line 82
def mixed_logical_operator?(node)
  or_with_and?(node) ||
    and_with_or?(node) ||
    mixed_precedence_and?(node) ||
    mixed_precedence_or?(node)
end
mixed_precedence_and?(node) click to toggle source
# File lib/rubocop/cop/style/unless_logical_operators.rb, line 89
def mixed_precedence_and?(node)
  and_sources = node.condition.each_descendant(:and).map(&:operator)
  and_sources << node.condition.operator if node.condition.and_type?

  !(and_sources.all?('&&') || and_sources.all?('and'))
end
mixed_precedence_or?(node) click to toggle source
# File lib/rubocop/cop/style/unless_logical_operators.rb, line 96
def mixed_precedence_or?(node)
  or_sources = node.condition.each_descendant(:or).map(&:operator)
  or_sources << node.condition.operator if node.condition.or_type?

  !(or_sources.all?('||') || or_sources.all?('or'))
end