Class: RuboCop::Cop::DevDoc::Style::RepeatedSafeNavigationReceiver

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/dev_doc/style/repeated_safe_navigation_receiver.rb

Overview

Avoid using ‘&.` on the same receiver more than once in a method body.

## Rationale When a receiver appears with ‘&.` repeatedly across a method, the reader has to mentally re-evaluate the nil case at every call, and the intent of each `&.` becomes ambiguous — is this call nullable for a fresh reason, or is the dev just mirroring the earlier `&.` out of habit? Repetition also propagates nil silently into downstream comparisons (`current_user&.id == something` evaluates to `nil == something`, which is false but not for the reason the reader expects).

Resolve the nil case once at the top of the method, then use the local with plain ‘.`:

❌
def show?
  current_user&.super_admin? ||
    current_user&.developer?  ||
    current_user&.admin_of_organization?(organization)
end

✔️ Guard once, then plain calls
def show?
  return false unless current_user

  current_user.super_admin? ||
    current_user.developer?  ||
    current_user.admin_of_organization?(organization)
end

✔️ Alternative — assign-and-test in the condition
def label
  if (user = current_user)
    "#{user.full_name} <#{user.email}>"
  end
end

The cop is policy-safe by design: it does not assume anything about ‘current_user` non-nullability or branching semantics — it only flags repeated `&.` on the same receiver, which is a smell regardless of whether the receiver is `current_user`, a model attribute, or a local variable.

## Exception Legitimate cases (e.g. when the repeated calls are conceptually distinct sources that happen to share source spelling) go through inline ‘# rubocop:disable` with a reason.

NOTE: Receivers are compared by source text — two ‘&.` calls share a receiver if their source spelling matches verbatim. The cop does not perform flow analysis, so a receiver reassigned between uses is not detected (false negative).

NOTE: Scope is the enclosing ‘def`/`defs` body. The cop does not partition by inner blocks, so the same parameter name reused across separate block bodies in one method may produce a false positive — inline-disable with a reason if it surfaces.

Examples:

# bad — same receiver, multiple safe-nav reads
def card
  name = current_user&.full_name
  email = current_user&.email
end

# bad — same receiver, multiple safe-nav predicates
def show?
  user&.super_admin? || user&.developer?
end

# good — assign once, then plain calls
def show?
  return false unless user

  user.super_admin? || user.developer?
end

# good — single use of safe-nav
def label
  current_user&.full_name
end

Constant Summary collapse

MSG =
"Receiver `%<receiver>s` already used with `&.` earlier in this method — assign once and use `.` after.".freeze

Instance Method Summary collapse

Instance Method Details

#on_def(node) ⇒ Object Also known as: on_defs



90
91
92
# File 'lib/rubocop/cop/dev_doc/style/repeated_safe_navigation_receiver.rb', line 90

def on_def(node)
  check_method(node)
end