Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new Rails/SquishedSQLHeredocs cop #291

Merged
merged 1 commit into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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