diff --git a/changelog/fix_an_error_for_performance_map_compact.md b/changelog/fix_an_error_for_performance_map_compact.md new file mode 100644 index 0000000000..e1ee0bd56c --- /dev/null +++ b/changelog/fix_an_error_for_performance_map_compact.md @@ -0,0 +1 @@ +* [#309](https://github.com/rubocop/rubocop-performance/issues/309): Fix an error for `Performance/MapCompact` when using `map(&:do_something).compact` and there is a line break after `map.compact` and assigning with `||=`. ([@koic][]) diff --git a/lib/rubocop/cop/performance/map_compact.rb b/lib/rubocop/cop/performance/map_compact.rb index b3a168d772..014bb47c1a 100644 --- a/lib/rubocop/cop/performance/map_compact.rb +++ b/lib/rubocop/cop/performance/map_compact.rb @@ -67,7 +67,7 @@ def on_send(node) def remove_compact_method(corrector, map_node, compact_node, chained_method) compact_method_range = compact_node.loc.selector - if compact_node.multiline? && chained_method&.loc.respond_to?(:selector) && chained_method.dot? && + if compact_node.multiline? && chained_method&.loc.respond_to?(:selector) && use_dot?(chained_method) && !map_method_and_compact_method_on_same_line?(map_node, compact_node) && !invoke_method_after_map_compact_on_same_line?(compact_node, chained_method) compact_method_range = compact_method_with_final_newline_range(compact_method_range) @@ -78,6 +78,10 @@ def remove_compact_method(corrector, map_node, compact_node, chained_method) corrector.remove(compact_method_range) end + def use_dot?(node) + node.respond_to?(:dot?) && node.dot? + end + def map_method_and_compact_method_on_same_line?(map_node, compact_node) compact_node.loc.selector.line == map_node.loc.selector.line end diff --git a/spec/rubocop/cop/performance/map_compact_spec.rb b/spec/rubocop/cop/performance/map_compact_spec.rb index 43275e8053..55f5cda5c0 100644 --- a/spec/rubocop/cop/performance/map_compact_spec.rb +++ b/spec/rubocop/cop/performance/map_compact_spec.rb @@ -119,6 +119,20 @@ RUBY end + it 'registers an offense when using `map(&:do_something).compact` and there is a line break after' \ + '`map.compact` and assigning with `||=`' do + expect_offense(<<~RUBY) + foo[1] ||= collection + .map(&:do_something).compact + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `filter_map` instead. + RUBY + + expect_correction(<<~RUBY) + foo[1] ||= collection + .filter_map(&:do_something) + RUBY + end + it 'registers an offense when using `map { ... }.compact.first` with single-line method calls' do expect_offense(<<~RUBY) collection.map { |item| item.do_something }.compact.first