Skip to content

Commit

Permalink
Merge pull request #291 from mobilutz/ll-squished-heredocs
Browse files Browse the repository at this point in the history
Add new `Rails/SquishedSQLHeredocs` cop
  • Loading branch information
koic authored Aug 20, 2020
2 parents bc81fa9 + d2e978c commit 9e2ff2c
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

### New features

* [#291](https://github.com/rubocop-hq/rubocop-rails/pull/291): Add new `Rails/SquishedSQLHeredocs` cop. ([@mobilutz][])
* [#283](https://github.com/rubocop-hq/rubocop-rails/pull/283): Add new `Rails/FindById` cop. ([@fatkodima][])
* [#285](https://github.com/rubocop-hq/rubocop-rails/pull/285): Add new `Rails/ActiveRecordCallbacksOrder` cop. ([@fatkodima][])
* [#276](https://github.com/rubocop-hq/rubocop-rails/pull/276): Add new `Rails/RenderPlainText` cop. ([@fatkodima][])
Expand Down Expand Up @@ -269,3 +270,4 @@
[@philcoggins]: https://github.com/philcoggins
[@kunitoo]: https://github.com/kunitoo
[@jaredmoody]: https://github.com/jaredmoody
[@mobilutz]: https://github.com/mobilutz
6 changes: 6 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,12 @@ Rails/SkipsModelValidations:
- upsert_all
AllowedMethods: []

Rails/SquishedSQLHeredocs:
Description: 'Checks SQL heredocs to use `.squish`.'
StyleGuide: 'https://rails.rubystyle.guide/#squished-heredocs'
Enabled: 'pending'
VersionAdded: '2.8'

Rails/TimeZone:
Description: 'Checks the correct usage of time zone aware methods.'
StyleGuide: 'https://rails.rubystyle.guide#time'
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ based on the https://rails.rubystyle.guide/[Rails Style Guide].
* xref:cops_rails.adoc#railsscopeargs[Rails/ScopeArgs]
* xref:cops_rails.adoc#railsshorti18n[Rails/ShortI18n]
* xref:cops_rails.adoc#railsskipsmodelvalidations[Rails/SkipsModelValidations]
* xref:cops_rails.adoc#railssquishedsqlheredocs[Rails/SquishedSQLHeredocs]
* xref:cops_rails.adoc#railstimezone[Rails/TimeZone]
* xref:cops_rails.adoc#railsuniqbeforepluck[Rails/UniqBeforePluck]
* xref:cops_rails.adoc#railsuniquevalidationwithoutindex[Rails/UniqueValidationWithoutIndex]
Expand Down
53 changes: 53 additions & 0 deletions docs/modules/ROOT/pages/cops_rails.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3932,6 +3932,59 @@ user.touch

* https://guides.rubyonrails.org/active_record_validations.html#skipping-validations

== Rails/SquishedSQLHeredocs

|===
| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged

| Pending
| Yes
| Yes
| 2.8
| -
|===

Checks SQL heredocs to use `.squish`.

=== Examples

[source,ruby]
----
# bad
<<-SQL
SELECT * FROM posts;
SQL
<<-SQL
SELECT * FROM posts
WHERE id = 1
SQL
execute(<<~SQL, "Post Load")
SELECT * FROM posts
WHERE post_id = 1
SQL
# good
<<-SQL.squish
SELECT * FROM posts;
SQL
<<~SQL.squish
SELECT * FROM table
WHERE id = 1
SQL
execute(<<~SQL.squish, "Post Load")
SELECT * FROM posts
WHERE post_id = 1
SQL
----

=== References

* https://rails.rubystyle.guide/#squished-heredocs

== Rails/TimeZone

|===
Expand Down
83 changes: 83 additions & 0 deletions lib/rubocop/cop/rails/squished_sql_heredocs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Rails
#
# Checks SQL heredocs to use `.squish`.
#
# @example
# # bad
# <<-SQL
# SELECT * FROM posts;
# SQL
#
# <<-SQL
# SELECT * FROM posts
# WHERE id = 1
# SQL
#
# execute(<<~SQL, "Post Load")
# SELECT * FROM posts
# WHERE post_id = 1
# SQL
#
# # good
# <<-SQL.squish
# SELECT * FROM posts;
# SQL
#
# <<~SQL.squish
# SELECT * FROM table
# WHERE id = 1
# SQL
#
# execute(<<~SQL.squish, "Post Load")
# SELECT * FROM posts
# WHERE post_id = 1
# SQL
#
class SquishedSQLHeredocs < Cop
include Heredoc

SQL = 'SQL'
SQUISH = '.squish'
MSG = 'Use `%<expect>s` instead of `%<current>s`.'

def on_heredoc(node)
return unless offense_detected?(node)

add_offense(node)
end

def autocorrect(node)
lambda do |corrector|
corrector.insert_after(node, SQUISH)
end
end

private

def offense_detected?(node)
sql_heredoc?(node) && !using_squish?(node)
end

def sql_heredoc?(node)
delimiter_string(node) == SQL
end

def using_squish?(node)
node.parent&.send_type? && node.parent&.method?(:squish)
end

def message(node)
format(
MSG,
expect: "#{node.source}#{SQUISH}",
current: node.source
)
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rails_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
require_relative 'rails/scope_args'
require_relative 'rails/short_i18n'
require_relative 'rails/skips_model_validations'
require_relative 'rails/squished_sql_heredocs'
require_relative 'rails/time_zone'
require_relative 'rails/uniq_before_pluck'
require_relative 'rails/unique_validation_without_index'
Expand Down
86 changes: 86 additions & 0 deletions spec/rubocop/cop/rails/squished_sql_heredocs_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Rails::SquishedSQLHeredocs, :config do
subject(:cop) { described_class.new(config) }

context 'with multi line heredoc' do
it 'registers an offense and corrects it' do
expect_offense(<<~RUBY)
<<~SQL
^^^^^^ Use `<<~SQL.squish` instead of `<<~SQL`.
SELECT * FROM posts
WHERE id = 1
SQL
RUBY

expect_correction(<<~RUBY)
<<~SQL.squish
SELECT * FROM posts
WHERE id = 1
SQL
RUBY
end

it 'does not register an offense' do
expect_no_offenses(<<~RUBY)
<<-SQL.squish
SELECT * FROM posts
WHERE id = 1
SQL
RUBY
end
end

context 'with single line heredoc' do
it 'registers an offense and corrects it' do
expect_offense(<<~RUBY)
<<-SQL
^^^^^^ Use `<<-SQL.squish` instead of `<<-SQL`.
SELECT * FROM posts;
SQL
RUBY

expect_correction(<<~RUBY)
<<-SQL.squish
SELECT * FROM posts;
SQL
RUBY
end

it 'does not register an offense' do
expect_no_offenses(<<~RUBY)
<<-SQL.squish
SELECT * FROM posts;
SQL
RUBY
end
end

context 'with heredocs as method parameters' do
it 'registers an offense and corrects it' do
expect_offense(<<~RUBY)
execute(<<~SQL, "Post Load")
^^^^^^ Use `<<~SQL.squish` instead of `<<~SQL`.
SELECT * FROM posts
WHERE post_id = 1
SQL
RUBY

expect_correction(<<~RUBY)
execute(<<~SQL.squish, "Post Load")
SELECT * FROM posts
WHERE post_id = 1
SQL
RUBY
end

it 'does not register an offense' do
expect_no_offenses(<<~RUBY)
execute(<<~SQL.squish, "Post Load")
SELECT * FROM posts
WHERE post_id = 1
SQL
RUBY
end
end
end

0 comments on commit 9e2ff2c

Please sign in to comment.