Class: LiveCable::Rendering::PartialRenderer
- Inherits:
-
Object
- Object
- LiveCable::Rendering::PartialRenderer
- Defined in:
- lib/live_cable/rendering/partial_renderer.rb
Overview
Base class for partial renderers with common functionality
Instance Attribute Summary collapse
- #component ⇒ LiveCable::Component readonly
Instance Method Summary collapse
-
#expand_component_method_dependencies(method_names) ⇒ Array<Symbol>
Expand component.method_name calls to their transitive dependencies Results are cached per render cycle to avoid redundant analysis.
-
#initialize(component, parts, view_context) ⇒ PartialRenderer
constructor
A new instance of PartialRenderer.
- #mark_locals_dirty(locals) ⇒ Object
- #method_missing(method) ⇒ Object
-
#render ⇒ Object
Pass through renders to the view context, otherwise method_missing will pass to the component instead since it also has a render method.
- #render_changes(changes = :all) ⇒ Object
- #respond_to_missing?(method, _include_private = false) ⇒ Boolean
-
#should_skip_part?(changes, component_dependencies, component_method_calls, local_dependencies) ⇒ Boolean
Check if this part should be skipped based on its dependencies.
Constructor Details
#initialize(component, parts, view_context) ⇒ PartialRenderer
Returns a new instance of PartialRenderer.
10 11 12 13 14 |
# File 'lib/live_cable/rendering/partial_renderer.rb', line 10 def initialize(component, parts, view_context) @component = component @parts = parts @view_context = view_context end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/live_cable/rendering/partial_renderer.rb', line 97 def method_missing(method, ...) if locals.key?(method) return locals[method] end if component.respond_to?(method) return component.public_send(method, ...) end if view_context.respond_to?(method) return view_context.public_send(method, ...) end super end |
Instance Attribute Details
#component ⇒ LiveCable::Component (readonly)
8 9 10 |
# File 'lib/live_cable/rendering/partial_renderer.rb', line 8 def component @component end |
Instance Method Details
#expand_component_method_dependencies(method_names) ⇒ Array<Symbol>
Expand component.method_name calls to their transitive dependencies Results are cached per render cycle to avoid redundant analysis
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/live_cable/rendering/partial_renderer.rb', line 47 def (method_names) return [] if method_names.empty? # Use cache key based on the sorted method names array cache_key = method_names.sort # Return cached result if available return method_deps_cache[cache_key] if method_deps_cache.key?(cache_key) # Get the analyzer for the component class analyzer = component.class.method_dependencies_analyzer = [] method_names.each do |method_name| # Get transitive dependencies for this method deps = analyzer.(method_name) .concat(deps.to_a) end # Cache and return the result method_deps_cache[cache_key] = .uniq end |
#mark_locals_dirty(locals) ⇒ Object
39 40 41 |
# File 'lib/live_cable/rendering/partial_renderer.rb', line 39 def mark_locals_dirty(locals) locals.each { |local| dirty_locals << local } end |
#render ⇒ Object
Pass through renders to the view context, otherwise method_missing will pass to the component instead since it also has a render method
35 36 37 |
# File 'lib/live_cable/rendering/partial_renderer.rb', line 35 def render(*) view_context.render(*) end |
#render_changes(changes = :all) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/live_cable/rendering/partial_renderer.rb', line 16 def render_changes(changes = :all) # No changes, different from :all (:all means render all) # Return an array of nils if changes == [] return Array.new(parts.size, nil) end @locals = {} @dirty_locals = Set.new # Track which locals were recomputed this render @method_deps_cache = {} # Cache method dependency expansion for this render cycle parts.each_with_index.with_object([]) do |item, acc| part, index = item result = view_context.render_part(index) { send("render_part_#{index}", changes) } acc << result unless part[0] == :code end end |
#respond_to_missing?(method, _include_private = false) ⇒ Boolean
113 114 115 |
# File 'lib/live_cable/rendering/partial_renderer.rb', line 113 def respond_to_missing?(method, _include_private = false) locals.key?(method) || component.respond_to?(method) || view_context.respond_to?(method) end |
#should_skip_part?(changes, component_dependencies, component_method_calls, local_dependencies) ⇒ Boolean
Check if this part should be skipped based on its dependencies
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/live_cable/rendering/partial_renderer.rb', line 76 def should_skip_part?(changes, component_dependencies, component_method_calls, local_dependencies) # Always render on initial render (all parts) return false if changes == :all # Always render on template switch (all dynamic parts must render) return false if changes == :dynamic # Expand component.method_name calls to their transitive dependencies = (component_method_calls) all_component_deps = component_dependencies | # Render if any component dependencies changed return false if changes.intersect?(all_component_deps) # Render if any local dependencies are dirty return false if dirty_locals.intersect?(local_dependencies) # Otherwise, skip rendering this part true end |