module Pakyow::UI::Recordable
@api private
Constants
- PRIORITY_CALLS
Attributes
calls[R]
@api private
Public Class Methods
new(*)
click to toggle source
Calls superclass method
# File lib/pakyow/ui/recordable.rb, line 234 def initialize(*) super @calls = [] cache_bindings! end
Private Class Methods
find_through(binding_path, binding_info, options, context, calls)
click to toggle source
# File lib/pakyow/ui/recordable.rb, line 164 def self.find_through(binding_path, binding_info, options, context, calls) if binding_path.any? binding_path_part = binding_path.shift current_options = options.dup if id = binding_info[binding_path_part.to_s.split(":", 2)[0].to_sym] # Tie the transformations to a node of a specific id, unless we're transforming the entire set. # unless calls.any? { |call| call[0] == :transform } current_options["id"] = id end end subsequent = [] args = [[binding_path_part]] unless current_options.empty? args << current_options end context << [ :find, args, [], subsequent ] find_through(binding_path, binding_info, options, subsequent, calls) else context.concat(calls) end end
Public Instance Methods
cache_bindings!()
click to toggle source
@api private
# File lib/pakyow/ui/recordable.rb, line 42 def cache_bindings! binding_nodes = if (view.object.is_a?(StringDoc::Node) || view.object.is_a?(StringDoc::MetaNode)) && view.object.significant?(:multipart_binding) [view.object] else view.object.find_significant_nodes(:binding) end @bindings = binding_nodes.flat_map { |node| [node.label(:binding), node.label(:binding_prop)] }.compact end
to_a()
click to toggle source
# File lib/pakyow/ui/recordable.rb, line 37 def to_a @calls end
to_json(*)
click to toggle source
# File lib/pakyow/ui/recordable.rb, line 33 def to_json(*) optimized.to_json end
Private Instance Methods
attributes()
click to toggle source
Calls superclass method
# File lib/pakyow/ui/recordable.rb, line 295 def attributes Attributes.from_attributes(super).tap do |subsequent| calls << [:attributes, [], [], subsequent] end end
Also aliased as: attrs
call_priority(call, calls)
click to toggle source
# File lib/pakyow/ui/recordable.rb, line 80 def call_priority(call, calls) if PRIORITY_CALLS.include?(call[0]) # Set priority calls to a priority of -1000, which is highest priority. # -1000 elsif call[0] == :find # Make priority of finds an inverse of specificity (e.g. [:post] > [:post, :title]). # -1000 + call[1][0].count else # Or just keep the same order we have now. # calls.index(call) end end
from_presenter(presenter)
click to toggle source
# File lib/pakyow/ui/recordable.rb, line 220 def from_presenter(presenter) allocate.tap { |instance| # Copy state from the presenter we're tracking. # presenter.instance_variables.each do |ivar| instance.instance_variable_set(ivar, presenter.instance_variable_get(ivar)) end instance.cache_bindings! } end
optimized()
click to toggle source
# File lib/pakyow/ui/recordable.rb, line 56 def optimized calls = [] # Combine finds when looking for the same nodes. # @calls.each do |call| if call[0] == :find && matching_call = calls.find { |c| c[0] == :find && c[1] == call[1] && c[2] == call[2] } matching_call[3].to_a.concat(call[3].to_a) else calls << call end end # Prioritize the calls so they are applied correctly on the client. # calls.sort! { |a, b| call_priority(a, calls) <=> call_priority(b, calls) } calls end
presenter_for(view, type: view&.label(:presenter_type))
click to toggle source
Calls superclass method
# File lib/pakyow/ui/recordable.rb, line 241 def presenter_for(view, type: view&.label(:presenter_type)) presenter = super if presenter.is_a?(Delegator) presenter.__setobj__(self.class.from_presenter(presenter.__getobj__)) else presenter = self.class.from_presenter(presenter) end presenter end
render_proc(view, render, &block)
click to toggle source
Calls superclass method
# File lib/pakyow/ui/recordable.rb, line 196 def render_proc(view, render, &block) super(view, render) do |_, context| if render[:node] instance_exec(&block) # The super proc creates a new presenter instance per render, but we want each to use the # same starting point for calls since they all apply to the same node. # context.calls.concat(calls) else instance_exec(&block) if calls.any? # Explicitly find the node to apply the transformation to the correct node. While # we're at it, append any transformations caused by the `instance_exec` above. # Recordable.find_through( render[:binding_path].dup, object.label(:binding_info).to_h, {}, context.calls, calls ) end end end end
viewify(data)
click to toggle source
FIXME: We currently viewify twice for present; once for transform, another for bind. Let's create a `Viewified` object instead… then check to see if it's already happened.
# File lib/pakyow/ui/recordable.rb, line 99 def viewify(data) data = if data.is_a?(Data::Proxy) data.to_a elsif data.nil? [] else Array.ensure(data) end data.map { |object| binder = wrap_data_in_binder(object) object = binder.object # Map object keys to the binding name. # keys_and_binding_names = object.to_h.keys.map { |key| key = key.to_sym if key == :id || @bindings.include?(key) binding_name = key else plural_binding_name = Support.inflector.pluralize(key.to_s).to_sym singular_binding_name = Support.inflector.singularize(key.to_s).to_sym if @bindings.include?(plural_binding_name) binding_name = plural_binding_name elsif @bindings.include?(singular_binding_name) binding_name = singular_binding_name else next end end [key, binding_name] } # Add view-specific bindings that aren't in the object, but may exist in the binder. # @bindings.each do |binding_name| unless keys_and_binding_names.find { |_, k2| k2 == binding_name } keys_and_binding_names << [binding_name, binding_name] end end viewified = keys_and_binding_names.compact.uniq.each_with_object({}) { |(key, binding_name), values| value = binder.__value(key) if value.is_a?(String) value = ensure_html_safety(value) end if value.is_a?(Presenter::BindingParts) values[binding_name] = value.values(@view.find(binding_name)) elsif !value.nil? values[binding_name] = value end } viewified } end