Class: Utopia::Content::Document
- Defined in:
- lib/utopia/content/document.rb
Overview
A single request through content middleware. We use a struct to hide instance varibles since we instance_exec within this context.
Constant Summary
Constants included from Response
Response::CONTENT_TYPE, Response::LOCATION, Response::NotFound
Instance Attribute Summary collapse
-
#attributes ⇒ Object
readonly
Per-document global attributes.
-
#current ⇒ Object
readonly
The current state, represents a list from outer to inner most tag by traversing State#parent.
-
#end_tags ⇒ Object
readonly
End tags represents a list of execution order.
-
#first ⇒ Object
readonly
The first State generated by rendering this document.
-
#request ⇒ Object
readonly
The request for this document.
Class Method Summary collapse
-
.render(node, request, attributes, localization: request&.localization) ⇒ Object
Render a content node into a new document.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Fetch a document-global attribute.
-
#[]=(key, value) ⇒ Object
Assign a document-global attribute.
-
#base_uri(relative_to = self.current_base_uri_path) ⇒ Object
Compute the relative path from the curent base uri (e.g. the node being rendered) to the request uri.
-
#content ⇒ Object
The content of the node.
-
#controller ⇒ Object
A helper method for accessing controller variables from view:.
-
#initialize(request, attributes = {}, localization: request&.localization) ⇒ Document
constructor
Initialize a document for a protocol request.
-
#localization ⇒ Object
Return the selected localization preferences for this document.
-
#lookup_node(path) ⇒ Node
Lookup a node with the given path relative to the current node.
-
#lookup_tag(tag) ⇒ Node
Maps a tag to a node instance by asking the current node to lookup the tag name.
-
#parent ⇒ Object
Return the enclosing rendering state.
-
#parse_markup(markup) ⇒ Object
Parse markup into this document.
-
#render!(node, attributes) ⇒ Object
Render.
-
#render_node(node, attributes = {}) ⇒ Object
Render a content node within the current builder state.
- #request_path ⇒ Object
-
#tag(name, attributes = {}) ⇒ Object
Render a complete or block-delimited tag.
-
#tag_begin(tag, node = nil) ⇒ Object
Begin a tag through a matching content node or the current builder.
-
#tag_complete(tag, node = nil) ⇒ Object
Render a complete tag through a matching content node or the current builder.
-
#tag_end(tag = nil) ⇒ Object
Complete the current content node or close a nested markup tag.
-
#text(string) ⇒ Object
Process text content.
-
#write(string) ⇒ Object
(also: #cdata)
Append raw content to the current builder.
Methods included from Response
[], html, redirect, text, wrap
Constructor Details
#initialize(request, attributes = {}, localization: request&.localization) ⇒ Document
Initialize a document for a protocol request.
43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/utopia/content/document.rb', line 43 def initialize(request, attributes = {}, localization: request&.localization) @request = request @localization = localization @attributes = attributes @first = nil @current = nil @end_tags = [] super() end |
Instance Attribute Details
#attributes ⇒ Object (readonly)
Per-document global attributes.
124 125 126 |
# File 'lib/utopia/content/document.rb', line 124 def attributes @attributes end |
#current ⇒ Object (readonly)
The current state, represents a list from outer to inner most tag by traversing State#parent. At any point in parsing markup, this is a list of the inner most tag, then the next outer tag, etc.
129 130 131 |
# File 'lib/utopia/content/document.rb', line 129 def current @current end |
#end_tags ⇒ Object (readonly)
End tags represents a list of execution order. This is the order that end tags have appeared when evaluating nodes.
137 138 139 |
# File 'lib/utopia/content/document.rb', line 137 def @end_tags end |
#first ⇒ Object (readonly)
The first State generated by rendering this document. It contains useful information regarding the node and uri used to access the resource.
133 134 135 |
# File 'lib/utopia/content/document.rb', line 133 def first @first end |
#request ⇒ Object (readonly)
The request for this document.
121 122 123 |
# File 'lib/utopia/content/document.rb', line 121 def request @request end |
Class Method Details
.render(node, request, attributes, localization: request&.localization) ⇒ Object
Render a content node into a new document.
35 36 37 |
# File 'lib/utopia/content/document.rb', line 35 def self.render(node, request, attributes, localization: request&.localization) self.new(request, attributes, localization: localization).render!(node, attributes) end |
Instance Method Details
#[](key) ⇒ Object
Fetch a document-global attribute.
80 81 82 |
# File 'lib/utopia/content/document.rb', line 80 def [] key @attributes[key] end |
#[]=(key, value) ⇒ Object
Assign a document-global attribute.
88 89 90 |
# File 'lib/utopia/content/document.rb', line 88 def []= key, value @attributes[key] = value end |
#base_uri(relative_to = self.current_base_uri_path) ⇒ Object
Compute the relative path from the curent base uri (e.g. the node being rendered) to the request uri. This path can be used to ensure resources are loaded relative to a given path.
| Relative To | Request Path | Base URI |
|---|---|---|
| "/page" | "/index" | "" |
| "/blog/entry" | "/blog/2025/05/my-cat" | "../.." |
73 74 75 |
# File 'lib/utopia/content/document.rb', line 73 def base_uri(relative_to = self.current_base_uri_path) Path[relative_to].dirname.shortest_path(request_path) end |
#content ⇒ Object
The content of the node
280 281 282 |
# File 'lib/utopia/content/document.rb', line 280 def content @end_tags.last.content end |
#controller ⇒ Object
A helper method for accessing controller variables from view:
103 104 105 |
# File 'lib/utopia/content/document.rb', line 103 def controller @controller ||= Utopia::Controller[request] end |
#localization ⇒ Object
Return the selected localization preferences for this document.
109 110 111 |
# File 'lib/utopia/content/document.rb', line 109 def localization @localization end |
#lookup_node(path) ⇒ Node
Lookup a node with the given path relative to the current node.
273 274 275 276 277 |
# File 'lib/utopia/content/document.rb', line 273 def lookup_node(path) @end_tags.reverse_each do |state| return state.node.lookup_node(path) if state.node.respond_to?(:lookup_node) end end |
#lookup_tag(tag) ⇒ Node
Maps a tag to a node instance by asking the current node to lookup the tag name. This function is called for each tag and thus heavily affects performance.
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/utopia/content/document.rb', line 253 def lookup_tag(tag) # result = tag # # # This loop works from inner to outer tags, and updates the tag we are currently searching for based on any overrides: # @begin_tags.reverse_each do |state| # result = state.lookup(result) # # return result if result.is_a?(Node) # end # This loop looks up a tag by asking the most embedded node to look it up based on tag name. This almost always only evaluates the top state: @end_tags.reverse_each do |state| return state.node.lookup_tag(tag) if state.node.respond_to?(:lookup_tag) end return nil end |
#parent ⇒ Object
Return the enclosing rendering state.
286 287 288 |
# File 'lib/utopia/content/document.rb', line 286 def parent @end_tags[-2] end |
#parse_markup(markup) ⇒ Object
Parse markup into this document.
116 117 118 |
# File 'lib/utopia/content/document.rb', line 116 def parse_markup(markup) MarkupParser.parse(markup, self) end |
#render!(node, attributes) ⇒ Object
Render.
96 97 98 99 100 |
# File 'lib/utopia/content/document.rb', line 96 def render!(node, attributes) @body << render_node(node, attributes) return self end |
#render_node(node, attributes = {}) ⇒ Object
Render a content node within the current builder state.
241 242 243 244 245 246 247 248 249 |
# File 'lib/utopia/content/document.rb', line 241 def render_node(node, attributes = {}) @current = Builder.new(@current, nil, node, attributes, indent: false) # We keep track of the first thing rendered by this document. @first ||= @current # This returns the content of rendering the tag: return tag_end end |
#request_path ⇒ Object
57 58 59 |
# File 'lib/utopia/content/document.rb', line 57 def request_path request.request_path end |
#tag(name, attributes = {}) ⇒ Object
Render a complete or block-delimited tag.
144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/utopia/content/document.rb', line 144 def tag(name, attributes = {}) # If we provide a block which can give inner data, we are not self-closing. tag = Tag.new(name, !block_given?, attributes) if block_given? node = tag_begin(tag) yield node tag_end(tag) else tag_complete(tag, node) end end |
#tag_begin(tag, node = nil) ⇒ Object
Begin a tag through a matching content node or the current builder.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/utopia/content/document.rb', line 176 def tag_begin(tag, node = nil) node ||= lookup_tag(tag) if node @current = Builder.new(@current, tag, node, tag.to_hash, indent: false) node.tag_begin(self, @current) if node.respond_to?(:tag_begin) return node end # raise ArgumentError.new("tag_begin: #{tag} is tag.self_closed?") if tag.self_closed? @current.tag_begin(tag) return nil end |
#tag_complete(tag, node = nil) ⇒ Object
Render a complete tag through a matching content node or the current builder.
161 162 163 164 165 166 167 168 169 170 |
# File 'lib/utopia/content/document.rb', line 161 def tag_complete(tag, node = nil) node ||= lookup_tag(tag) if node tag_begin(tag, node) tag_end(tag) else @current.tag_complete(tag) end end |
#tag_end(tag = nil) ⇒ Object
Complete the current content node or close a nested markup tag.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/utopia/content/document.rb', line 213 def tag_end(tag = nil) # Determine if the current state contains tags that need to be completed, or if the state itself is finished. if @current.empty? if node = @current.node node.tag_end(self, @current) if node.respond_to?(:tag_end) end @end_tags << @current buffer = @current.call(self) @current = @current.parent @end_tags.pop @current.write(buffer) if @current return buffer else # raise ArgumentError.new("tag_begin: #{tag} is tag.self_closed?") if tag.self_closed? @current.tag_end(tag) end return nil end |
#text(string) ⇒ Object
Process text content.
206 207 208 |
# File 'lib/utopia/content/document.rb', line 206 def text(string) @current.text(string) end |
#write(string) ⇒ Object Also known as: cdata
Append raw content to the current builder.
197 198 199 |
# File 'lib/utopia/content/document.rb', line 197 def write(string) @current.write(string) end |