Class: Undies::Template
- Inherits:
-
Object
- Object
- Undies::Template
- Defined in:
- lib/undies/template.rb
Constant Summary collapse
- ESCAPE_HTML =
Ripped from Rack v1.3.0 ======================================
> ripped b/c I don’t want a dependency on Rack for just this
{ "&" => "&", "<" => "<", ">" => ">", "'" => "'", '"' => """, "/" => "/" }
- ESCAPE_HTML_PATTERN =
Regexp.union(*ESCAPE_HTML.keys)
- ELEM_METH_REGEX =
Element proxy methods (‘_<element>”) ========================
/^_(.+)$/
Class Method Summary collapse
-
.escape_html(string) ⇒ Object
Escape ampersands, brackets and quotes to their HTML/XML entities.
- .flush(template) ⇒ Object
- .node_stack(template) ⇒ Object
-
.source_stack(template) ⇒ Object
have as many methods on the class level as possible to keep from polluting the public instance methods, the instance scope, and to maximize the effectiveness of the Template#method_missing logic.
Instance Method Summary collapse
-
#_(data = "", mode = :inline) ⇒ Object
Add a text node (data escaped) to the nodes of the current node.
-
#__(data = "", mode = :inline) ⇒ Object
Add a text node with the data un-escaped.
-
#__attrs(attrs_hash = {}) ⇒ Object
call this to modify element attrs inside a build block.
-
#__flush ⇒ Object
call this to manually flush a template.
-
#__partial(source, data = {}) ⇒ Object
call this to render partial source embedded in a template partial source is rendered with its own scope/data but shares its parent template’s output object.
-
#__pop ⇒ Object
call this method to manually pop the current scoped node from the node stack - flushes the cache - changes the context of template method calls to operate on the parent node.
-
#__push ⇒ Object
call this method to manually push the currently cached node onto the node stack - implicitly flushes the cache - changes the context of template method calls to operate on that node.
-
#__yield ⇒ Object
call this to render template source use this method in layouts to insert a layout’s content source.
-
#element(*args, &build) ⇒ Object
(also: #tag)
Add an element to the node stack.
-
#initialize(*args) ⇒ Template
constructor
end Rip from Rack v1.3.0 =====================================.
- #method_missing(meth, *args, &block) ⇒ Object
- #respond_to?(*args) ⇒ Boolean
Constructor Details
#initialize(*args) ⇒ Template
end Rip from Rack v1.3.0 =====================================
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/undies/template.rb', line 44 def initialize(*args) # setup a node stack with the given output obj output = if args.last.kind_of?(NodeStack) || args.last.kind_of?(Output) args.pop else raise ArgumentError, "please provide an Output object" end @_undies_node_stack = NodeStack.create(output) # apply any given data to template scope data = args.last.kind_of?(::Hash) ? args.pop : {} if (data.keys.map(&:to_s) & self.public_methods.map(&:to_s)).size > 0 raise ArgumentError, "data conflicts with template public methods." end = class << self; self; end data.each {|key, value| .class_eval { define_method(key){value} }} # setup a source stack with the given source source = args.last.kind_of?(Source) ? args.pop : Source.new(Proc.new {}) @_undies_source_stack = SourceStack.new(source) # yield to recursivley render the source stack self.__yield # flush any elements that need to be built self.class.flush(self) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth, *args, &block) ⇒ Object
161 162 163 164 165 166 167 |
# File 'lib/undies/template.rb', line 161 def method_missing(meth, *args, &block) if meth.to_s =~ ELEM_METH_REGEX element($1, *args, &block) else super end end |
Class Method Details
.escape_html(string) ⇒ Object
Escape ampersands, brackets and quotes to their HTML/XML entities.
39 40 41 |
# File 'lib/undies/template.rb', line 39 def self.escape_html(string) string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] } end |
.flush(template) ⇒ Object
23 24 25 |
# File 'lib/undies/template.rb', line 23 def self.flush(template) node_stack(template).flush end |
.node_stack(template) ⇒ Object
19 20 21 |
# File 'lib/undies/template.rb', line 19 def self.node_stack(template) template.instance_variable_get("@_undies_node_stack") end |
.source_stack(template) ⇒ Object
have as many methods on the class level as possible to keep from polluting the public instance methods, the instance scope, and to maximize the effectiveness of the Template#method_missing logic
15 16 17 |
# File 'lib/undies/template.rb', line 15 def self.source_stack(template) template.instance_variable_get("@_undies_source_stack") end |
Instance Method Details
#_(data = "", mode = :inline) ⇒ Object
Add a text node (data escaped) to the nodes of the current node
140 141 142 |
# File 'lib/undies/template.rb', line 140 def _(data="", mode=:inline) self.__ self.class.escape_html(data.to_s), mode end |
#__(data = "", mode = :inline) ⇒ Object
Add a text node with the data un-escaped
145 146 147 148 149 |
# File 'lib/undies/template.rb', line 145 def __(data="", mode=:inline) Node.new(data.to_s, mode).tap do |node| self.class.node_stack(self).node(node) end end |
#__attrs(attrs_hash = {}) ⇒ Object
call this to modify element attrs inside a build block. Once content or child elements have been added, any ‘__attr’ directives will be ignored b/c the elements start_tag has already been flushed to the output
76 77 78 79 80 81 82 83 |
# File 'lib/undies/template.rb', line 76 def __attrs(attrs_hash={}) self.class.node_stack(self).current.tap do |node| if node node.class.merge_attrs(node, attrs_hash) node.class.set_start_tag(node) end end end |
#__flush ⇒ Object
call this to manually flush a template
113 114 115 |
# File 'lib/undies/template.rb', line 113 def __flush self.class.flush(self) end |
#__partial(source, data = {}) ⇒ Object
call this to render partial source embedded in a template partial source is rendered with its own scope/data but shares its parent template’s output object
131 132 133 134 135 136 137 |
# File 'lib/undies/template.rb', line 131 def __partial(source, data={}) if source.kind_of?(Source) Undies::Template.new(source, data, self.class.node_stack(self)) else self.__ source.to_s, :partial end end |
#__pop ⇒ Object
call this method to manually pop the current scoped node from the node stack
-
flushes the cache
-
changes the context of template method calls to operate on the parent node
106 107 108 109 110 |
# File 'lib/undies/template.rb', line 106 def __pop ns = self.class.node_stack(self) ns.clear_cached ns.pop end |
#__push ⇒ Object
call this method to manually push the currently cached node onto the node stack
-
implicitly flushes the cache
-
changes the context of template method calls to operate on that node
89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/undies/template.rb', line 89 def __push ns = self.class.node_stack(self) node, ns.cached_node = ns.cached_node, nil if node # add an empty build block to generate a non-closing start tag # and a closing end tag node.class.add_build(node, Proc.new {}) node.class.set_start_tag(node) node.class.set_end_tag(node) ns.push(node) end end |
#__yield ⇒ Object
call this to render template source use this method in layouts to insert a layout’s content source
119 120 121 122 123 124 125 126 |
# File 'lib/undies/template.rb', line 119 def __yield return if self.class.node_stack(self).nil? || (source = self.class.source_stack(self).pop).nil? if source.file? instance_eval(source.data, source.source, 1) else instance_eval(&source.data) end end |
#element(*args, &build) ⇒ Object Also known as: tag
Add an element to the node stack
152 153 154 155 156 |
# File 'lib/undies/template.rb', line 152 def element(*args, &build) Element.new(*args, &build).tap do |element| self.class.node_stack(self).node(element) end end |
#respond_to?(*args) ⇒ Boolean
168 169 170 171 172 173 174 |
# File 'lib/undies/template.rb', line 168 def respond_to?(*args) if args.first.to_s =~ ELEM_METH_REGEX true else super end end |