Skip to content

Commit e0d2a47

Browse files
authored
Merge pull request #706 from koic/add_new_rails_strip_heredoc_cop
[Fix #704] Add new `Rails/StripHeredoc` cop
2 parents 7c3b098 + 25c2e6b commit e0d2a47

File tree

5 files changed

+163
-0
lines changed

5 files changed

+163
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#704](https://github.com/rubocop/rubocop-rails/issues/704): Add new `Rails/StripHeredoc` cop. ([@koic][])

config/default.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,12 @@ Rails/SquishedSQLHeredocs:
885885
# to be preserved in order to work, thus autocorrection is not safe.
886886
SafeAutoCorrect: false
887887

888+
Rails/StripHeredoc:
889+
Description: 'Enforces the use of squiggly heredoc over `strip_heredoc`.'
890+
StyleGuide: 'https://rails.rubystyle.guide/#prefer-squiggly-heredoc'
891+
Enabled: pending
892+
VersionAdded: '<<next>>'
893+
888894
Rails/TableNameAssignment:
889895
Description: >-
890896
Do not use `self.table_name =`. Use Inflections or `table_name_prefix` instead.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module Rails
6+
# Enforces the use of squiggly heredoc over `strip_heredoc`.
7+
#
8+
# @example
9+
#
10+
# # bad
11+
# <<EOS.strip_heredoc
12+
# some text
13+
# EOS
14+
#
15+
# # bad
16+
# <<-EOS.strip_heredoc
17+
# some text
18+
# EOS
19+
#
20+
# # good
21+
# <<~EOS
22+
# some text
23+
# EOS
24+
#
25+
class StripHeredoc < Base
26+
extend AutoCorrector
27+
extend TargetRubyVersion
28+
29+
MSG = 'Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.'
30+
RESTRICT_ON_SEND = %i[strip_heredoc].freeze
31+
32+
minimum_target_ruby_version 2.3
33+
34+
def on_send(node)
35+
return unless (receiver = node.receiver)
36+
return unless receiver.str_type? || receiver.dstr_type?
37+
return unless receiver.respond_to?(:heredoc?) && receiver.heredoc?
38+
39+
register_offense(node, receiver)
40+
end
41+
42+
private
43+
44+
def register_offense(node, heredoc)
45+
add_offense(node) do |corrector|
46+
squiggly_heredoc = heredoc.source.sub(/\A<<-?/, '<<~')
47+
48+
corrector.replace(heredoc, squiggly_heredoc)
49+
corrector.remove(node.loc.dot)
50+
corrector.remove(node.loc.selector)
51+
end
52+
end
53+
end
54+
end
55+
end
56+
end

lib/rubocop/cop/rails_cops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
require_relative 'rails/short_i18n'
107107
require_relative 'rails/skips_model_validations'
108108
require_relative 'rails/squished_sql_heredocs'
109+
require_relative 'rails/strip_heredoc'
109110
require_relative 'rails/table_name_assignment'
110111
require_relative 'rails/time_zone'
111112
require_relative 'rails/time_zone_assignment'
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::Rails::StripHeredoc, :config do
4+
context 'Ruby <= 2.2', :ruby22 do
5+
it 'does not register an offense when using `strip_heredoc`' do
6+
expect_no_offenses(<<~RUBY)
7+
<<-EOS.strip_heredoc
8+
some text
9+
EOS
10+
RUBY
11+
end
12+
end
13+
14+
context 'Ruby >= 2.3', :ruby23 do
15+
it 'registers an offense when using `strip_heredoc` with `<<`' do
16+
expect_offense(<<~RUBY)
17+
<<EOS.strip_heredoc
18+
^^^^^^^^^^^^^^^^^^^ Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.
19+
some text
20+
EOS
21+
RUBY
22+
23+
expect_correction(<<~RUBY)
24+
<<~EOS
25+
some text
26+
EOS
27+
RUBY
28+
end
29+
30+
it 'registers an offense when using `strip_heredoc` with `<<-`' do
31+
expect_offense(<<~RUBY)
32+
<<-EOS.strip_heredoc
33+
^^^^^^^^^^^^^^^^^^^^ Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.
34+
some text
35+
EOS
36+
RUBY
37+
38+
expect_correction(<<~RUBY)
39+
<<~EOS
40+
some text
41+
EOS
42+
RUBY
43+
end
44+
45+
it 'registers an offense when using `strip_heredoc.do_something`' do
46+
expect_offense(<<~RUBY)
47+
<<-EOS.strip_heredoc.do_something
48+
^^^^^^^^^^^^^^^^^^^^ Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.
49+
some text
50+
EOS
51+
RUBY
52+
53+
expect_correction(<<~RUBY)
54+
<<~EOS.do_something
55+
some text
56+
EOS
57+
RUBY
58+
end
59+
60+
it 'registers an offense when using `strip_heredoc` with multiline text' do
61+
expect_offense(<<~RUBY)
62+
<<-EOS.strip_heredoc
63+
^^^^^^^^^^^^^^^^^^^^ Use squiggly heredoc (`<<~`) instead of `strip_heredoc`.
64+
some text
65+
some text
66+
EOS
67+
RUBY
68+
69+
expect_correction(<<~RUBY)
70+
<<~EOS
71+
some text
72+
some text
73+
EOS
74+
RUBY
75+
end
76+
77+
it 'does not register an offense when using squiggly heredoc' do
78+
expect_no_offenses(<<~RUBY)
79+
<<~EOS
80+
some text
81+
EOS
82+
RUBY
83+
end
84+
85+
it 'does not register an offense when using `do_something.strip_heredoc`' do
86+
expect_no_offenses(<<~RUBY)
87+
<<-EOS.do_something.strip_heredoc
88+
some text
89+
EOS
90+
RUBY
91+
end
92+
93+
it 'does not register an offense when using `strip_heredoc` without receiver' do
94+
expect_no_offenses(<<~RUBY)
95+
strip_heredoc
96+
RUBY
97+
end
98+
end
99+
end

0 commit comments

Comments
 (0)