Skip to content

Commit

Permalink
Add new Style/EmptyHeredoc cop
Browse files Browse the repository at this point in the history
## Summary

Checks for using empty heredoc to reduce redundancy.

```ruby
# bad
<<~EOS
EOS

<<-EOS
EOS

<<EOS
EOS

# good
''

# bad
do_something(<<~EOS)
EOS

do_something(<<-EOS)
EOS

do_something(<<EOS)
EOS

# good
do_something('')
```

## Other Information

I noticed the following redundancy in the RuboCop test code:

```ruby
expect_correction(<<~RUBY)
RUBY
```

This cop solves it generically.
  • Loading branch information
koic authored and bbatsov committed Jul 18, 2022
1 parent 992019e commit 2c4215f
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 8 deletions.
1 change: 1 addition & 0 deletions changelog/new_add_new_style_empty_heredoc_cop.md
@@ -0,0 +1 @@
* [#10820](https://github.com/rubocop/rubocop/pull/10820): Add new `Style/EmptyHeredoc` cop. ([@koic][])
5 changes: 5 additions & 0 deletions config/default.yml
Expand Up @@ -3514,6 +3514,11 @@ Style/EmptyElse:
- both
AllowComments: false

Style/EmptyHeredoc:
Description: 'Checks for using empty heredoc to reduce redundancy.'
Enabled: pending
VersionAdded: '<<next>>'

Style/EmptyLambdaParameter:
Description: 'Omit parens for empty lambda parameters.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -481,6 +481,7 @@
require_relative 'rubocop/cop/style/empty_block_parameter'
require_relative 'rubocop/cop/style/empty_case_condition'
require_relative 'rubocop/cop/style/empty_else'
require_relative 'rubocop/cop/style/empty_heredoc'
require_relative 'rubocop/cop/style/empty_lambda_parameter'
require_relative 'rubocop/cop/style/empty_literal'
require_relative 'rubocop/cop/style/empty_method'
Expand Down
59 changes: 59 additions & 0 deletions lib/rubocop/cop/style/empty_heredoc.rb
@@ -0,0 +1,59 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Style
# Checks for using empty heredoc to reduce redundancy.
#
# @example
#
# # bad
# <<~EOS
# EOS
#
# <<-EOS
# EOS
#
# <<EOS
# EOS
#
# # good
# ''
#
# # bad
# do_something(<<~EOS)
# EOS
#
# do_something(<<-EOS)
# EOS
#
# do_something(<<EOS)
# EOS
#
# # good
# do_something('')
#
class EmptyHeredoc < Base
include Heredoc
include RangeHelp
extend AutoCorrector

MSG = 'Use an empty string literal instead of heredoc.'

def on_heredoc(node)
heredoc_body = node.loc.heredoc_body

return unless heredoc_body.source.empty?

add_offense(node) do |corrector|
heredoc_end = node.loc.heredoc_end

corrector.replace(node, "''")
corrector.remove(range_by_whole_lines(heredoc_body, include_final_newline: true))
corrector.remove(range_by_whole_lines(heredoc_end, include_final_newline: true))
end
end
end
end
end
end
12 changes: 4 additions & 8 deletions spec/rubocop/cop/layout/empty_comment_spec.rb
Expand Up @@ -9,8 +9,7 @@
^ Source code comment is empty.
RUBY

expect_correction(<<~RUBY)
RUBY
expect_correction('')
end

it 'registers an offense and corrects using multiline empty comments' do
Expand All @@ -21,8 +20,7 @@
^ Source code comment is empty.
RUBY

expect_correction(<<~RUBY)
RUBY
expect_correction('')
end

it 'registers an offense and corrects using an empty comment next to code' do
Expand Down Expand Up @@ -83,8 +81,7 @@ def hello
^ Source code comment is empty.
RUBY

expect_correction(<<~RUBY)
RUBY
expect_correction('')
end

it 'registers an offense and corrects using border comment' do
Expand All @@ -93,8 +90,7 @@ def hello
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Source code comment is empty.
RUBY

expect_correction(<<~RUBY)
RUBY
expect_correction('')
end
end

Expand Down
71 changes: 71 additions & 0 deletions spec/rubocop/cop/style/empty_heredoc_spec.rb
@@ -0,0 +1,71 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Style::EmptyHeredoc, :config do
it 'registers an offense when using empty `<<~EOS` heredoc' do
expect_offense(<<~RUBY)
<<~EOS
^^^^^^ Use an empty string literal instead of heredoc.
EOS
RUBY

expect_correction(<<~RUBY)
''
RUBY
end

it 'registers an offense when using empty `<<-EOS` heredoc' do
expect_offense(<<~RUBY)
<<-EOS
^^^^^^ Use an empty string literal instead of heredoc.
EOS
RUBY

expect_correction(<<~RUBY)
''
RUBY
end

it 'registers an offense when using empty `<<EOS` heredoc' do
expect_offense(<<~RUBY)
<<EOS
^^^^^ Use an empty string literal instead of heredoc.
EOS
RUBY

expect_correction(<<~RUBY)
''
RUBY
end

it 'registers an offense when using empty heredoc single argument' do
expect_offense(<<~RUBY)
do_something(<<~EOS)
^^^^^^ Use an empty string literal instead of heredoc.
EOS
RUBY

expect_correction(<<~RUBY)
do_something('')
RUBY
end

it 'registers an offense when using empty heredoc argument with other argument' do
expect_offense(<<~RUBY)
do_something(<<~EOS, arg)
^^^^^^ Use an empty string literal instead of heredoc.
EOS
RUBY

expect_correction(<<~RUBY)
do_something('', arg)
RUBY
end

it 'does not register an offense when using not empty heredoc' do
expect_no_offenses(<<~RUBY)
<<~EOS
Hello.
EOS
RUBY
end
end

0 comments on commit 2c4215f

Please sign in to comment.