Class: RuboCop::Cop::DevDoc::Style::MinimizeVariableScope
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::DevDoc::Style::MinimizeVariableScope
- Defined in:
- lib/rubocop/cop/dev_doc/style/minimize_variable_scope.rb
Overview
Assign a variable inside the if condition that guards it, so the
variable's scope is the branch that actually uses it.
Rationale
When a local is assigned and then immediately gated by a truthiness check, hoisting the assignment to its own line widens its scope to the whole method and separates the binding from the guard. Folding the assignment into the condition (with parentheses) keeps the variable local to the branch that uses it and reads as one thought.
❌
token = params[:token]
if token
authenticate(token)
end
✔️
if (token = params[:token])
authenticate(token)
end
Parentheses around the assignment silence Ruby's "assignment in condition" warning and signal the assignment is intentional.
When it fires
Only when the assigned variable is used only inside the guarding
if — its condition plus the true branch — and is read at least once
in that branch. If the variable is read in the else branch or after
the block, folding wouldn't narrow its scope, so the cop leaves it.
Exception
When the assigned expression is long, inlining it into the condition
hurts readability more than the scope-narrowing helps. Keep the
two-line form and inline-disable with a reason.
NOTE: Conservative by design — it skips reassigned variables, op_asgn
(+=, ||=), compound/comparison conditions, and scopes containing a
nested def or a block that rebinds the same name. Those are left
un-flagged rather than risk a wrong rewrite.
Constant Summary collapse
- MSG =
"Assign `%<name>s` inside the `if` condition " \ "(`if (%<name>s = ...)`) so its scope is the branch that uses it.".freeze
- TRUTHY_PREDICATES =
Truthiness-shaped predicates we fold. Comparisons (
x == 1) are deliberately excluded — folding those reads as assignment-in-condition. %i[present? any? presence].freeze
Instance Method Summary collapse
Instance Method Details
#on_lvasgn(node) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/rubocop/cop/dev_doc/style/minimize_variable_scope.rb', line 64 def on_lvasgn(node) name, value = *node return unless value if_node = guarding_if(node) return unless if_node return unless truthiness_check?(if_node.condition, name) return unless confined_to_if?(node, if_node, name) add_offense(node.loc.name, message: format(MSG, name: name)) end |