class RuboCop::Cop::Rails::CompactBlank


collection.compact_blank!
# good
collection.keep_if { |_k, v| v.present? } # Same behavior as ‘Array#compact_blank!` and `Hash#compact_blank!`
collection.keep_if(&:present?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
collection.delete_if { |_k, v| v.blank? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
collection.delete_if(&:blank?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
# bad
collection.compact_blank
# good
collection.filter { |_k, v| v.present? }
collection.filter(&:present?)
collection.select { |_k, v| v.present? }
collection.select(&:present?)
collection.reject { |_k, v| v.blank? }
collection.reject(&:blank?)
# bad
@example
If the cop makes a mistake, autocorrected code may get unexpected behavior.
`Array#compact_blank!`, `Hash#compact_blank!` are equivalent to `delete_if(&:blank?)`.
`ActionController::Parameters`.
And `compact_blank!` has different implementations for `Array`, `Hash`, and
This will work fine when the receiver is a hash object.
`[[1, 2], [3, nil]].compact_blank` are not compatible. The same is true for `blank?`.
For example, `[[1, 2], [3, nil]].reject { |first, second| second.blank? }` and
blank check of block arguments to the receiver object.
It is unsafe by default because false positives may occur in the
@safety
Checks if collection can be blank-compacted with `compact_blank`.

def bad_method?(node)

def bad_method?(node)
  return true if reject_with_block_pass?(node)
  return true if select_with_block_pass?(node)
  arguments, receiver_in_block = reject_with_block?(node.parent) || select_with_block?(node.parent)
  if arguments
    return use_single_value_block_argument?(arguments, receiver_in_block) ||
           use_hash_value_block_argument?(arguments, receiver_in_block)
  end
  false
end

def offense_range(node)

def offense_range(node)
  end_pos = if node.parent&.block_type? && node.parent&.send_node == node
              node.parent.source_range.end_pos
            else
              node.source_range.end_pos
            end
  range_between(node.loc.selector.begin_pos, end_pos)
end

def on_send(node)

def on_send(node)
  return if target_ruby_version < 2.6 && node.method?(:filter)
  return unless bad_method?(node)
  range = offense_range(node)
  preferred_method = preferred_method(node)
  add_offense(range, message: format(MSG, preferred_method: preferred_method)) do |corrector|
    corrector.replace(range, preferred_method)
  end
end

def preferred_method(node)

def preferred_method(node)
  DESTRUCTIVE_METHODS.include?(node.method_name) ? 'compact_blank!' : 'compact_blank'
end

def use_hash_value_block_argument?(arguments, receiver_in_block)

def use_hash_value_block_argument?(arguments, receiver_in_block)
  arguments.length == 2 && arguments[1].source == receiver_in_block.source
end

def use_single_value_block_argument?(arguments, receiver_in_block)

def use_single_value_block_argument?(arguments, receiver_in_block)
  arguments.length == 1 && arguments[0].source == receiver_in_block.source
end