Skip to content

Commit fd13dab

Browse files
dvandersluisbbatsov
authored andcommitted
[Fix #13299] Fix Style/BlockDelimiters to always accept braces when an operator method argument is chained
Update `Style/BlockDelimiters` to not register an offense when braces are necessary to avoid changing precedence. Previously when an operator method was encountered, it was automatically evaluated (ie. not marked as ignored), but this can result in block delimiters being changed that affects block binding. Now operator methods are evaluated for nodes to ignore, other than if it only has a single argument which is of block type. As well, I added the missing `expect_corrections` tests for offenses without it.
1 parent 522950a commit fd13dab

3 files changed

Lines changed: 137 additions & 31 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#13299](https://github.com/rubocop/rubocop/issues/13299): Fix `Style/BlockDelimiters` to always accept braces when an operator method argument is chained. ([@dvandersluis][])

lib/rubocop/cop/style/block_delimiters.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ def self.autocorrect_incompatible_with
183183
def on_send(node)
184184
return unless node.arguments?
185185
return if node.parenthesized?
186-
return if node.operator_method? || node.assignment_method?
186+
return if node.assignment_method?
187+
return if single_argument_operator_method?(node)
187188

188189
node.arguments.each do |arg|
189190
get_blocks(arg) do |block|
@@ -501,6 +502,12 @@ def begin_required?(block_node)
501502
# `begin`...`end` when changing `do-end` to `{}`.
502503
block_node.each_child_node(:rescue, :ensure).any? && !block_node.single_line?
503504
end
505+
506+
def single_argument_operator_method?(node)
507+
return false unless node.operator_method?
508+
509+
node.arguments.one? && node.first_argument.block_type?
510+
end
504511
end
505512
end
506513
end

spec/rubocop/cop/style/block_delimiters_spec.rb

Lines changed: 128 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,25 @@
3535
RUBY
3636
end
3737

38+
it 'accepts a multi-line block with chained method as an argument to an operator method' do
39+
expect_no_offenses(<<~RUBY)
40+
'Some text: %s' %
41+
%w[foo bar].map { |v|
42+
v.upcase
43+
}.join(', ')
44+
RUBY
45+
end
46+
47+
it 'accepts a multi-line block with chained method as an argument to an operator method' \
48+
'inside a kwarg' do
49+
expect_no_offenses(<<~RUBY)
50+
foo :bar, baz: 'Some text: %s' %
51+
%w[foo bar].map { |v|
52+
v.upcase
53+
}.join(', ')
54+
RUBY
55+
end
56+
3857
context 'Ruby >= 2.7', :ruby27 do
3958
it 'accepts a multi-line numblock' do
4059
expect_no_offenses(<<~RUBY)
@@ -59,6 +78,25 @@
5978
} + [0], 1
6079
RUBY
6180
end
81+
82+
it 'accepts a multi-line numblock with chained method as an argument to an operator method' do
83+
expect_no_offenses(<<~RUBY)
84+
foo %
85+
%w[bar baz].map {
86+
_1.upcase
87+
}.join(', ')
88+
RUBY
89+
end
90+
91+
it 'accepts a multi-line numblock with chained method as an argument to an operator method' \
92+
'inside a kwarg' do
93+
expect_no_offenses(<<~RUBY)
94+
foo :bar, baz: 'Some text: %s' %
95+
%w[foo bar].map {
96+
_1.upcase
97+
}.join(', ')
98+
RUBY
99+
end
62100
end
63101
end
64102
end
@@ -69,6 +107,10 @@
69107
each do |x| end
70108
^^ Prefer `{...}` over `do...end` for single-line blocks.
71109
RUBY
110+
111+
expect_correction(<<~RUBY)
112+
each { |x| }
113+
RUBY
72114
end
73115

74116
it 'accepts a single line block with braces' do
@@ -88,6 +130,10 @@
88130
each do _1 end
89131
^^ Prefer `{...}` over `do...end` for single-line blocks.
90132
RUBY
133+
134+
expect_correction(<<~RUBY)
135+
each { _1 }
136+
RUBY
91137
end
92138

93139
it 'accepts a single line numblock with braces' do
@@ -166,6 +212,12 @@
166212
x
167213
}
168214
RUBY
215+
216+
expect_correction(<<~RUBY)
217+
each do |x|
218+
x
219+
end
220+
RUBY
169221
end
170222

171223
it 'registers an offense for a multi-line block with do-end if the return value is assigned' do
@@ -175,6 +227,12 @@
175227
x
176228
end
177229
RUBY
230+
231+
expect_correction(<<~RUBY)
232+
foo = map { |x|
233+
x
234+
}
235+
RUBY
178236
end
179237

180238
it 'registers an offense for a multi-line block with do-end if the ' \
@@ -185,6 +243,12 @@
185243
x
186244
end)
187245
RUBY
246+
247+
expect_correction(<<~RUBY)
248+
puts (map { |x|
249+
x
250+
})
251+
RUBY
188252
end
189253

