Skip to content

Commit

Permalink
Add Sevencop/OrderField cop
Browse files Browse the repository at this point in the history
  • Loading branch information
r7kamura committed Jun 18, 2022
1 parent 8fc5595 commit 94b8dbf
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Added

- Add `Sevencop/OrderField` cop.

### Changed

- Improve performance of `Sevencop/UniquenessValidatorExplicitCaseSensitivity` cop.
Expand Down
22 changes: 21 additions & 1 deletion README.md
Expand Up @@ -35,6 +35,26 @@ require:

## Cops

### Sevencop/OrderField

Identifies a String including "field" is passed to `order` or `reorder`.

```ruby
# bad
articles.order('field(id, ?)', a)

# good
articles.order(Arel.sql('field(id, ?)'), a)

# bad
reorder('field(id, ?)', a)

# good
reorder(Arel.sql('field(id, ?)'), a)
```

`Enabled: false` by default.

### `Sevencop/RedundantExistenceCheck`

Identifies redundant existent check before file operation.
Expand Down Expand Up @@ -76,4 +96,4 @@ validates :name, uniqueness: { allow_nil: true, scope: :user_id, case_sensitive:

Useful to keep the same behavior between Rails 6.0 and 6.1 where case insensitive collation is used in MySQL.

Note that this cop is `Enabled: false` by default.
`Enabled: false` by default.
6 changes: 6 additions & 0 deletions config/default.yml
@@ -1,3 +1,9 @@
Sevencop/UniquenessValidatorExplicitCaseSensitivity:
Description: Wrap safe SQL String by `Arel.sql`.
Enabled: false
Safe: false
VersionAdded: '0.4'

Sevencop/RedundantExistenceCheck:
Description: Avoid redundant existent check before file operation.
Enabled: true
Expand Down
62 changes: 62 additions & 0 deletions lib/rubocop/cop/sevencop/order_field.rb
@@ -0,0 +1,62 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Sevencop
# Identifies a String including "field" is passed to `order` or `reorder`.
#
# @safety
# This cop is unsafe because it can register a false positive.
#
# @example
#
# # bad
# articles.order('field(id, ?)', a)
#
# # good
# articles.order(Arel.sql('field(id, ?)'), a)
#
# # bad
# reorder('field(id, ?)', a)
#
# # good
# reorder(Arel.sql('field(id, ?)'), a)
#
class OrderField < Base
extend AutoCorrector

MSG = 'Wrap safe SQL String by `Arel.sql`.'

RESTRICT_ON_SEND = %i[
order
reorder
].freeze

ORDER_METHOD_NAMES = ::Set[
*RESTRICT_ON_SEND
]

def_node_matcher :order_with_field?, <<~PATTERN
(send
_ ORDER_METHOD_NAMES
(str /field\(.+\)/)
...
)
PATTERN

# @param [RuboCop::AST::SendNode] node
def on_send(node)
return unless order_with_field?(node)

first_argument_node = node.arguments.first
add_offense(first_argument_node) do |corrector|
corrector.replace(
node.arguments.first,
"Arel.sql(#{first_argument_node.source})"
)
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/sevencop.rb
Expand Up @@ -6,6 +6,7 @@
require_relative 'sevencop/inject'
require_relative 'sevencop/version'

require_relative 'rubocop/cop/sevencop/order_field'
require_relative 'rubocop/cop/sevencop/redundant_existence_check'
require_relative 'rubocop/cop/sevencop/uniqueness_validator_explicit_case_sensitivity'

Expand Down
58 changes: 58 additions & 0 deletions spec/rubocop/cop/rails_deprecation/order_field_spec.rb
@@ -0,0 +1,58 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Sevencop::OrderField, :config do
context 'without field' do
it 'registers no offense' do
expect_no_offenses(<<~TEXT)
articles.order('id DESC')
TEXT
end
end

context 'with Hash' do
it 'registers no offense' do
expect_no_offenses(<<~TEXT)
articles.order(id: :desc)
TEXT
end
end

context 'with receiver' do
it 'autocorrects offense' do
expect_offense(<<~TEXT)
articles.order('field(id, ?)', a)
^^^^^^^^^^^^^^ Wrap safe SQL String by `Arel.sql`.
TEXT

expect_correction(<<~RUBY)
articles.order(Arel.sql('field(id, ?)'), a)
RUBY
end
end

context 'without receiver' do
it 'autocorrects offense' do
expect_offense(<<~TEXT)
order('field(id, ?)', a)
^^^^^^^^^^^^^^ Wrap safe SQL String by `Arel.sql`.
TEXT

expect_correction(<<~RUBY)
order(Arel.sql('field(id, ?)'), a)
RUBY
end
end

context 'with reorder' do
it 'autocorrects offense' do
expect_offense(<<~TEXT)
reorder('field(id, ?)', a)
^^^^^^^^^^^^^^ Wrap safe SQL String by `Arel.sql`.
TEXT

expect_correction(<<~RUBY)
reorder(Arel.sql('field(id, ?)'), a)
RUBY
end
end
end

0 comments on commit 94b8dbf

Please sign in to comment.