Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add always_braces to Style/BlockDelimiters #6973

Merged
merged 1 commit into from Apr 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@

### New features

* [#6973](https://github.com/rubocop-hq/rubocop/pull/6973): Add `always_braces` to `Style/BlockDelimiter`. ([@iGEL][])
* [#6841](https://github.com/rubocop-hq/rubocop/issues/6841): Node patterns can now match children in any order using `<>`. ([@marcandre][])
* [#6928](https://github.com/rubocop-hq/rubocop/pull/6928): Add `--init` option for generate `.rubocop.yml` file in the current directory. ([@koic][])
* Add new `Layout/HeredocArgumentClosingParenthesis` cop. ([@maxh][])
Expand Down
2 changes: 2 additions & 0 deletions config/default.yml
Expand Up @@ -2663,6 +2663,8 @@ Style/BlockDelimiters:
# return value is being chained with another method (in which case braces
# are enforced).
- braces_for_chaining
# The `always_braces` style always enforces braces.
- always_braces
ProceduralMethods:
# Methods that are known to be procedural in nature but look functional from
# their usage, e.g.
Expand Down
20 changes: 20 additions & 0 deletions lib/rubocop/cop/style/block_delimiters.rb
Expand Up @@ -95,10 +95,24 @@ module Style
# word.flip.flop
# }.join("-")
#
# @example EnforcedStyle: always_braces
# # bad
# words.each do |word|
# word.flip.flop
# end
#
# # good
# words.each { |word|
# word.flip.flop
# }
#
class BlockDelimiters < Cop
include ConfigurableEnforcedStyle
include IgnoredMethods

ALWAYS_BRACES_MESSAGE = 'Prefer `{...}` over `do...end` for blocks.'
.freeze

def on_send(node)
return unless node.arguments?
return if node.parenthesized? || node.operator_method?
Expand Down Expand Up @@ -166,6 +180,7 @@ def message(node)
when :line_count_based then line_count_based_message(node)
when :semantic then semantic_message(node)
when :braces_for_chaining then braces_for_chaining_message(node)
when :always_braces then ALWAYS_BRACES_MESSAGE
end
end

Expand Down Expand Up @@ -229,6 +244,7 @@ def proper_block_style?(node)
when :line_count_based then line_count_based_block_style?(node)
when :semantic then semantic_block_style?(node)
when :braces_for_chaining then braces_for_chaining_style?(node)
when :always_braces then braces_style?(node)
end
end

Expand Down Expand Up @@ -257,6 +273,10 @@ def braces_for_chaining_style?(node)
end
end

def braces_style?(node)
node.loc.begin.source == '{'
end

def return_value_chaining?(node)
node.parent && node.parent.send_type? && node.parent.dot?
end
Expand Down
15 changes: 14 additions & 1 deletion manual/cops_style.md
Expand Up @@ -460,12 +460,25 @@ words.each { |word|
word.flip.flop
}.join("-")
```
#### EnforcedStyle: always_braces

```ruby
# bad
words.each do |word|
word.flip.flop
end

# good
words.each { |word|
word.flip.flop
}
```

### Configurable attributes

Name | Default value | Configurable values
--- | --- | ---
EnforcedStyle | `line_count_based` | `line_count_based`, `semantic`, `braces_for_chaining`
EnforcedStyle | `line_count_based` | `line_count_based`, `semantic`, `braces_for_chaining`, `always_braces`
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
Expand Down
93 changes: 93 additions & 0 deletions spec/rubocop/cop/style/block_delimiters_spec.rb
Expand Up @@ -507,4 +507,97 @@
end
end
end

context 'always braces' do
cop_config = {
'EnforcedStyle' => 'always_braces',
'IgnoredMethods' => %w[proc]
}

let(:cop_config) { cop_config }

it 'registers an offense for a single line block with do-end' do
expect_offense(<<-RUBY.strip_indent)
each do |x| end
^^ Prefer `{...}` over `do...end` for blocks.
RUBY
end

it 'accepts a single line block with braces' do
expect_no_offenses('each { |x| }')
end

it 'registers an offence for a multi-line block with do-end' do
expect_offense(<<-RUBY.strip_indent)
each do |x|
^^ Prefer `{...}` over `do...end` for blocks.
end
RUBY
end

it 'auto-corrects do and end for single line blocks to { and }' do
new_source = autocorrect_source('block do |x| end')
expect(new_source).to eq('block { |x| }')
end

it 'does not auto-correct do-end if {} would change the meaning' do
src = "s.subspec 'Subspec' do |sp| end"
new_source = autocorrect_source(src)
expect(new_source).to eq(src)
end

it 'accepts a multi-line block that needs braces to be valid ruby' do
expect_no_offenses(<<-RUBY.strip_indent)
puts [1, 2, 3].map { |n|
n * n
}, 1
RUBY
end

it 'registers an offense for multi-line chained do-end blocks' do
expect_offense(<<-RUBY.strip_indent)
each do |x|
^^ Prefer `{...}` over `do...end` for blocks.
end.map(&:to_s)
RUBY
end

it 'auto-corrects do-end for chained blocks' do
src = <<-RUBY.strip_indent
each do |x|
end.map(&:to_s)
RUBY
new_source = autocorrect_source(src)
expect(new_source).to eq(<<-RUBY.strip_indent)
each { |x|
}.map(&:to_s)
RUBY
end

it 'accepts a multi-line functional block with do-end if it is ' \
'an ignored method' do
expect_no_offenses(<<-RUBY.strip_indent)
foo = proc do
puts 42
end
RUBY
end

context 'when there are braces around a multi-line block' do
it 'registers an offense in the simple case' do
expect_offense(<<-RUBY.strip_indent)
each do |x|
^^ Prefer `{...}` over `do...end` for blocks.
end
RUBY
end

it 'allows when the block is being chained' do
expect_no_offenses(<<-RUBY.strip_indent)
each { |x|
}.map(&:to_sym)
RUBY
end
end
end
end