Class: RuboCop::Cop::Apartment::NoDirectCurrentWrite
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::Apartment::NoDirectCurrentWrite
- Defined in:
- lib/rubocop/cop/apartment/no_direct_current_write.rb
Overview
Bans direct assignment to Apartment::Current attributes. Application code must change tenant context through the block-form switch, which guarantees restore via ensure.
Covers plain assignment (‘=`) and operator assignment (`||=`, `&&=`, `+=`). Known syntactic limitations (deliberately not chased — they signal deliberate evasion and are out of scope for a lint nudge): multiple assignment (`a, Apartment::Current.tenant = …`), safe navigation (`Apartment::Current&.tenant = …`), dynamic dispatch (`Apartment::Current.public_send(:tenant=, …)`), bulk mutators (`Apartment::Current.set(…)` / `.reset`), and aliased receivers.
Constant Summary collapse
- MSG =
'Do not write `Apartment::Current.%<attr>s` directly; use the ' \ 'block-form `Apartment::Tenant.switch(tenant) { ... }`.'
- RESTRICT_ON_SEND =
Only invoke on_send for these setters — keeps the cop off the hot path (RuboCop would otherwise call on_send for every method call linted).
%i[tenant= previous_tenant=].freeze
Instance Method Summary collapse
-
#current_attr_lhs?(node) ⇒ Object
The reader-shaped LHS of an operator-assignment (‘tenant ||= x` parses as an or_asgn around `(send recv :tenant)`, not a `:tenant=` send).
- #current_attr_write?(node) ⇒ Object
- #on_op_asgn(node) ⇒ Object
-
#on_or_asgn(node) ⇒ Object
(also: #on_and_asgn)
‘||=` and `&&=` are or_asgn / and_asgn; `+=` etc.
- #on_send(node) ⇒ Object
Instance Method Details
#current_attr_lhs?(node) ⇒ Object
The reader-shaped LHS of an operator-assignment (‘tenant ||= x` parses as an or_asgn around `(send recv :tenant)`, not a `:tenant=` send).
41 42 43 |
# File 'lib/rubocop/cop/apartment/no_direct_current_write.rb', line 41 def_node_matcher :current_attr_lhs?, <<~PATTERN (send (const (const {nil? cbase} :Apartment) :Current) {:tenant :previous_tenant}) PATTERN |
#current_attr_write?(node) ⇒ Object
34 35 36 |
# File 'lib/rubocop/cop/apartment/no_direct_current_write.rb', line 34 def_node_matcher :current_attr_write?, <<~PATTERN (send (const (const {nil? cbase} :Apartment) :Current) {:tenant= :previous_tenant=} _) PATTERN |
#on_op_asgn(node) ⇒ Object
59 60 61 |
# File 'lib/rubocop/cop/apartment/no_direct_current_write.rb', line 59 def on_op_asgn(node) check_op_assign(node.children.first) end |
#on_or_asgn(node) ⇒ Object Also known as: on_and_asgn
‘||=` and `&&=` are or_asgn / and_asgn; `+=` etc. are op_asgn. The LHS is always the first child (a reader send). RESTRICT_ON_SEND does not apply to these callbacks, so the matcher does the filtering.
54 55 56 |
# File 'lib/rubocop/cop/apartment/no_direct_current_write.rb', line 54 def on_or_asgn(node) check_op_assign(node.children.first) end |
#on_send(node) ⇒ Object
45 46 47 48 49 |
# File 'lib/rubocop/cop/apartment/no_direct_current_write.rb', line 45 def on_send(node) return unless current_attr_write?(node) register(node, node.method_name.to_s.delete_suffix('=')) end |