class RuboCop::Cop::Performance::MapCompact
ary.compact.map(&:foo)
ary.map(&:foo).compact!
ary.filter_map(&:foo)
# good
ary.collect(&:foo).compact
ary.map(&:foo).compact
# bad
@example
—-
[true, false, nil].filter_map(&:itself) #=> [true]
[true, false, nil].compact #=> [true, false]
—-
[source,ruby]
that is not compatible with ‘filter_map`.
It is marked as unsafe auto-correction by default because `map { … }.compact`
This cop identifies places where `map { … }.compact` can be replaced by `filter_map`.
In Ruby 2.7, `Enumerable#filter_map` has been added.
def invoke_method_after_map_compact_on_same_line?(compact_node, chained_method)
def invoke_method_after_map_compact_on_same_line?(compact_node, chained_method) compact_node.loc.selector.line == chained_method.loc.selector.line end
def on_send(node)
def on_send(node) return unless (map_node = map_compact(node)) compact_loc = node.loc range = range_between(map_node.loc.selector.begin_pos, compact_loc.selector.end_pos) add_offense(range) do |corrector| corrector.replace(map_node.loc.selector, 'filter_map') remove_compact_method(corrector, node) end end
def remove_compact_method(corrector, compact_node)
def remove_compact_method(corrector, compact_node) chained_method = compact_node.parent compact_method_range = compact_node.loc.selector if compact_node.multiline? && chained_method&.loc.respond_to?(:selector) && !invoke_method_after_map_compact_on_same_line?(compact_node, chained_method) compact_method_range = range_by_whole_lines(compact_method_range, include_final_newline: true) else corrector.remove(compact_node.loc.dot) end corrector.remove(compact_method_range) end