class RuboCop::Cop::Style::ZeroLengthPredicate

Checks for numeric comparisons that can be replaced by a predicate method, such as ‘receiver.length == 0`, `receiver.length > 0`, and `receiver.length != 0`, `receiver.length < 1` and `receiver.size == 0` that can be replaced by `receiver.empty?` and `!receiver.empty?`.

NOTE: ‘File`, `Tempfile`, and `StringIO` do not have `empty?` so allow `size == 0` and `size.zero?`.

@safety

This cop is unsafe because it cannot be guaranteed that the receiver
has an `empty?` method that is defined in terms of `length`. If there
is a non-standard class that redefines `length` or `empty?`, the cop
may register a false positive.

@example

# bad
[1, 2, 3].length == 0
0 == "foobar".length
array.length < 1
{a: 1, b: 2}.length != 0
string.length > 0
hash.size > 0

# good
[1, 2, 3].empty?
"foobar".empty?
array.empty?
!{a: 1, b: 2}.empty?
!string.empty?
!hash.empty?

Constants

NONZERO_MSG
RESTRICT_ON_SEND
ZERO_MSG

Public Instance Methods

on_csend(node) click to toggle source
# File lib/rubocop/cop/style/zero_length_predicate.rb, line 51
def on_csend(node)
  check_zero_length_predicate(node)
  check_zero_length_comparison(node)
end
on_send(node) click to toggle source
# File lib/rubocop/cop/style/zero_length_predicate.rb, line 45
def on_send(node)
  check_zero_length_predicate(node)
  check_zero_length_comparison(node)
  check_nonzero_length_comparison(node)
end

Private Instance Methods

check_nonzero_length_comparison(node) click to toggle source
# File lib/rubocop/cop/style/zero_length_predicate.rb, line 85
def check_nonzero_length_comparison(node)
  nonzero_length_comparison = nonzero_length_comparison(node.parent)
  return unless nonzero_length_comparison

  lhs, opr, rhs = nonzero_length_comparison

  return if non_polymorphic_collection?(node.parent)

  add_offense(
    node.parent, message: format(NONZERO_MSG, current: "#{lhs} #{opr} #{rhs}")
  ) do |corrector|
    corrector.replace(node.parent, replacement(node.parent))
  end
end
check_zero_length_comparison(node) click to toggle source
# File lib/rubocop/cop/style/zero_length_predicate.rb, line 70
def check_zero_length_comparison(node)
  zero_length_comparison = zero_length_comparison(node.parent)
  return unless zero_length_comparison

  lhs, opr, rhs = zero_length_comparison

  return if non_polymorphic_collection?(node.parent)

  add_offense(
    node.parent, message: format(ZERO_MSG, current: "#{lhs} #{opr} #{rhs}")
  ) do |corrector|
    corrector.replace(node.parent, replacement(node.parent))
  end
end
check_zero_length_predicate(node) click to toggle source
# File lib/rubocop/cop/style/zero_length_predicate.rb, line 58
def check_zero_length_predicate(node)
  return unless zero_length_predicate?(node.parent)
  return if non_polymorphic_collection?(node.parent)

  offense = node.loc.selector.join(node.parent.source_range.end)
  message = format(ZERO_MSG, current: offense.source)

  add_offense(offense, message: message) do |corrector|
    corrector.replace(offense, 'empty?')
  end
end
replacement(node) click to toggle source
# File lib/rubocop/cop/style/zero_length_predicate.rb, line 119
def replacement(node)
  length_node = zero_length_node(node)
  if length_node&.receiver
    return "#{length_node.receiver.source}#{length_node.loc.dot.source}empty?"
  end

  other_length_node = other_length_node(node)
  "!#{other_length_node.receiver.source}#{other_length_node.loc.dot.source}empty?"
end