Skip to content

Commit

Permalink
[Fix rubocop#6393] Add AllowBracesOnProceduralOneLiners
Browse files Browse the repository at this point in the history
option to fine-tune behavior of Style/BlockDelimiters
  • Loading branch information
davearonson committed Oct 30, 2018
1 parent 1ab8170 commit 8c946fd
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 12 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,10 @@

## master (unreleased)

### New features

* [#6393](https://github.com/rubocop-hq/rubocop/issues/6393): Add AllowBracesOnProceduralOneLiners option to fine-tune Style/BlockDelimiter's semantic mode. ([@davearonson][])

### Bug fixes

* [#5934](https://github.com/rubocop-hq/rubocop/issues/5934): Handle the combination of `--auto-gen-config` and `--config FILE` correctly. ([@jonas054][])
Expand Down Expand Up @@ -3636,3 +3640,4 @@
[@andrew-aladev]: https://github.com/andrew-aladev
[@y-yagi]: https://github.com/y-yagi
[@DiscoStarslayer]: https://github.com/DiscoStarslayer
[@davearonson]: https://github.com/davearonson
27 changes: 25 additions & 2 deletions config/default.yml
Expand Up @@ -2719,8 +2719,9 @@ Style/BlockDelimiters:
- line_count_based
# The `semantic` style enforces braces around functional blocks, where the
# primary purpose of the block is to return a value and do..end for
# procedural blocks, where the primary purpose of the block is its
# side-effects.
# multi-line procedural blocks, where the primary purpose of the block is
# its side-effects. Single-line procedural blocks may only use do-end,
# unless AllowBracesOnProceduralOneLiners has a truthy value (see below).
#
# This looks at the usage of a block's method to determine its type (e.g. is
# the result of a `map` assigned to a variable or passed to another
Expand Down Expand Up @@ -2781,6 +2782,28 @@ Style/BlockDelimiters:
- lambda
- proc
- it
# The AllowBracesOnProceduralOneLiners option is ignored unless the
# EnforcedStyle is set to `semantic`. If so:
#
# If AllowBracesOnProceduralOneLiners is unspecified, or set to any
# falsey value, then semantic purity is maintained, so one-line
# procedural blocks must use do-end, not braces.
#
# # bad
# collection.each { |element| puts element }
#
# # good
# collection.each do |element| puts element end
#
# If AllowBracesOnProceduralOneLiners is set to any truthy value,
# then one-line procedural blocks may use either style.
#
# # good
# collection.each { |element| puts element }
#
# # also good
# collection.each do |element| puts element end
AllowBracesOnProceduralOneLiners: false

Style/BracesAroundHashParameters:
Description: 'Enforce braces style around hash parameters.'
Expand Down
31 changes: 30 additions & 1 deletion lib/rubocop/cop/style/block_delimiters.rb
Expand Up @@ -60,6 +60,30 @@ module Style
# x
# }.inspect
#
# # The AllowBracesOnProceduralOneLiners option is ignored unless the
# # EnforcedStyle is set to `semantic`. If so:
#
# # If the AllowBracesOnProceduralOneLiners option is unspecified, or
# # set to `false` or any other falsey value, then semantic purity is
# # maintained, so one-line procedural blocks must use do-end, not
# # braces.
#
# # bad
# collection.each { |element| puts element }
#
# # good
# collection.each do |element| puts element end
#
# # If the AllowBracesOnProceduralOneLiners option is set to `true`, or
# # any other truthy value, then one-line procedural blocks may use
# # either style. (There is no setting for requiring braces on them.)
#
# # good
# collection.each { |element| puts element }
#
# # also good
# collection.each do |element| puts element end
#
# @example EnforcedStyle: braces_for_chaining
# # bad
# words.each do |word|
Expand Down Expand Up @@ -216,7 +240,8 @@ def semantic_block_style?(node)
method_name = node.method_name

if node.braces?
functional_method?(method_name) || functional_block?(node)
functional_method?(method_name) || functional_block?(node) ||
(procedural_oneliners_may_have_braces? && !node.multiline?)
else
procedural_method?(method_name) || !return_value_used?(node)
end
Expand Down Expand Up @@ -250,6 +275,10 @@ def functional_block?(node)
return_value_used?(node) || return_value_of_scope?(node)
end

def procedural_oneliners_may_have_braces?
cop_config['AllowBracesOnProceduralOneLiners']
end

def procedural_method?(method_name)
cop_config['ProceduralMethods'].map(&:to_sym).include?(method_name)
end
Expand Down
25 changes: 25 additions & 0 deletions manual/cops_style.md
Expand Up @@ -415,6 +415,30 @@ foo = map { |x|
map { |x|
x
}.inspect

# The AllowBracesOnProceduralOneLiners option is ignored unless the
# EnforcedStyle is set to `semantic`. If so:

# If the AllowBracesOnProceduralOneLiners option is unspecified, or
# set to `false` or any other falsey value, then semantic purity is
# maintained, so one-line procedural blocks must use do-end, not
# braces.

# bad
collection.each { |element| puts element }

# good
collection.each do |element| puts element end

# If the AllowBracesOnProceduralOneLiners option is set to `true`, or
# any other truthy value, then one-line procedural blocks may use
# either style. (There is no setting for requiring braces on them.)

# good
collection.each { |element| puts element }

# also good
collection.each do |element| puts element end
```
#### EnforcedStyle: braces_for_chaining

Expand All @@ -438,6 +462,7 @@ EnforcedStyle | `line_count_based` | `line_count_based`, `semantic`, `braces_for
ProceduralMethods | `benchmark`, `bm`, `bmbm`, `create`, `each_with_object`, `measure`, `new`, `realtime`, `tap`, `with_object` | Array
FunctionalMethods | `let`, `let!`, `subject`, `watch` | Array
IgnoredMethods | `lambda`, `proc`, `it` | Array
AllowBracesOnProceduralOneLiners | `false` | Boolean

### References

Expand Down
36 changes: 27 additions & 9 deletions spec/rubocop/cop/style/block_delimiters_spec.rb
Expand Up @@ -169,18 +169,36 @@
RUBY
end

it 'registers an offense for a single line procedural block' do
expect_offense(<<-RUBY.strip_indent)
each { |x| puts x }
^ Prefer `do...end` over `{...}` for procedural blocks.
RUBY
end
context 'with a procedural one-line block' do
context 'with AllowBracesOnProceduralOneLiners false or unset' do
it 'registers an offense for a single line procedural block' do
expect_offense(<<-RUBY.strip_indent)
each { |x| puts x }
^ Prefer `do...end` over `{...}` for procedural blocks.
RUBY
end

it 'accepts a single line block with do-end if it is procedural' do
expect_no_offenses('each do |x| puts x; end')
end
end

context 'with AllowBracesOnProceduralOneLiners true' do
let(:cop_config) do
cop_config.merge('AllowBracesOnProceduralOneLiners' => true)
end

it 'accepts a single line block with do-end if it is procedural' do
expect_no_offenses('each do |x| puts x; end')
it 'accepts a single line procedural block with braces' do
expect_no_offenses('each { |x| puts x }')
end

it 'accepts a single line procedural do-end block' do
expect_no_offenses('each do |x| puts x; end')
end
end
end

context 'with a procedural block' do
context 'with a procedural multi-line block' do
let(:corrected_source) do
<<-RUBY.strip_indent
each do |x|
Expand Down

0 comments on commit 8c946fd

Please sign in to comment.