class RuboCop::Cop::Style::CollectionCompact

Checks for places where custom logic on rejection nils from arrays and hashes can be replaced with ‘{Array,Hash}#{compact,compact!}`.

@safety

It is unsafe by default because false positives may occur in the
`nil` check of block arguments to the receiver object.

For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
when the receiver is a hash object.

@example

# bad
array.reject(&:nil?)
array.reject { |e| e.nil? }
array.select { |e| !e.nil? }

# good
array.compact

# bad
hash.reject!(&:nil?)
hash.reject! { |k, v| v.nil? }
hash.select! { |k, v| !v.nil? }

# good
hash.compact!

Constants

MSG
RESTRICT_ON_SEND
TO_ENUM_METHODS

Public Instance Methods

on_send(node) click to toggle source
# File lib/rubocop/cop/style/collection_compact.rb, line 70
def on_send(node)
  return unless (range = offense_range(node))
  return if target_ruby_version <= 3.0 && to_enum_method?(node)

  good = good_method_name(node)
  message = format(MSG, good: good, bad: range.source)

  add_offense(range, message: message) { |corrector| corrector.replace(range, good) }
end

Private Instance Methods

good_method_name(node) click to toggle source
# File lib/rubocop/cop/style/collection_compact.rb, line 102
def good_method_name(node)
  if node.bang_method?
    'compact!'
  else
    'compact'
  end
end
offense_range(node) click to toggle source
# File lib/rubocop/cop/style/collection_compact.rb, line 82
def offense_range(node)
  if reject_method_with_block_pass?(node)
    range(node, node)
  else
    block_node = node.parent

    return unless block_node&.block_type?
    unless (args, receiver = reject_method?(block_node) || select_method?(block_node))
      return
    end
    return unless args.last.source == receiver.source

    range(node, block_node)
  end
end
range(begin_pos_node, end_pos_node) click to toggle source
# File lib/rubocop/cop/style/collection_compact.rb, line 110
def range(begin_pos_node, end_pos_node)
  range_between(begin_pos_node.loc.selector.begin_pos, end_pos_node.loc.end.end_pos)
end
to_enum_method?(node) click to toggle source
# File lib/rubocop/cop/style/collection_compact.rb, line 98
def to_enum_method?(node)
  TO_ENUM_METHODS.include?(node.children.first.method_name)
end