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` 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` keep the spelling in sync, but if one of them silently becomes `params`, the line returns nil and the bug ships. A single assignment fixes the spelling in exactly one place — a typo there becomes a `NameError`, 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 ‘session` or 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[:slug])
redirect_to canonical_url(@item) if @item.slug != params[:slug]
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 = 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` and `hash` 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 }; other.each { |item| item }`) 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 |