Skip to content

Commit

Permalink
Merge pull request #133 from gyfis/th/safe-nagivation-with-blank
Browse files Browse the repository at this point in the history
Add Rails/SafeNavigationWithBlank cop
  • Loading branch information
koic authored Nov 12, 2019
2 parents c607c66 + 35b9cc0 commit eb02e64
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

* [#123](https://github.com/rubocop-hq/rubocop-rails/pull/123): Add new `Rails/ApplicationController` and `Rails/ApplicationMailer` cops. ([@eugeneius][])
* [#130](https://github.com/rubocop-hq/rubocop-rails/pull/130): Add new `Rails/RakeEnvironment` cop. ([@pocke][])
* [#132](https://github.com/rubocop-hq/rubocop-rails/pull/132): Add new `Rails/SafeNavigationWithBlank` cop. ([@gyfis][])

### Bug fixes

Expand Down Expand Up @@ -98,4 +99,5 @@
[@forresty]: https://github.com/forresty
[@sinsoku]: https://github.com/sinsoku
[@pocke]: https://github.com/pocke
[@gyfis]: https:/github.com/gyfis
[@DNA]: https://github.com/DNA
12 changes: 12 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,18 @@ Rails/SafeNavigation:
# implement the intended method. `try` will not raise an exception for this.
ConvertTry: false

Rails/SafeNavigationWithBlank:
Description: 'Avoid `foo&.blank?` in conditionals.'
Enabled: true
VersionAdded: '2.4'
# While the safe navigation operator is generally a good idea, when
# checking `foo&.blank?` in a conditional, `foo` being `nil` will actually
# do the opposite of what the author intends.
#
# foo&.blank? #=> nil
# foo.blank? #=> true
SafeAutoCorrect: false

Rails/SaveBang:
Description: 'Identifies possible cases where Active Record save! or related should be used.'
StyleGuide: 'https://rails.rubystyle.guide#save-bang'
Expand Down
48 changes: 48 additions & 0 deletions lib/rubocop/cop/rails/safe_nagivation_with_blank.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Rails
# This cop checks to make sure safe navigation isn't used with `blank?` in
# a conditional.
#
# While the safe navigation operator is generally a good idea, when
# checking `foo&.blank?` in a conditional, `foo` being `nil` will actually
# do the opposite of what the author intends.
#
# @example
# # bad
# do_something if foo&.blank?
# do_something unless foo&.blank?
#
# # good
# do_something if foo.blank?
# do_something unless foo.blank?
#
class SafeNavigationWithBlank < Cop
MSG =
'Avoid calling `blank?` with the safe navigation operator ' \
'in conditionals.'

def_node_matcher :safe_navigation_blank_in_conditional?, <<-PATTERN
(if $(csend ... :blank?) ...)
PATTERN

def on_if(node)
return unless safe_navigation_blank_in_conditional?(node)

add_offense(node)
end

def autocorrect(node)
lambda do |corrector|
corrector.replace(
safe_navigation_blank_in_conditional?(node).location.dot,
'.'
)
end
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 @@ -51,6 +51,7 @@
require_relative 'rails/request_referer'
require_relative 'rails/reversible_migration'
require_relative 'rails/safe_navigation'
require_relative 'rails/safe_nagivation_with_blank'
require_relative 'rails/save_bang'
require_relative 'rails/scope_args'
require_relative 'rails/skips_model_validations'
Expand Down
1 change: 1 addition & 0 deletions manual/cops.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
* [Rails/RequestReferer](cops_rails.md#railsrequestreferer)
* [Rails/ReversibleMigration](cops_rails.md#railsreversiblemigration)
* [Rails/SafeNavigation](cops_rails.md#railssafenavigation)
* [Rails/SafeNavigationWithBlank](cops_rails.md#railssafenavigationwithblank)
* [Rails/SaveBang](cops_rails.md#railssavebang)
* [Rails/ScopeArgs](cops_rails.md#railsscopeargs)
* [Rails/SkipsModelValidations](cops_rails.md#railsskipsmodelvalidations)
Expand Down
25 changes: 25 additions & 0 deletions manual/cops_rails.md
Original file line number Diff line number Diff line change
Expand Up @@ -2144,6 +2144,31 @@ Name | Default value | Configurable values
--- | --- | ---
ConvertTry | `false` | Boolean

## Rails/SafeNavigationWithBlank

Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
--- | --- | --- | --- | ---
Enabled | Yes | Yes (Unsafe) | 2.4 | -

This cop checks to make sure safe navigation isn't used with `blank?` in
a conditional.

While the safe navigation operator is generally a good idea, when
checking `foo&.blank?` in a conditional, `foo` being `nil` will actually
do the opposite of what the author intends.

### Examples

```ruby
# bad
do_something if foo&.blank?
do_something unless foo&.blank?

# good
do_something if foo.blank?
do_something unless foo.blank?
```

## Rails/SaveBang

Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
Expand Down
43 changes: 43 additions & 0 deletions spec/rubocop/cop/rails/safe_navigation_with_blank_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

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

context 'in a conditional' do
it 'registers an offense on a single conditional' do
expect_offense(<<~RUBY)
do_something unless foo&.blank?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid calling `blank?` with the safe navigation operator in conditionals.
RUBY

expect_correction(<<~RUBY)
do_something unless foo.blank?
RUBY
end

it 'registers an offense on chained conditionals' do
expect_offense(<<~RUBY)
do_something unless foo&.bar&.blank?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid calling `blank?` with the safe navigation operator in conditionals.
RUBY

expect_correction(<<~RUBY)
do_something unless foo&.bar.blank?
RUBY
end

it 'does not register an offense on `.blank?`' do
expect_no_offenses(<<~RUBY)
return if foo.blank?
RUBY
end
end

context 'outside a conditional' do
it 'registers no offense' do
expect_no_offenses(<<~RUBY)
bar = foo&.blank?
RUBY
end
end
end

0 comments on commit eb02e64

Please sign in to comment.