Class: LiveCable::Container
- Inherits:
-
Hash
- Object
- Hash
- LiveCable::Container
- Defined in:
- lib/live_cable/container.rb
Overview
Storage for reactive variable values with automatic change tracking.
A Container is a Hash subclass that stores the values of reactive variables for a single component instance. It automatically wraps supported types (Arrays, Hashes, ActiveRecord models) in Delegators that track mutations.
Architecture:
- Each component instance has its own Container (identified by live_id)
- Shared reactive variables use a special SHARED_CONTAINER
- During message processing, mutations are tracked in a changeset
- After message processing, components with dirty changesets are re-rendered
- Changesets are reset after broadcasting updates
Change Tracking:
- Value is stored via []=
- If value is an Array/Hash/Model, it's wrapped in a Delegator
- Delegator attaches observers to the value
- When value is mutated, observers mark the variable as dirty
- Component re-renders if changeset contains the variable
Instance Attribute Summary collapse
-
#changeset ⇒ Array<Symbol>
readonly
Returns the list of variables that have changed during this message cycle.
Instance Method Summary collapse
-
#[]=(key, value) ⇒ Object
Store a value in the container, automatically wrapping supported types in Delegators for change tracking.
-
#changed? ⇒ Boolean
Check if any variables have changed.
-
#cleanup ⇒ void
Clean up all observer references to prevent memory leaks.
-
#initialize ⇒ Container
constructor
A new instance of Container.
-
#mark_dirty(*variables) ⇒ void
Mark one or more variables as dirty (changed).
-
#observer ⇒ LiveCable::Observer
Get or create the observer for this container.
-
#reset_changeset ⇒ void
Clear the changeset after broadcasting updates.
Constructor Details
#initialize ⇒ Container
Returns a new instance of Container.
31 32 33 34 |
# File 'lib/live_cable/container.rb', line 31 def initialize(...) super @changeset = [] end |
Instance Attribute Details
#changeset ⇒ Array<Symbol> (readonly)
Returns the list of variables that have changed during this message cycle.
81 82 83 |
# File 'lib/live_cable/container.rb', line 81 def changeset @changeset end |
Instance Method Details
#[]=(key, value) ⇒ Object
Store a value in the container, automatically wrapping supported types in Delegators for change tracking.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/live_cable/container.rb', line 47 def []=(key, value) # Remove observer from the old value so it stops notifying this container self[key].try(:remove_live_cable_observer, observer, key) # ActiveRecord models get observers attached directly if value.class < ModelObserver value.add_live_cable_observer(observer, key) end # If value is already a Delegator, add observer and store as-is if value.is_a?(Delegator) value.add_live_cable_observer(observer, key) super else # Wrap supported types in Delegators for change tracking super(key, Delegator.create_if_supported(value, key, observer)) end end |
#changed? ⇒ Boolean
Check if any variables have changed.
86 87 88 |
# File 'lib/live_cable/container.rb', line 86 def changed? !@changeset.empty? end |
#cleanup ⇒ void
This method returns an undefined value.
Clean up all observer references to prevent memory leaks. This breaks the reference chain between delegators, observers, and the container.
Should be called when the component is destroyed.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/live_cable/container.rb', line 112 def cleanup # Remove this container's observer from all delegated values # Note: We only remove this specific observer, not all observers, # because the same object might be shared across multiple containers each do |variable, value| if value.respond_to?(:remove_live_cable_observer) value.remove_live_cable_observer(observer, variable) end end # Clear the container's data clear @changeset&.clear @observer = nil end |
#mark_dirty(*variables) ⇒ void
This method returns an undefined value.
Mark one or more variables as dirty (changed). Dirty variables will trigger a re-render of their component.
74 75 76 |
# File 'lib/live_cable/container.rb', line 74 def mark_dirty(*variables) @changeset |= variables # Union operator keeps values unique end |
#observer ⇒ LiveCable::Observer
Get or create the observer for this container. Each container has exactly one observer instance.
102 103 104 |
# File 'lib/live_cable/container.rb', line 102 def observer @observer ||= Observer.new(self) end |
#reset_changeset ⇒ void
This method returns an undefined value.
Clear the changeset after broadcasting updates. Called by Connection after all components have been re-rendered.
94 95 96 |
# File 'lib/live_cable/container.rb', line 94 def reset_changeset @changeset = [] end |