Skip to content

Commit 2420d70

Browse files
authored
Merge pull request #1471 from koic/support_itblock_in_rails_cops
Support `it` block parameter in `Rails` cops
2 parents 3fbbca6 + 72155fd commit 2420d70

22 files changed

+352
-7
lines changed

.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ jobs:
8383
-e "/gem 'rubocop-performance',/d" \
8484
-e "/gem 'rubocop-rspec',/d" -i Gemfile
8585
cat << EOF > Gemfile.local
86-
gem 'rubocop', '1.72.1' # Specify the oldest supported RuboCop version
86+
gem 'rubocop', '1.75.0' # Specify the oldest supported RuboCop version
8787
EOF
8888
- uses: ruby/setup-ruby@v1
8989
with:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#1471](https://github.com/rubocop/rubocop-rails/pull/1471): Support `it` block parameter in `Rails` cops. ([@koic][])

lib/rubocop/cop/mixin/index_method.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def set_new_method_name(new_method_name, corrector)
5858
end
5959

6060
def set_new_arg_name(transformed_argname, corrector)
61-
return if block_node.numblock_type?
61+
return unless block_node.block_type?
6262

6363
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
6464
end
@@ -84,6 +84,7 @@ def on_block(node)
8484
end
8585

8686
alias on_numblock on_block
87+
alias on_itblock on_block
8788

8889
def on_send(node)
8990
on_bad_map_to_h(node) do |*match|

lib/rubocop/cop/rails/index_by.rb

+9
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class IndexBy < Base
3737
(numblock
3838
(call _ :to_h) $1
3939
(array $_ (lvar :_1)))
40+
(itblock
41+
(call _ :to_h) $:it
42+
(array $_ (lvar :it)))
4043
}
4144
PATTERN
4245

@@ -50,6 +53,9 @@ class IndexBy < Base
5053
(numblock
5154
(call _ {:map :collect}) $1
5255
(array $_ (lvar :_1)))
56+
(itblock
57+
(call _ {:map :collect}) $:it
58+
(array $_ (lvar :it)))
5359
}
5460
:to_h)
5561
PATTERN
@@ -66,6 +72,9 @@ class IndexBy < Base
6672
(numblock
6773
(call _ {:map :collect}) $1
6874
(array $_ (lvar :_1)))
75+
(itblock
76+
(call _ {:map :collect}) $:it
77+
(array $_ (lvar :it)))
6978
}
7079
)
7180
PATTERN

lib/rubocop/cop/rails/index_with.rb

+9
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class IndexWith < Base
4040
(numblock
4141
(call _ :to_h) $1
4242
(array (lvar :_1) $_))
43+
(itblock
44+
(call _ :to_h) $:it
45+
(array (lvar :it) $_))
4346
}
4447
PATTERN
4548

@@ -53,6 +56,9 @@ class IndexWith < Base
5356
(numblock
5457
(call _ {:map :collect}) $1
5558
(array (lvar :_1) $_))
59+
(itblock
60+
(call _ {:map :collect}) $:it
61+
(array (lvar :it) $_))
5662
}
5763
:to_h)
5864
PATTERN
@@ -69,6 +75,9 @@ class IndexWith < Base
6975
(numblock
7076
(call _ {:map :collect}) $1
7177
(array (lvar :_1) $_))
78+
(itblock
79+
(call _ {:map :collect}) $:it
80+
(array (lvar :it) $_))
7281
}
7382
)
7483
PATTERN

lib/rubocop/cop/rails/pluck.rb

+9-3
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class Pluck < Base
5959
(any_block (call _ {:map :collect}) $_argument (send lvar :[] $_key))
6060
PATTERN
6161

62+
# rubocop:disable Metrics/AbcSize
6263
def on_block(node)
6364
return if node.each_ancestor(:any_block).any?
6465

@@ -68,20 +69,25 @@ def on_block(node)
6869
match = if node.block_type?
6970
block_argument = argument.children.first.source
7071
use_block_argument_in_key?(block_argument, key)
71-
else # numblock
72-
argument == 1 && use_block_argument_in_key?('_1', key)
72+
elsif node.numblock_type?
73+
use_block_argument_in_key?('_1', key)
74+
else # itblock
75+
use_block_argument_in_key?('it', key)
7376
end
7477
next unless match
7578

7679
register_offense(node, key)
7780
end
7881
end
82+
# rubocop:enable Metrics/AbcSize
7983
alias on_numblock on_block
84+
alias on_itblock on_block
8085

8186
private
8287

8388
def use_one_block_argument?(argument)
84-
return true if argument == 1 # Checks for numbered argument `_1`.
89+
# Checks for numbered argument `_1` or `it block parameter.
90+
return true if [1, :it].include?(argument)
8591

8692
argument.respond_to?(:one?) && argument.one?
8793
end

lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,22 @@ def on_block(node)
8585
end
8686

