Skip to content

Commit

Permalink
[Fix rubocop#704] Add new Rails/StripHeredoc cop
Browse files Browse the repository at this point in the history
Enforces the use of squiggly heredoc over `strip_heredoc`.

```ruby
# bad
<<EOS.strip_heredoc
  some text
EOS

<<-EOS.strip_heredoc
  some text
EOS

# good
<<~EOS
  some text
EOS
```
  • Loading branch information
koic committed May 27, 2022
1 parent 3a93706 commit 92dfb4e
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog/new_add_new_rails_strip_heredoc_cop.md
@@ -0,0 +1 @@
* [#704](https://github.com/rubocop/rubocop-rails/issues/704): Add new `Rails/StripHeredoc` cop. ([@koic][])
5 changes: 5 additions & 0 deletions config/default.yml
Expand Up @@ -871,6 +871,11 @@ Rails/SquishedSQLHeredocs:
# to be preserved in order to work, thus autocorrection is not safe.
SafeAutoCorrect: false

Rails/StripHeredoc:
Description: 'Enforces the use of squiggly heredoc over `strip_heredoc`.'
Enabled: pending
VersionAdded: '<<next>>'

Rails/TableNameAssignment:
Description: >-
Do not use `self.table_name =`. Use Inflections or `table_name_prefix` instead.
Expand Down
55 changes: 55 additions & 0 deletions lib/rubocop/cop/rails/strip_heredoc.rb
@@ -0,0 +1,55 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Rails
# Enforces the use of squiggly heredoc over `strip_heredoc`.
#
# @example
#
# # bad
# <<EOS.strip_heredoc
# some text
# EOS
#
# <<-EOS.strip_heredoc
# some text
# EOS
#
# # good
# <<~EOS
# some text
# EOS
#
class StripHeredoc < Base
extend AutoCorrector
extend TargetRubyVersion

MSG = 'Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.'

minimum_target_ruby_version 2.3

def on_send(node)
return unless node.method?(:strip_heredoc)
return unless (receiver = node.receiver)
return unless receiver.str_type? || receiver.dstr_type?
return unless receiver.respond_to?(:heredoc?) && receiver.heredoc?

register_offense(node, receiver)
end

private

def register_offense(node, heredoc_identifier)
add_offense(node) do |corrector|
replacement = heredoc_identifier.source.gsub(/\A<<-?/, '<<~')

corrector.replace(heredoc_identifier, replacement)
corrector.remove(node.loc.dot)
corrector.remove(node.loc.selector)
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rails_cops.rb
Expand Up @@ -104,6 +104,7 @@
require_relative 'rails/short_i18n'
require_relative 'rails/skips_model_validations'
require_relative 'rails/squished_sql_heredocs'
require_relative 'rails/strip_heredoc'
require_relative 'rails/table_name_assignment'
require_relative 'rails/time_zone'
require_relative 'rails/time_zone_assignment'
Expand Down
99 changes: 99 additions & 0 deletions spec/rubocop/cop/rails/strip_heredoc_spec.rb
@@ -0,0 +1,99 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Rails::StripHeredoc, :config do
context 'Ruby <= 2.2', :ruby22 do
it 'does not register an offense when using `strip_heredoc`' do
expect_no_offenses(<<~RUBY)
<<-EOS.strip_heredoc
some text
EOS
RUBY
end
end

context 'Ruby >= 2.3', :ruby23 do
it 'registers an offense when using `strip_heredoc` with `<<`' do
expect_offense(<<~RUBY)
<<EOS.strip_heredoc
^^^^^^^^^^^^^^^^^^^ Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.
some text
EOS
RUBY

expect_correction(<<~RUBY)
<<~EOS
some text
EOS
RUBY
end

it 'registers an offense when using `strip_heredoc` with `<<-`' do
expect_offense(<<~RUBY)
<<-EOS.strip_heredoc
^^^^^^^^^^^^^^^^^^^^ Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.
some text
EOS
RUBY

expect_correction(<<~RUBY)
<<~EOS
some text
EOS
RUBY
end

it 'registers an offense when using `strip_heredoc.do_something`' do
expect_offense(<<~RUBY)
<<-EOS.strip_heredoc.do_something
^^^^^^^^^^^^^^^^^^^^ Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.
some text
EOS
RUBY

expect_correction(<<~RUBY)
<<~EOS.do_something
some text
EOS
RUBY
end

it 'registers an offense when using `strip_heredoc` with multiline text' do
expect_offense(<<~RUBY)
<<-EOS.strip_heredoc
^^^^^^^^^^^^^^^^^^^^ Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.
some text
some text
EOS
RUBY

expect_correction(<<~RUBY)
<<~EOS
some text
some text
EOS
RUBY
end

it 'does not register an offense when using squiggly heredoc' do
expect_no_offenses(<<~RUBY)
<<~EOS
some text
EOS
RUBY
end

it 'does not register an offense when using `do_something.strip_heredoc`' do
expect_no_offenses(<<~RUBY)
<<-EOS.do_something.strip_heredoc
some text
EOS
RUBY
end

it 'does not register an offense when using `strip_heredoc` without receiver' do
expect_no_offenses(<<~RUBY)
strip_heredoc
RUBY
end
end
end

0 comments on commit 92dfb4e

Please sign in to comment.