diff --git a/changelog/change_support_filter_filter_in_style_collection_compact.md b/changelog/change_support_filter_filter_in_style_collection_compact.md new file mode 100644 index 000000000000..0630e79d6bbd --- /dev/null +++ b/changelog/change_support_filter_filter_in_style_collection_compact.md @@ -0,0 +1 @@ +* [#13245](https://github.com/rubocop/rubocop/pull/13245): Support `filter/filter!` in `Style/CollectionCompact`. ([@masato-bkn][]) diff --git a/lib/rubocop/cop/style/collection_compact.rb b/lib/rubocop/cop/style/collection_compact.rb index 55ca193a4fa8..981222d2300a 100644 --- a/lib/rubocop/cop/style/collection_compact.rb +++ b/lib/rubocop/cop/style/collection_compact.rb @@ -21,6 +21,7 @@ module Style # array.reject(&:nil?) # array.reject { |e| e.nil? } # array.select { |e| !e.nil? } + # array.filter { |e| !e.nil? } # array.grep_v(nil) # array.grep_v(NilClass) # @@ -31,6 +32,7 @@ module Style # hash.reject!(&:nil?) # hash.reject! { |k, v| v.nil? } # hash.select! { |k, v| !v.nil? } + # hash.filter! { |k, v| !v.nil? } # # # good # hash.compact! @@ -46,8 +48,9 @@ class CollectionCompact < Base extend TargetRubyVersion MSG = 'Use `%s` instead of `%s`.' - RESTRICT_ON_SEND = %i[reject reject! select select! grep_v].freeze + RESTRICT_ON_SEND = %i[reject reject! select select! filter filter! grep_v].freeze TO_ENUM_METHODS = %i[to_enum lazy].freeze + FILTER_METHODS = %i[filter filter!].freeze minimum_target_ruby_version 2.4 @@ -72,7 +75,7 @@ class CollectionCompact < Base def_node_matcher :select_method?, <<~PATTERN (block (call - !nil? {:select :select!}) + !nil? {:select :select! :filter :filter!}) $(args ...) (call (call @@ -85,6 +88,7 @@ class CollectionCompact < Base PATTERN def on_send(node) + return if target_ruby_version < 2.6 && FILTER_METHODS.include?(node.method_name) return unless (range = offense_range(node)) return if allowed_receiver?(node.receiver) return if target_ruby_version <= 3.0 && to_enum_method?(node) diff --git a/spec/rubocop/cop/style/collection_compact_spec.rb b/spec/rubocop/cop/style/collection_compact_spec.rb index 6ed76e28006a..cd4e34a11c3a 100644 --- a/spec/rubocop/cop/style/collection_compact_spec.rb +++ b/spec/rubocop/cop/style/collection_compact_spec.rb @@ -249,6 +249,52 @@ def foo(params) end end + context 'Ruby >= 2.6', :ruby26, unsupported_on: :prism do + it 'registers an offense and corrects when using `filter/filter!` to reject nils' do + expect_offense(<<~RUBY) + array.filter { |e| !e.nil? } + ^^^^^^^^^^^^^^^^^^^^^^ Use `compact` instead of `filter { |e| !e.nil? }`. + hash.filter! { |k, v| !v.nil? } + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact!` instead of `filter! { |k, v| !v.nil? }`. + RUBY + + expect_correction(<<~RUBY) + array.compact + hash.compact! + RUBY + end + + it 'registers an offense and corrects when using safe navigation `filter/filter!` call to reject nils' do + expect_offense(<<~RUBY) + array&.filter { |e| e&.nil?&.! } + ^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact` instead of `filter { |e| e&.nil?&.! }`. + hash&.filter! { |k, v| v&.nil?&.! } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact!` instead of `filter! { |k, v| v&.nil?&.! }`. + RUBY + + expect_correction(<<~RUBY) + array&.compact + hash&.compact! + RUBY + end + + it 'does not register an offense when using `filter/filter!` to reject nils without a receiver' do + expect_no_offenses(<<~RUBY) + filter { |e| !e.nil? } + filter! { |k, v| !v.nil? } + RUBY + end + end + + context 'Ruby <= 2.5', :ruby25, unsupported_on: :prism do + it 'does not register an offense when using `filter/filter!`' do + expect_no_offenses(<<~RUBY) + array.filter { |e| !e.nil? } + hash.filter! { |k, v| !v.nil? } + RUBY + end + end + context 'when Ruby <= 2.3', :ruby23, unsupported_on: :prism do it 'does not register an offense when using `reject` on hash to reject nils' do expect_no_offenses(<<~RUBY)