class RuboCop::Cop::Style::YodaCondition

Enforces or forbids Yoda conditions, i.e. comparison operations where the order of expression is reversed. eg. ‘5 == x`

@safety

This cop is unsafe because comparison operators can be defined
differently on different classes, and are not guaranteed to
have the same result if reversed.

For example:

[source,ruby]
----
class MyKlass
  def ==(other)
    true
  end
end

obj = MyKlass.new
obj == 'string'   #=> true
'string' == obj   #=> false
----

@example EnforcedStyle: forbid_for_all_comparison_operators (default)

# bad
99 == foo
"bar" != foo
42 >= foo
10 < bar
99 == CONST

# good
foo == 99
foo == "bar"
foo <= 42
bar > 10
CONST == 99
"#{interpolation}" == foo
/#{interpolation}/ == foo

@example EnforcedStyle: forbid_for_equality_operators_only

# bad
99 == foo
"bar" != foo

# good
99 >= foo
3 < a && a < 5

@example EnforcedStyle: require_for_all_comparison_operators

# bad
foo == 99
foo == "bar"
foo <= 42
bar > 10

# good
99 == foo
"bar" != foo
42 >= foo
10 < bar

@example EnforcedStyle: require_for_equality_operators_only

# bad
99 >= foo
3 < a && a < 5

# good
99 == foo
"bar" != foo

Constants

EQUALITY_OPERATORS
MSG
NONCOMMUTATIVE_OPERATORS
PROGRAM_NAMES
RESTRICT_ON_SEND
REVERSE_COMPARISON

Public Instance Methods

on_send(node) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 94
def on_send(node)
  return unless yoda_compatible_condition?(node)
  return if (equality_only? && non_equality_operator?(node)) ||
            file_constant_equal_program_name?(node) ||
            valid_yoda?(node)

  add_offense(node) do |corrector|
    corrector.replace(actual_code_range(node), corrected_code(node))
  end
end

Private Instance Methods

actual_code_range(node) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 149
def actual_code_range(node)
  range_between(node.source_range.begin_pos, node.source_range.end_pos)
end
constant_portion?(node) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 145
def constant_portion?(node)
  node.literal? || node.const_type?
end
corrected_code(node) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 138
def corrected_code(node)
  lhs = node.receiver
  rhs = node.first_argument

  "#{rhs.source} #{reverse_comparison(node.method_name)} #{lhs.source}"
end
enforce_yoda?() click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 107
def enforce_yoda?
  style == :require_for_all_comparison_operators ||
    style == :require_for_equality_operators_only
end
equality_only?() click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 112
def equality_only?
  style == :forbid_for_equality_operators_only ||
    style == :require_for_equality_operators_only
end
interpolation?(node) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 173
def interpolation?(node)
  return true if node.dstr_type?

  node.regexp_type? && node.interpolation?
end
message(node) click to toggle source

rubocop:enable Metrics/CyclomaticComplexity

# File lib/rubocop/cop/style/yoda_condition.rb, line 134
def message(node)
  format(MSG, source: node.source)
end
non_equality_operator?(node) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 157
def non_equality_operator?(node)
  !EQUALITY_OPERATORS.include?(node.method_name)
end
noncommutative_operator?(node) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 161
def noncommutative_operator?(node)
  NONCOMMUTATIVE_OPERATORS.include?(node.method_name)
end
program_name?(name) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 169
def program_name?(name)
  PROGRAM_NAMES.include?(name)
end
reverse_comparison(operator) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 153
def reverse_comparison(operator)
  REVERSE_COMPARISON.fetch(operator.to_s, operator)
end
source_file_path_constant?(node) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 165
def source_file_path_constant?(node)
  node.source == '__FILE__'
end
valid_yoda?(node) click to toggle source

rubocop:disable Metrics/CyclomaticComplexity

# File lib/rubocop/cop/style/yoda_condition.rb, line 122
def valid_yoda?(node)
  return true unless (rhs = node.first_argument)

  lhs = node.receiver
  return true if (constant_portion?(lhs) && constant_portion?(rhs)) ||
                 (!constant_portion?(lhs) && !constant_portion?(rhs)) ||
                 interpolation?(lhs)

  enforce_yoda? ? constant_portion?(lhs) : constant_portion?(rhs)
end
yoda_compatible_condition?(node) click to toggle source
# File lib/rubocop/cop/style/yoda_condition.rb, line 117
def yoda_compatible_condition?(node)
  node.comparison_method? && !noncommutative_operator?(node)
end