Skip to content

Commit

Permalink
[Fix rubocop#704] Add new Rails/StripHeredoc cop
Browse files Browse the repository at this point in the history
Closes rubocop#704.

Enforces the use of squiggly heredoc over `strip_heredoc`.

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

# bad
<<-EOS.strip_heredoc
  some text
EOS

# good
<<~EOS
  some text
EOS
```
  • Loading branch information
koic committed May 30, 2022
1 parent 3a93706 commit 25c2e6b
Show file tree
Hide file tree
Showing 5 changed files with 163 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][])
6 changes: 6 additions & 0 deletions config/default.yml
Expand Up @@ -871,6 +871,12 @@ 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`.'
StyleGuide: 'https://rails.rubystyle.guide/#prefer-squiggly-heredoc'
Enabled: pending
VersionAdded: '<<next>>'

Rails/TableNameAssignment:
Description: >-
Do not use `self.table_name =`. Use Inflections or `table_name_prefix` instead.
Expand Down
56 changes: 56 additions & 0 deletions lib/rubocop/cop/rails/strip_heredoc.rb
@@ -0,0 +1,56 @@
# 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
#
# # bad
# <<-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`.'
RESTRICT_ON_SEND = %i[strip_heredoc].freeze

minimum_target_ruby_version 2.3

def on_send(node)
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)
add_offense(node) do |corrector|
squiggly_heredoc = heredoc.source.sub(/\A<<-?/, '<<~')

corrector.replace(heredoc, squiggly_heredoc)
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 25c2e6b

Please sign in to comment.