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 ||= xparses 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 |