Class: RuboCop::Cop::DevDoc::Style::RepeatedBracketRead
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::DevDoc::Style::RepeatedBracketRead
- Defined in:
- lib/rubocop/cop/dev_doc/style/repeated_bracket_read.rb
Overview
Avoid reading obj[key] more than once with the same receiver and
same key in a single method body.
Rationale
When the same bracket read appears in multiple places, two distinct failure modes open up:
-
Silent typos. Bracket access returns nil for missing keys; nothing raises. Two occurrences of
params[:status]keep the spelling in sync, but if one of them silently becomesparams[:stutus], the line returns nil and the bug ships. A single assignment fixes the spelling in exactly one place — a typo there becomes aNameError, not a silent nil. -
Reader ambiguity and mutation risk. The reader has to verify every occurrence really is the same key and that nothing in between mutates the hash. Assigning once makes the value a stable named thing — and on receivers like
sessionor shared hashes, it also avoids a real TOCTOU shape where the value can change between the guard and the use.
❌ def show @item = Item.lookup_by_slug(params) redirect_to canonical_url(@item) if @item.slug != params end
✔️
def show
slug = params[:slug]
@item = Item.lookup_by_slug(slug)
redirect_to canonical_url(@item) if @item.slug != slug
end
The cop only counts reads. obj[k] = v is a write (:[]=) and is
not compared against bracket reads of the same key.
Exception
Genuine intentional re-reads (e.g. a deliberate second check after
a write that may have mutated the receiver) go through inline
# rubocop:disable with a reason.
NOTE: Receiver and key are compared by source text — hash['foo']
and hash[:foo] look different to the cop even though they're the
same value on a HashWithIndifferentAccess like params. That is
a known false negative; the cop will miss that shape rather than
over-fire.
NOTE: Scope is the enclosing def/defs body, including nested
blocks. Block parameters are scoped to their block, so the same name
in two sibling blocks (arr.each { |item| item[:k] }; other.each { |item| item[:k] }) is correctly treated as two different bindings,
not a repeat. Reads of the same block param within one block are
still flagged. (Numbered/it block params are matched textually — a
rare residual false positive; inline-disable if it surfaces.)
NOTE: Multi-argument bracket calls (arr[i, len], slicing) are
ignored. Only single-argument reads participate.
Constant Summary collapse
- MSG =
"Receiver `%<receiver>s[%<key>s]` already read earlier in this method — assign once and reuse.".freeze
Instance Method Summary collapse
- #on_def(node) ⇒ Object (also: #on_defs)
Instance Method Details
#on_def(node) ⇒ Object Also known as: on_defs
92 93 94 |
# File 'lib/rubocop/cop/dev_doc/style/repeated_bracket_read.rb', line 92 def on_def(node) check_method(node) end |