Skip to content

Commit 356fc46

Browse files
koicbbatsov
authored andcommitted
[Fix #11908] Support AllowedReceivers for Style/CollectionMethods
Fixes #11908. This PR supports `AllowedReceivers` for `Style/CollectionMethods`. For example, by setting `AllowedReceivers: ['params']` in RuboCop Rails or user configuration, the following false positive for `params` can be prevented: ```ruby def selection_params(current, last_category = nil, params = {}) params.merge( category_id: current.is_a?(Category) ? current.to_param : last_category.to_param, site_id: current.is_a?(Site) ? current.to_param : nil, ).delete_if { |_k, v| v.nil? } end ``` The configuration to `params` is not set in the RuboCop core due to Rails specific issues. So if this approach is accepted, I will add it to RuboCop Rails's default configuration.
1 parent 713e7da commit 356fc46

7 files changed

Lines changed: 67 additions & 22 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#11908](https://github.com/rubocop/rubocop/issues/11908): Support `AllowedReceivers` for `Style/CollectionMethods`. ([@koic][])

config/default.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3362,6 +3362,7 @@ Style/CollectionCompact:
33623362
Safe: false
33633363
VersionAdded: '1.2'
33643364
VersionChanged: '1.3'
3365+
AllowedReceivers: []
33653366

33663367
# Align with the style guide.
33673368
Style/CollectionMethods:

lib/rubocop.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
require_relative 'rubocop/cop/mixin/allowed_identifiers'
7070
require_relative 'rubocop/cop/mixin/allowed_methods'
7171
require_relative 'rubocop/cop/mixin/allowed_pattern'
72+
require_relative 'rubocop/cop/mixin/allowed_receivers'
7273
require_relative 'rubocop/cop/mixin/auto_corrector' # rubocop:todo Naming/InclusiveLanguage
7374
require_relative 'rubocop/cop/mixin/check_assignment'
7475
require_relative 'rubocop/cop/mixin/check_line_breakable'
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
# This module encapsulates the ability to allow certain receivers in a cop.
6+
module AllowedReceivers
7+
def allowed_receiver?(receiver)
8+
receiver_name = receiver_name(receiver)
9+
10+
allowed_receivers.include?(receiver_name)
11+
end
12+
13+
def receiver_name(receiver)
14+
if receiver.receiver && !receiver.receiver.const_type?
15+
return receiver_name(receiver.receiver)
16+
end
17+
18+
if receiver.send_type?
19+
if receiver.receiver
20+
"#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
21+
else
22+
receiver.method_name.to_s
23+
end
24+
else
25+
receiver.source
26+
end
27+
end
28+
29+
def allowed_receivers
30+
cop_config.fetch('AllowedReceivers', [])
31+
end
32+
end
33+
end
34+
end

lib/rubocop/cop/style/collection_compact.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ module Style
3535
# # good
3636
# hash.compact!
3737
#
38+
# @example AllowedReceivers: ['params']
39+
# # good
40+
# params.reject(&:nil?)
41+
#
3842
class CollectionCompact < Base
43+
include AllowedReceivers
3944
include RangeHelp
4045
extend AutoCorrector
4146
extend TargetRubyVersion
@@ -76,6 +81,7 @@ class CollectionCompact < Base
7681

7782
def on_send(node)
7883
return unless (range = offense_range(node))
84+
return if allowed_receiver?(node.receiver)
7985
if (target_ruby_version <= 3.0 || node.method?(:delete_if)) && to_enum_method?(node)
8086
return
8187
end

lib/rubocop/cop/style/hash_each_methods.rb

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ module Style
2828
# execute(sql).keys.each { |v| p v }
2929
# execute(sql).values.each { |v| p v }
3030
class HashEachMethods < Base
31+
include AllowedReceivers
3132
include Lint::UnusedArgument
3233
extend AutoCorrector
3334

@@ -116,28 +117,6 @@ def correct_args(node, corrector)
116117
def kv_range(outer_node)
117118
outer_node.receiver.loc.selector.join(outer_node.loc.selector)
118119
end
119-
120-
def allowed_receiver?(receiver)
121-
receiver_name = receiver_name(receiver)
122-
123-
allowed_receivers.include?(receiver_name)
124-
end
125-
126-
def receiver_name(receiver)
127-
if receiver.send_type?
128-
if receiver.receiver
129-
"#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
130-
else
131-
receiver.method_name.to_s
132-
end
133-
else
134-
receiver.source
135-
end
136-
end
137-
138-
def allowed_receivers
139-
cop_config.fetch('AllowedReceivers', [])
140-
end
141120
end
142121
end
143122
end

spec/rubocop/cop/style/collection_compact_spec.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,27 @@ def foo(params)
197197
RUBY
198198
end
199199
end
200+
201+
context "when `AllowedReceivers: ['params']`" do
202+
let(:cop_config) { { 'AllowedReceivers' => ['params'] } }
203+
204+
it 'does not register an offense when receiver is `params` method' do
205+
expect_no_offenses(<<~RUBY)
206+
params.reject { |param| param.nil? }
207+
RUBY
208+
end
209+
210+
it 'does not register an offense when method chained receiver is `params` method' do
211+
expect_no_offenses(<<~RUBY)
212+
params.merge(key: value).delete_if { |_k, v| v.nil? }
213+
RUBY
214+
end
215+
216+
it 'registers an offense when receiver is not allowed name' do
217+
expect_offense(<<~RUBY)
218+
foo.reject { |param| param.nil? }
219+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact` instead of `reject { |param| param.nil? }`.
220+
RUBY
221+
end
222+
end
200223
end

0 commit comments

Comments
 (0)