Class: Pakyow::Presenter::View
- Inherits:
-
Object
- Object
- Pakyow::Presenter::View
- Extended by:
- Forwardable
- Includes:
- Support::SafeStringHelpers
- Defined in:
- lib/pakyow/presenter/view.rb
Overview
Provides an interface for manipulating view templates.
Direct Known Subclasses
Pakyow::Presenter::Views::Form, Pakyow::Presenter::Views::Layout, Pakyow::Presenter::Views::Page, Pakyow::Presenter::Views::Partial
Constant Summary collapse
- INFO_MERGER =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Thanks Dan! stackoverflow.com/a/30225093
proc { |_, v1, v2| Support::IndifferentHash === v1 && Support::IndifferentHash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
Instance Attribute Summary collapse
-
#logical_path ⇒ Object
readonly
The logical path to the view template.
-
#object ⇒ Object
private
The object responsible for transforming and rendering the underlying document or node.
Class Method Summary collapse
-
.from_object(object) ⇒ Object
Creates a view wrapping an object.
- .from_view_or_string(view_or_string) ⇒ Object private
-
.load(path, content: nil) ⇒ Object
Creates a view from a file.
Instance Method Summary collapse
-
#==(other) ⇒ Object
Returns true if
self
equalsother
. - #add_info(*infos) ⇒ Object private
-
#after(view_or_string) ⇒ Object
Inserts a view or string after
self
. -
#append(view_or_string) ⇒ Object
Appends a view or string to
self
. -
#attributes ⇒ Object
(also: #attrs)
Returns attributes object for
self
. -
#attributes=(attributes) ⇒ Object
(also: #attrs=)
Wraps
attributes
in a Attributes instance. -
#before(view_or_string) ⇒ Object
Inserts a view or string before
self
. -
#bind(object) ⇒ Object
Binds a single object.
-
#binding? ⇒ Boolean
Returns true if
self
is a binding. - #binding_name ⇒ Object private
- #binding_prop?(node) ⇒ Boolean private
- #binding_props(descend: false) ⇒ Object private
- #binding_scope?(node) ⇒ Boolean private
- #binding_scopes(descend: false) ⇒ Object private
-
#body ⇒ Object
Returns a view for the <body> node.
- #channeled_binding_name ⇒ Object private
- #channeled_binding_scope?(scope) ⇒ Boolean private
-
#clear ⇒ Object
Removes
self
‘s children. -
#component(name, renderable: false) ⇒ Object
Finds a component matching
name
. -
#components(renderable: false) ⇒ Object
private
Returns all components.
-
#container? ⇒ Boolean
Returns true if
self
is a container. - #each_binding(name) ⇒ Object private
- #each_binding_prop(descend: false) ⇒ Object private
- #each_binding_scope(descend: false) ⇒ Object private
-
#find(*names) ⇒ Object
Finds a view binding by name.
-
#find_all(named) ⇒ Object
private
Finds all view bindings by name, returning an array of View objects.
- #find_partials(partials, found = []) ⇒ Object private
-
#form(name) ⇒ Object
Finds a form with a binding matching
name
. -
#form? ⇒ Boolean
Returns true if
self
is a form. -
#forms ⇒ Object
private
Returns all forms.
-
#head ⇒ Object
Returns a view for the <head> node.
-
#html=(html) ⇒ Object
Safely sets the html value of
self
. -
#info(key = nil) ⇒ Object
Returns all view info when
key
isnil
, otherwise returns the value forkey
. -
#initialize(html, info: {}, logical_path: nil) ⇒ View
constructor
Creates a view with
html
. - #initialize_copy(_) ⇒ Object
- #mixin(partials) ⇒ Object private
-
#partial? ⇒ Boolean
Returns true if
self
is a partial. - #plural_binding_name ⇒ Object private
- #plural_channeled_binding_name ⇒ Object private
-
#prepend(view_or_string) ⇒ Object
Prepends a view or string to
self
. -
#remove ⇒ Object
Removes
self
. -
#replace(view_or_string) ⇒ Object
Replaces
self
with a view or string. - #singular_binding_name ⇒ Object private
- #singular_channeled_binding_name ⇒ Object private
- #soft_copy ⇒ Object private
-
#title ⇒ Object
Returns a view for the <title> node.
-
#to_html ⇒ Object
Converts
self
to html, rendering the view. - #to_s ⇒ Object
-
#transform(object) ⇒ Object
Transforms
self
to match structure ofobject
. -
#version ⇒ Object
Returns the version name for
self
. -
#with ⇒ Object
Yields
self
.
Constructor Details
#initialize(html, info: {}, logical_path: nil) ⇒ View
Creates a view with html
.
77 78 79 80 81 82 83 84 85 86 |
# 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 |
Instance Attribute Details
#logical_path ⇒ Object (readonly)
The logical path to the view template.
73 74 75 |
# File 'lib/pakyow/presenter/view.rb', line 73 def logical_path @logical_path end |
#object ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The object responsible for transforming and rendering the underlying document or node.
69 70 71 |
# File 'lib/pakyow/presenter/view.rb', line 69 def object @object end |
Class Method Details
.from_object(object) ⇒ Object
Creates a view wrapping an object.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# 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 |
.from_view_or_string(view_or_string) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
47 48 49 50 51 52 53 54 |
# 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 |
.load(path, content: nil) ⇒ Object
Creates a view from a file.
20 21 22 |
# File 'lib/pakyow/presenter/view.rb', line 20 def load(path, content: nil) new(content || File.read(path)) end |
Instance Method Details
#==(other) ⇒ Object
Returns true if self
equals other
.
392 393 394 |
# File 'lib/pakyow/presenter/view.rb', line 392 def ==(other) other.is_a?(self.class) && @object == other.object end |
#add_info(*infos) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
559 560 561 562 563 564 565 |
# 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 |
#after(view_or_string) ⇒ Object
Inserts a view or string after self
.
322 323 324 325 326 |
# 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 |
#append(view_or_string) ⇒ Object
Appends a view or string to self
.
306 307 308 309 310 |
# 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 |
#attributes ⇒ Object Also known as: attrs
Returns attributes object for self
.
398 399 400 |
# File 'lib/pakyow/presenter/view.rb', line 398 def attributes @attributes end |
#attributes=(attributes) ⇒ Object Also known as: attrs=
Wraps attributes
in a Attributes instance.
405 406 407 |
# File 'lib/pakyow/presenter/view.rb', line 405 def attributes=(attributes) @attributes = Attributes.new(attributes) end |
#before(view_or_string) ⇒ Object
Inserts a view or string before self
.
330 331 332 333 334 |
# 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 |
#bind(object) ⇒ Object
Binds a single object.
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# 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 |
#binding? ⇒ Boolean
Returns true if self
is a binding.
368 369 370 |
# File 'lib/pakyow/presenter/view.rb', line 368 def binding? @object.significant?(:binding) end |
#binding_name ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
427 428 429 |
# File 'lib/pakyow/presenter/view.rb', line 427 def binding_name label(:binding) end |
#binding_prop?(node) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
527 528 529 |
# 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 |
#binding_props(descend: false) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
517 518 519 |
# File 'lib/pakyow/presenter/view.rb', line 517 def binding_props(descend: false) each_binding_prop(descend: descend).map(&:itself) end |
#binding_scope?(node) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
522 523 524 |
# 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 |
#binding_scopes(descend: false) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
512 513 514 |
# File 'lib/pakyow/presenter/view.rb', line 512 def binding_scopes(descend: false) each_binding_scope(descend: descend).map(&:itself) end |
#body ⇒ Object
Returns a view for the <body> node.
221 222 223 224 225 226 227 |
# 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 |
#channeled_binding_name ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
442 443 444 |
# File 'lib/pakyow/presenter/view.rb', line 442 def channeled_binding_name label(:channeled_binding) end |
#channeled_binding_scope?(scope) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
568 569 570 571 572 573 574 |
# 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 |
#clear ⇒ Object
Removes self
‘s children.
354 355 356 357 358 |
# File 'lib/pakyow/presenter/view.rb', line 354 def clear tap do @object.clear end end |
#component(name, renderable: false) ⇒ Object
Finds a component matching name
.
179 180 181 182 183 184 185 186 |
# 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 |
#components(renderable: false) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns all components.
191 192 193 194 195 196 197 |
# 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 |
#container? ⇒ Boolean
Returns true if self
is a container.
374 375 376 |
# File 'lib/pakyow/presenter/view.rb', line 374 def container? @object.significant?(:container) end |
#each_binding(name) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
# 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 |
#each_binding_prop(descend: false) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
# 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 |
#each_binding_scope(descend: false) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
# 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 |
#find(*names) ⇒ Object
Finds a view binding by name. When passed more than one value, the view will be traversed through each name. Returns a Pakyow::Presenter::VersionedView.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# 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 |
#find_all(named) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Finds all view bindings by name, returning an array of Pakyow::Presenter::View objects.
152 153 154 155 156 |
# File 'lib/pakyow/presenter/view.rb', line 152 def find_all(named) each_binding(named).map { |node| View.from_object(node) } end |
#find_partials(partials, found = []) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
532 533 534 535 536 537 538 539 540 541 |
# 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 |
#form(name) ⇒ Object
Finds a form with a binding matching name
.
160 161 162 163 164 165 166 |
# 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 |
#form? ⇒ Boolean
Returns true if self
is a form.
386 387 388 |
# File 'lib/pakyow/presenter/view.rb', line 386 def form? @object.significant?(:form) end |
#forms ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns all forms.
171 172 173 174 175 |
# 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 |
#head ⇒ Object
Returns a view for the <head> node.
211 212 213 214 215 216 217 |
# 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 |
#html=(html) ⇒ Object
Safely sets the html value of self
.
362 363 364 |
# File 'lib/pakyow/presenter/view.rb', line 362 def html=(html) @object.html = ensure_html_safety(html.to_s) end |
#info(key = nil) ⇒ Object
Returns all view info when key
is nil
, otherwise returns the value for key
.
201 202 203 204 205 206 207 |
# File 'lib/pakyow/presenter/view.rb', line 201 def info(key = nil) if key.nil? @info else @info.fetch(key, nil) end end |
#initialize_copy(_) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 |
# 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 |
#mixin(partials) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
544 545 546 547 548 549 550 551 552 |
# 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 |
#partial? ⇒ Boolean
Returns true if self
is a partial.
380 381 382 |
# File 'lib/pakyow/presenter/view.rb', line 380 def partial? @object.significant?(:partial) end |
#plural_binding_name ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
437 438 439 |
# File 'lib/pakyow/presenter/view.rb', line 437 def plural_binding_name label(:plural_binding) end |
#plural_channeled_binding_name ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
447 448 449 |
# File 'lib/pakyow/presenter/view.rb', line 447 def plural_channeled_binding_name label(:plural_channeled_binding) end |
#prepend(view_or_string) ⇒ Object
Prepends a view or string to self
.
314 315 316 317 318 |
# 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 |
#remove ⇒ Object
Removes self
.
346 347 348 349 350 |
# File 'lib/pakyow/presenter/view.rb', line 346 def remove tap do @object.remove end end |
#replace(view_or_string) ⇒ Object
Replaces self
with a view or string.
338 339 340 341 342 |
# 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 |
#singular_binding_name ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
432 433 434 |
# File 'lib/pakyow/presenter/view.rb', line 432 def singular_binding_name label(:singular_binding) end |
#singular_channeled_binding_name ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
452 453 454 |
# File 'lib/pakyow/presenter/view.rb', line 452 def singular_channeled_binding_name label(:singular_channeled_binding) end |
#soft_copy ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# 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 |
#title ⇒ Object
Returns a view for the <title> node.
231 232 233 234 235 236 237 |
# 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 |
#to_html ⇒ Object
Converts self
to html, rendering the view.
418 419 420 |
# File 'lib/pakyow/presenter/view.rb', line 418 def to_html @object.to_html end |
#to_s ⇒ Object
422 423 424 |
# File 'lib/pakyow/presenter/view.rb', line 422 def to_s @object.to_s end |
#transform(object) ⇒ Object
Transforms self
to match structure of object
.
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
# 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 |
#version ⇒ Object
Returns the version name for self
.
412 413 414 |
# File 'lib/pakyow/presenter/view.rb', line 412 def version (label(:version) || VersionedView::DEFAULT_VERSION).to_sym end |
#with ⇒ Object
Yields self
.
241 242 243 244 245 |
# File 'lib/pakyow/presenter/view.rb', line 241 def with tap do yield self end end |