190254
it 'registers an offense for a multi-line block with do-end if the ' \
@@ -195,6 +259,12 @@
195259
x
196260
end
197261
RUBY
262+
263+
expect_correction(<<~RUBY)
264+
foo.bar = map { |x|
265+
x
266+
}
267+
RUBY
198268
end
199269

200270
it 'accepts a multi-line block with do-end if it is the return value of its scope' do
@@ -338,21 +408,6 @@
338408
RUBY
339409
end
340410

341-
it 'autocorrects do-end to {} if it is a functional block' do
342-
expect_offense(<<~RUBY)
343-
foo = map do |x|
344-
^^ Prefer `{...}` over `do...end` for functional blocks.
345-
x
346-
end
347-
RUBY
348-
349-
expect_correction(<<~RUBY)
350-
foo = map { |x|
351-
x
352-
}
353-
RUBY
354-
end
355-
356411
it 'autocorrects do-end to {} with appropriate spacing' do
357412
expect_offense(<<~RUBY)
358413
foo = map do|x|
@@ -368,21 +423,6 @@
368423
RUBY
369424
end
370425

371-
it 'autocorrects do-end to {} if it is a functional block and does not change the meaning' do
372-
expect_offense(<<~RUBY)
373-
puts (map do |x|
374-
^^ Prefer `{...}` over `do...end` for functional blocks.
375-
x
376-
end)
377-
RUBY
378-
379-
expect_correction(<<~RUBY)
380-
puts (map { |x|
381-
x
382-
})
383-
RUBY
384-
end
385-
386426
it 'autocorrects do-end with `rescue` to {} if it is a functional block' do
387427
expect_offense(<<~RUBY)
388428
x = map do |a|
@@ -473,6 +513,11 @@
473513
^ Avoid using `{...}` for multi-line blocks.
474514
}
475515
RUBY
516+
517+
expect_correction(<<~RUBY)
518+
each do |x|
519+
end
520+
RUBY
476521
end
477522

478523
it 'registers an offense when combined with attribute assignment' do
@@ -481,6 +526,11 @@
481526
^ Avoid using `{...}` for multi-line blocks.
482527
}
483528
RUBY
529+
530+
expect_correction(<<~RUBY)
531+
foo.bar = baz.map do |x|
532+
end
533+
RUBY
484534
end
485535

486536
it 'registers an offense when there is a comment after the closing brace and block body is not empty' do
@@ -603,6 +653,16 @@
603653
# ...
604654
})
605655
RUBY
656+
657+
expect_correction(<<~RUBY)
658+
scope :foo, (lambda do |f|
659+
where(condition: "value")
660+
end)
661+
662+
expect { something }.to(raise_error(ErrorClass) do |error|
663+
# ...
664+
end)
665+
RUBY
606666
end
607667

608668
it 'can handle special method names such as []= and done?' do
@@ -616,6 +676,16 @@
616676
e.nil?
617677
}
618678
RUBY
679+
680+
expect_correction(<<~RUBY)
681+
h2[k2] = Hash.new do |h3,k3|
682+
h3[k3] = 0
683+
end
684+
685+
x = done? list.reject { |e|
686+
e.nil?
687+
}
688+
RUBY
619689
end
620690

621691
it 'autocorrects { and } to do and end' do
@@ -802,6 +872,14 @@
802872
}
803873
]
804874
RUBY
875+
876+
expect_correction(<<~RUBY)
877+
Hash[
878+
{foo: :bar}.map do |k, v|
879+
[k, v]
880+
end
881+
]
882+
RUBY
805883
end
806884

807885
context 'when there are braces around a multi-line block' do
@@ -811,6 +889,11 @@
811889
^ Prefer `do...end` for multi-line blocks without chaining.
812890
}
813891
RUBY
892+
893+
expect_correction(<<~RUBY)
894+
each do |x|
895+
end
896+
RUBY
814897
end
815898

816899
it 'registers an offense when combined with attribute assignment' do
@@ -819,6 +902,11 @@
819902
^ Prefer `do...end` for multi-line blocks without chaining.
820903
}
821904
RUBY
905+
906+
expect_correction(<<~RUBY)
907+
foo.bar = baz.map do |x|
908+
end
909+
RUBY
822910
end
823911

824912
it 'allows when the block is being chained' do
@@ -926,6 +1014,11 @@
9261014
^^ Prefer `{...}` over `do...end` for blocks.
9271015
end
9281016
RUBY
1017+
1018+
expect_correction(<<~RUBY)
1019+
each { |x|
1020+
}
1021+
RUBY
9291022
end
9301023

9311024
it 'does not autocorrect do-end if {} would change the meaning' do
@@ -965,6 +1058,11 @@
9651058
^^ Prefer `{...}` over `do...end` for blocks.
9661059
end
9671060
RUBY
1061+
1062+
expect_correction(<<~RUBY)
1063+
foo.bar = baz.map { |x|
1064+
}
1065+
RUBY
9681066
end
9691067

9701068
it 'accepts a multi-line functional block with do-end if it is an ignored method' do

0 commit comments

Comments
 (0)