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