8787
alias on_numblock on_block
88+
alias on_itblock on_block
8889

8990
private
9091

9192
def autocorrect(corrector, send_node, node)
9293
corrector.remove(send_node.receiver)
9394
corrector.remove(send_node.loc.dot)
94-
corrector.remove(block_argument_range(send_node)) unless node.numblock_type?
95+
corrector.remove(block_argument_range(send_node)) if node.block_type?
9596
end
9697

98+
# rubocop:disable Metrics/AbcSize
9799
def redundant_receiver?(send_nodes, node)
98100
proc = if node.numblock_type?
99101
->(n) { n.receiver.lvar_type? && n.receiver.source == '_1' }
102+
elsif node.itblock_type?
103+
->(n) { n.receiver.lvar_type? && n.receiver.source == 'it' }
100104
else
101105
return false if node.arguments.empty?
102106

@@ -106,6 +110,7 @@ def redundant_receiver?(send_nodes, node)
106110

107111
send_nodes.all?(&proc)
108112
end
113+
# rubocop:enable Metrics/AbcSize
109114

110115
def block_argument_range(node)
111116
block_node = node.each_ancestor(:block).first

lib/rubocop/cop/rails/reversible_migration.rb

+1
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ def on_block(node)
205205
end
206206

207207
alias on_numblock on_block
208+
alias on_itblock on_block
208209

209210
private
210211

rubocop-rails.gemspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ Gem::Specification.new do |s|
3737
# Rack::Utils::SYMBOL_TO_STATUS_CODE, which is used by HttpStatus cop, was
3838
# introduced in rack 1.1
3939
s.add_dependency 'rack', '>= 1.1'
40-
s.add_dependency 'rubocop', '>= 1.72.1', '< 2.0'
40+
s.add_dependency 'rubocop', '>= 1.75.0', '< 2.0'
4141
s.add_dependency 'rubocop-ast', '>= 1.38.0', '< 2.0'
4242
end

spec/rubocop/cop/rails/create_table_with_timestamps_spec.rb

+11
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@
6464
RUBY
6565
end
6666

67+
it 'does not register an offense when including timestamps in itblock', :ruby34, unsupported_on: :parser do
68+
expect_no_offenses <<~RUBY
69+
create_table :users do
70+
it.string :name
71+
it.string :email
72+
73+
it.timestamps
74+
end
75+
RUBY
76+
end
77+
6778
it 'does not register an offense when including timestamps with `to_proc` syntax' do
6879
expect_no_offenses <<~RUBY
6980
create_table :users, &:timestamps

spec/rubocop/cop/rails/index_by_spec.rb

+64
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,68 @@
262262
end
263263
end
264264
end
265+
266+
context '`it` parameter', :ruby34, unsupported_on: :parser do
267+
it 'registers an offense for `map { ... }.to_h`' do
268+
expect_offense(<<~RUBY)
269+
x.map { [it.to_sym, it] }.to_h
270+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `index_by` over `map { ... }.to_h`.
271+
RUBY
272+
273+
expect_correction(<<~RUBY)
274+
x.index_by { it.to_sym }
275+
RUBY
276+
end
277+
278+
context 'when values are transformed' do
279+
it 'does not register an offense for `map { ... }.to_h`' do
280+
expect_no_offenses(<<~RUBY)
281+
x.map { [it.to_sym, foo(it)] }.to_h
282+
RUBY
283+
end
284+
end
285+
286+
it 'registers an offense for Hash[map { ... }]' do
287+
expect_offense(<<~RUBY)
288+
Hash[x.map { [it.to_sym, it] }]
289+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `index_by` over `Hash[map { ... }]`.
290+
RUBY
291+
292+
expect_correction(<<~RUBY)
293+
x.index_by { it.to_sym }
294+
RUBY
295+
end
296+
297+
context 'when the referenced `it` parameter is not it' do
298+
it 'does not register an offense for Hash[map { ... }]' do
299+
expect_no_offenses(<<~RUBY)
300+
Hash[x.map { [it.to_sym, y] }]
301+
RUBY
302+
end
303+
end
304+
305+
it 'registers an offense for `to_h { ... }`' do
306+
expect_offense(<<~RUBY)
307+
x.to_h { [it.to_sym, it] }
308+
^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `index_by` over `to_h { ... }`.
309+
RUBY
310+
311+
expect_correction(<<~RUBY)
312+
x.index_by { it.to_sym }
313+
RUBY
314+
end
315+
316+
context 'when `it` parameter other than `it` is referenced in the key' do
317+
it 'registers an offense for `to_h { ... }`' do
318+
expect_offense(<<~RUBY)
319+
x.to_h { [y.to_sym, it] }
320+
^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `index_by` over `to_h { ... }`.
321+
RUBY
322+
323+
expect_correction(<<~RUBY)
324+
x.index_by { y.to_sym }
325+
RUBY
326+
end
327+
end
328+
end
265329
end

