Skip to content

Commit ec8e18e

Browse files
authored
Merge pull request #1428 from Earlopain/uniq-pluck-multiple-lines
[Fix #1427] Fix an error for `Rails/UniqBeforePluck` with multi-line expression
2 parents eca3732 + 1980681 commit ec8e18e

File tree

3 files changed

+31
-33
lines changed

3 files changed

+31
-33
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#1427](https://github.com/rubocop/rubocop-rails/issues/1427): Fix an error for `Rails/UniqBeforePluck` when `pluck` and `unique` are on different lines. ([@earlopain][])

lib/rubocop/cop/rails/uniq_before_pluck.rb

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -51,51 +51,28 @@ class UniqBeforePluck < Base
5151

5252
MSG = 'Use `distinct` before `pluck`.'
5353
RESTRICT_ON_SEND = %i[uniq].freeze
54-
NEWLINE = "\n"
55-
PATTERN = '[!^block (send (send %<type>s :pluck ...) :uniq ...)]'
5654

57-
def_node_matcher :conservative_node_match, format(PATTERN, type: 'const')
58-
59-
def_node_matcher :aggressive_node_match, format(PATTERN, type: '_')
55+
def_node_matcher :uniq_before_pluck, '[!^block $(send $(send _ :pluck ...) :uniq ...)]'
6056

6157
def on_send(node)
62-
uniq = if style == :conservative
63-
conservative_node_match(node)
64-
else
65-
aggressive_node_match(node)
66-
end
67-
68-
return unless uniq
58+
uniq_before_pluck(node) do |uniq_node, pluck_node|
59+
next if style == :conservative && !pluck_node.receiver&.const_type?
6960

70-
add_offense(node.loc.selector) do |corrector|
71-
autocorrect(corrector, node)
61+
add_offense(uniq_node.loc.selector) do |corrector|
62+
autocorrect(corrector, uniq_node, pluck_node)
63+
end
7264
end
7365
end
7466

7567
private
7668

77-
def autocorrect(corrector, node)
78-
method = node.method_name
69+
def autocorrect(corrector, uniq_node, pluck_node)
70+
corrector.remove(range_between(pluck_node.loc.end.end_pos, uniq_node.loc.selector.end_pos))
7971

80-
corrector.remove(dot_method_with_whitespace(method, node))
81-
if (dot = node.receiver.loc.dot)
72+
if (dot = pluck_node.loc.dot)
8273
corrector.insert_before(dot.begin, '.distinct')
8374
else
84-
corrector.insert_before(node.receiver, 'distinct.')
85-
end
86-
end
87-
88-
def dot_method_with_whitespace(method, node)
89-
range_between(dot_method_begin_pos(method, node), node.loc.selector.end_pos)
90-
end
91-
92-
def dot_method_begin_pos(method, node)
93-
lines = node.source.split(NEWLINE)
94-
95-
if lines.last.strip == ".#{method}"
96-
node.source.rindex(NEWLINE)
97-
else
98-
node.loc.dot.begin_pos
75+
corrector.insert_before(pluck_node, 'distinct.')
9976
end
10077
end
10178
end

spec/rubocop/cop/rails/uniq_before_pluck_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@
3737
RUBY
3838
end
3939

40+
it 'corrects when uniq and pluck are on different lines' do
41+
expect_offense(<<~RUBY)
42+
Model
43+
.pluck(:name)
44+
.uniq
45+
^^^^ Use `distinct` before `pluck`.
46+
RUBY
47+
48+
expect_correction(<<~RUBY)
49+
Model
50+
.distinct.pluck(:name)
51+
RUBY
52+
end
53+
4054
it 'ignores uniq before pluck' do
4155
expect_no_offenses(<<~RUBY)
4256
Model.where(foo: 1).uniq.pluck(:something)
@@ -85,6 +99,12 @@
8599
instance.assoc.pluck(:name).uniq
86100
RUBY
87101
end
102+
103+
it 'ignores uniq without an receiver' do
104+
expect_no_offenses(<<~RUBY)
105+
pluck(:name).uniq
106+
RUBY
107+
end
88108
end
89109

90110
context 'when the enforced mode is aggressive' do

0 commit comments

Comments
 (0)