class Pakyow::Presenter::View
Provides an interface for manipulating view templates.
Constants
- INFO_MERGER
Thanks Dan! stackoverflow.com/a/30225093 @api private
Attributes
The logical path to the view template.
The object responsible for transforming and rendering the underlying document or node.
@api private
Public Class Methods
Creates a view wrapping an object.
# File lib/pakyow/presenter/view.rb, line 26 def from_object(object) instance = if object.is_a?(StringDoc::Node) && object.labeled?(:view_type) object.label(:view_type).allocate else allocate end instance.instance_variable_set(:@object, object) instance.instance_variable_set(:@info, {}) instance.instance_variable_set(:@logical_path, nil) if object.respond_to?(:attributes) instance.attributes = object.attributes else instance.instance_variable_set(:@attributes, nil) end instance end
@api private
# File lib/pakyow/presenter/view.rb, line 47 def from_view_or_string(view_or_string) case view_or_string when View, VersionedView view_or_string else View.new(Support::SafeStringHelpers.ensure_html_safety(view_or_string.to_s)) end end
Creates a view from a file.
# File lib/pakyow/presenter/view.rb, line 20 def load(path, content: nil) new(content || File.read(path)) end
Creates a view with html
.
# File lib/pakyow/presenter/view.rb, line 77 def initialize(html, info: {}, logical_path: nil) @object = StringDoc.new(html) @info, @logical_path = Support::IndifferentHash.deep(info), logical_path if @object.respond_to?(:attributes) self.attributes = @object.attributes else @attributes = nil end end
Public Instance Methods
Returns true if self
equals other
.
# File lib/pakyow/presenter/view.rb, line 392 def ==(other) other.is_a?(self.class) && @object == other.object end
@api private
# File lib/pakyow/presenter/view.rb, line 559 def add_info(*infos) tap do infos.each do |info| @info.merge!(Support::IndifferentHash.deep(info), &INFO_MERGER) end end end
Inserts a view or string after self
.
# File lib/pakyow/presenter/view.rb, line 322 def after(view_or_string) tap do @object.after(self.class.from_view_or_string(view_or_string).object) end end
Appends a view or string to self
.
# File lib/pakyow/presenter/view.rb, line 306 def append(view_or_string) tap do @object.append(self.class.from_view_or_string(view_or_string).object) end end
Returns attributes object for self
.
# File lib/pakyow/presenter/view.rb, line 398 def attributes @attributes end
Wraps attributes
in a {Attributes} instance.
# File lib/pakyow/presenter/view.rb, line 405 def attributes=(attributes) @attributes = Attributes.new(attributes) end
Inserts a view or string before self
.
# File lib/pakyow/presenter/view.rb, line 330 def before(view_or_string) tap do @object.before(self.class.from_view_or_string(view_or_string).object) end end
Binds a single object.
# File lib/pakyow/presenter/view.rb, line 276 def bind(object) tap do unless object.nil? each_binding_prop do |binding| binding_name = if binding.significant?(:multipart_binding) binding.label(:binding_prop) else binding.label(:binding) end if object.include?(binding_name) value = if object.is_a?(Binder) object.__content(binding_name, binding) else object[binding_name] end bind_value_to_node(value, binding) binding.set_label(:bound, true) end end attributes[:"data-id"] = object[:id] self.object.set_label(:bound, true) end end end
Returns true if self
is a binding.
# File lib/pakyow/presenter/view.rb, line 368 def binding? @object.significant?(:binding) end
@api private
# File lib/pakyow/presenter/view.rb, line 427 def binding_name label(:binding) end
@api private
# File lib/pakyow/presenter/view.rb, line 527 def binding_prop?(node) node.significant?(:binding) && node.label(:version) != :empty && (!node.significant?(:binding_within) || node.significant?(:multipart_binding)) end
@api private
# File lib/pakyow/presenter/view.rb, line 517 def binding_props(descend: false) each_binding_prop(descend: descend).map(&:itself) end
@api private
# File lib/pakyow/presenter/view.rb, line 522 def binding_scope?(node) node.significant?(:binding) && (node.significant?(:binding_within) || node.significant?(:multipart_binding) || node.label(:version) == :empty) end
@api private
# File lib/pakyow/presenter/view.rb, line 512 def binding_scopes(descend: false) each_binding_scope(descend: descend).map(&:itself) end
Returns a view for the +<body>+ node.
# File lib/pakyow/presenter/view.rb, line 221 def body if body_node = @object.find_first_significant_node(:body) View.from_object(body_node) else nil end end
@api private
# File lib/pakyow/presenter/view.rb, line 442 def channeled_binding_name label(:channeled_binding) end
@api private
# File lib/pakyow/presenter/view.rb, line 568 def channeled_binding_scope?(scope) binding_scopes.select { |node| node.label(:binding) == scope }.any? { |node| node.label(:channel).any? } end
Removes self
's children.
# File lib/pakyow/presenter/view.rb, line 354 def clear tap do @object.clear end end
Finds a component matching name
.
# File lib/pakyow/presenter/view.rb, line 179 def component(name, renderable: false) name = name.to_sym components(renderable: renderable).find { |component| component.object.label(:components).any? { |possible_component| possible_component[:name] == name } } end
Returns all components.
@api private
# File lib/pakyow/presenter/view.rb, line 191 def components(renderable: false) @object.each_significant_node_without_descending_into_type(:component, descend: true).select { |node| !renderable || node.label(:components).any? { |component| component[:renderable] } }.map { |node| View.from_object(node) } end
Returns true if self
is a container.
# File lib/pakyow/presenter/view.rb, line 374 def container? @object.significant?(:container) end
@api private
# File lib/pakyow/presenter/view.rb, line 495 def each_binding(name) return enum_for(:each_binding, name) unless block_given? each_binding_scope do |node| if node.label(:channeled_binding) == name yield node end end each_binding_prop do |node| if (node.significant?(:multipart_binding) && node.label(:binding_prop) == name) || (!node.significant?(:multipart_binding) && node.label(:binding) == name) yield node end end end
@api private
# File lib/pakyow/presenter/view.rb, line 474 def each_binding_prop(descend: false) return enum_for(:each_binding_prop, descend: descend) unless block_given? if (@object.is_a?(StringDoc::Node) || @object.is_a?(StringDoc::MetaNode)) && @object.significant?(:multipart_binding) yield @object else method = if descend :each_significant_node else :each_significant_node_without_descending_into_type end @object.send(method, :binding, descend: descend) do |node| if binding_prop?(node) yield node end end end end
@api private
# File lib/pakyow/presenter/view.rb, line 457 def each_binding_scope(descend: false) return enum_for(:each_binding_scope, descend: descend) unless block_given? method = if descend :each_significant_node else :each_significant_node_without_descending_into_type end @object.send(method, :binding, descend: descend) do |node| if binding_scope?(node) yield node end end end
Finds a view binding by name. When passed more than one value, the view will be traversed through each name. Returns a {VersionedView}.
# File lib/pakyow/presenter/view.rb, line 122 def find(*names) if names.any? named = names.shift.to_sym found = each_binding(named).map(&:itself) result = if names.empty? && !found.empty? # found everything; wrap it up if found[0].is_a?(StringDoc::MetaNode) VersionedView.new(View.from_object(found[0])) else VersionedView.new(View.from_object(StringDoc::MetaNode.new(found))) end elsif !found.empty? && names.count > 0 # descend further View.from_object(found[0]).find(*names) else nil end if result && block_given? yield result end result else nil end end
Finds all view bindings by name, returning an array of {View} objects.
@api private
# File lib/pakyow/presenter/view.rb, line 152 def find_all(named) each_binding(named).map { |node| View.from_object(node) } end
@api private
# File lib/pakyow/presenter/view.rb, line 532 def find_partials(partials, found = []) found.tap do @object.each_significant_node(:partial, descend: true) do |node| if replacement = partials[node.label(:partial)] found << node.label(:partial) replacement.find_partials(partials, found) end end end end
Finds a form with a binding matching name
.
# File lib/pakyow/presenter/view.rb, line 160 def form(name) @object.each_significant_node(:form) do |form_node| return Views::Form.from_object(form_node) if form_node.label(:binding) == name end nil end
Returns true if self
is a form.
# File lib/pakyow/presenter/view.rb, line 386 def form? @object.significant?(:form) end
Returns all forms.
@api private
# File lib/pakyow/presenter/view.rb, line 171 def forms @object.each_significant_node(:form, descend: true).map { |node| Views::Form.from_object(node) } end
Returns a view for the +<head>+ node.
# File lib/pakyow/presenter/view.rb, line 211 def head if head_node = @object.find_first_significant_node(:head) View.from_object(head_node) else nil end end
Safely sets the html value of self
.
# File lib/pakyow/presenter/view.rb, line 362 def html=(html) @object.html = ensure_html_safety(html.to_s) end
Returns all view info when key
is nil
, otherwise returns the value for key
.
# File lib/pakyow/presenter/view.rb, line 201 def info(key = nil) if key.nil? @info else @info.fetch(key, nil) end end
# File lib/pakyow/presenter/view.rb, line 88 def initialize_copy(_) super @info = @info.dup @object = @object.dup if @object.respond_to?(:attributes) self.attributes = @object.attributes else @attributes = nil end end
@api private
# File lib/pakyow/presenter/view.rb, line 544 def mixin(partials) tap do @object.each_significant_node(:partial, descend: true) do |partial_node| if replacement = partials[partial_node.label(:partial)] partial_node.replace(replacement.mixin(partials).object) end end end end
Returns true if self
is a partial.
# File lib/pakyow/presenter/view.rb, line 380 def partial? @object.significant?(:partial) end
@api private
# File lib/pakyow/presenter/view.rb, line 437 def plural_binding_name label(:plural_binding) end
@api private
# File lib/pakyow/presenter/view.rb, line 447 def plural_channeled_binding_name label(:plural_channeled_binding) end
Prepends a view or string to self
.
# File lib/pakyow/presenter/view.rb, line 314 def prepend(view_or_string) tap do @object.prepend(self.class.from_view_or_string(view_or_string).object) end end
Removes self
.
# File lib/pakyow/presenter/view.rb, line 346 def remove tap do @object.remove end end
Replaces self
with a view or string.
# File lib/pakyow/presenter/view.rb, line 338 def replace(view_or_string) tap do @object.replace(self.class.from_view_or_string(view_or_string).object) end end
@api private
# File lib/pakyow/presenter/view.rb, line 432 def singular_binding_name label(:singular_binding) end
@api private
# File lib/pakyow/presenter/view.rb, line 452 def singular_channeled_binding_name label(:singular_channeled_binding) end
@api private
# File lib/pakyow/presenter/view.rb, line 102 def soft_copy instance = self.class.allocate instance.instance_variable_set(:@info, @info.dup) new_object = @object.soft_copy instance.instance_variable_set(:@object, new_object) if new_object.respond_to?(:attributes) instance.attributes = new_object.attributes else instance.instance_variable_set(:@attributes, nil) end instance end
Returns a view for the +<title>+ node.
# File lib/pakyow/presenter/view.rb, line 231 def title if title_node = @object.find_first_significant_node(:title) View.from_object(title_node) else nil end end
Converts self
to html, rendering the view.
# File lib/pakyow/presenter/view.rb, line 418 def to_html @object.to_html end
# File lib/pakyow/presenter/view.rb, line 422 def to_s @object.to_s end
Transforms self
to match structure of object
.
# File lib/pakyow/presenter/view.rb, line 249 def transform(object) tap do if object.nil? || (object.respond_to?(:empty?) && object.empty?) remove else removals = [] each_binding_prop(descend: false) do |binding| binding_name = if binding.significant?(:multipart_binding) binding.label(:binding_prop) else binding.label(:binding) end unless object.present?(binding_name) removals << binding end end removals.each(&:remove) end yield self, object if block_given? end end
Returns the version name for self
.
# File lib/pakyow/presenter/view.rb, line 412 def version (label(:version) || VersionedView::DEFAULT_VERSION).to_sym end
Yields self
.
# File lib/pakyow/presenter/view.rb, line 241 def with tap do yield self end end
Private Instance Methods
# File lib/pakyow/presenter/view.rb, line 578 def bind_value_to_node(value, node) tag = node.tagname unless StringDoc::Node.without_value?(tag) value = String(value) if StringDoc::Node.self_closing?(tag) node.attributes[:value] = ensure_html_safety(value) if node.attributes[:value].nil? else node.html = ensure_html_safety(value) end end end