spec/rubocop/cop/rails/index_with_spec.rb

+64
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,70 @@
261261
end
262262
end
263263
end
264+
265+
context '`it` block parameter', :ruby34, unsupported_on: :parser do
266+
it 'registers an offense for `map { ... }.to_h`' do
267+
expect_offense(<<~RUBY)
268+
x.map { [it, it.to_sym] }.to_h
269+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `index_with` over `map { ... }.to_h`.
270+
RUBY
271+
272+
expect_correction(<<~RUBY)
273+
x.index_with { it.to_sym }
274+
RUBY
275+
end
276+
277+
context 'when keys are transformed' do
278+
it 'does not register an offense for `map { ... }.to_h`' do
279+
expect_no_offenses(<<~RUBY)
280+
x.map { [foo(it), it.to_sym] }.to_h
281+
RUBY
282+
end
283+
end
284+
285+
it 'registers an offense for Hash[map { ... }]' do
286+
expect_offense(<<~RUBY)
287+
Hash[x.map { [it, it.to_sym] }]
288+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `index_with` over `Hash[map { ... }]`.
289+
RUBY
290+
291+
expect_correction(<<~RUBY)
292+
x.index_with { it.to_sym }
293+
RUBY
294+
end
295+
296+
context 'when the referenced `it` parameter is not `it`' do
297+
it 'does not register an offense for Hash[map { ... }]' do
298+
expect_no_offenses(<<~RUBY)
299+
Hash[x.map { [y, it.to_sym] }]
300+
RUBY
301+
end
302+
end
303+
304+
it 'registers an offense for `to_h { ... }`' do
305+
expect_offense(<<~RUBY)
306+
x.to_h { [it, it.to_sym] }
307+
^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `index_with` over `to_h { ... }`.
308+
RUBY
309+
310+
expect_correction(<<~RUBY)
311+
x.index_with { it.to_sym }
312+
RUBY
313+
end
314+
315+
context 'when an `it` parameter other than `it` is referenced in the value' do
316+
it 'registers an offense for `to_h { ... }`' do
317+
expect_offense(<<~RUBY)
318+
x.to_h { [it, y.to_sym] }
319+
^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `index_with` over `to_h { ... }`.
320+
RUBY
321+
322+
expect_correction(<<~RUBY)
323+
x.index_with { y.to_sym }
324+
RUBY
325+
end
326+
end
327+
end
264328
end
265329

266330
context 'when using Rails 5.2 or older', :rails52 do

spec/rubocop/cop/rails/output_spec.rb

+6
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@
161161
RUBY
162162
end
163163

164+
it 'does not register an offense when io method is called with `it` parameter', :ruby34, unsupported_on: :parser do
165+
expect_no_offenses(<<~RUBY)
166+
obj.write { do_something(it) }
167+
RUBY
168+
end
169+
164170
it 'does not register an offense when a method is ' \
165171
'safe navigation called to a local variable with the same name as a print method' do
166172
expect_no_offenses(<<~RUBY)

spec/rubocop/cop/rails/pluck_spec.rb

+25
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,31 @@
129129
end
130130
end
131131

132+
context 'when using Ruby 3.4 or newer', :ruby34, unsupported_on: :parser do
133+
context 'when using `it` block parameter' do
134+
context "when `#{method}` can be replaced with `pluck`" do
135+
it 'registers an offense' do
136+
expect_offense(<<~RUBY, method: method)
137+
x.%{method} { it[:foo] }
138+
^{method}^^^^^^^^^^^^^ Prefer `pluck(:foo)` over `%{method} { it[:foo] }`.
139+
RUBY
140+
141+
expect_correction(<<~RUBY)
142+
x.pluck(:foo)
143+
RUBY
144+
end
145+
end
146+
147+
context 'when the `it` argument is used in `[]`' do
148+
it 'does not register an offense' do
149+
expect_no_offenses(<<~RUBY)
150+
x.#{method} { it[foo...it.to_something] }
151+
RUBY
152+
end
153+
end
154+
end
155+
end
156+
132157
context "when `#{method}` is used in block" do
133158
it 'does not register an offense' do
134159
expect_no_offenses(<<~RUBY)

spec/rubocop/cop/rails/redundant_active_record_all_method_spec.rb

+6
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,12 @@
329329
RUBY
330330
end
331331

332+
it "does not register an offense when using `#{method}` with `it` block", :ruby34, unsupported_on: :parser do
333+
expect_no_offenses(<<~RUBY)
334+
User.all.#{method} { it.do_something }
335+
RUBY
336+
end
337+
332338
it "does not register an offense when using `#{method}` with symbol block" do
333339
expect_no_offenses(<<~RUBY)
334340
User.all.#{method}(&:do_something)

0 commit comments

Comments
 (0)