Class: Utopia::Content::Document

Inherits:
Response
  • Object
show all
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.

Defined Under Namespace

Classes: State

Instance Attribute Summary collapse

Attributes inherited from Response

#body, #headers, #status

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Response

#cache!, #content_type=, #do_not_cache!, #lookup, #to_a

Constructor Details

#initialize(request, attributes = {}) ⇒ Document

Returns a new instance of Document.



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/utopia/content/document.rb', line 46

def initialize(request, attributes = {})
	@request = request
	
	@attributes = attributes
	
	@first = nil
	@current = nil
	@end_tags = []
	
	super()
end

Instance Attribute Details

#attributesObject (readonly)

Per-document global attributes.



89
90
91
# File 'lib/utopia/content/document.rb', line 89

def attributes
  @attributes
end

#currentObject (readonly)

The current state, represents a list from outer to inner most tag by traversing Utopia::Content::Document::State#parent. At any point in parsing markup, this is a list of the inner most tag, then the next outer tag, etc.



94
95
96
# File 'lib/utopia/content/document.rb', line 94

def current
  @current
end

#end_tagsObject (readonly)

End tags represents a list of execution order. This is the order that end tags have appeared when evaluating nodes.



102
103
104
# File 'lib/utopia/content/document.rb', line 102

def end_tags
  @end_tags
end

#firstObject (readonly)

The first State generated by rendering this document. It contains useful information regarding the node and uri used to access the resource.



98
99
100
# File 'lib/utopia/content/document.rb', line 98

def first
  @first
end

#requestObject (readonly)

The Rack::Request for this document.



86
87
88
# File 'lib/utopia/content/document.rb', line 86

def request
  @request
end

Class Method Details

.render(node, request, attributes) ⇒ Object



42
43
44
# File 'lib/utopia/content/document.rb', line 42

def self.render(node, request, attributes)
	self.new(request, attributes).render!(node, attributes)
end

Instance Method Details

#[](key) ⇒ Object



58
59
60
# File 'lib/utopia/content/document.rb', line 58

def [] key
	@attributes[key]
end

#[]=(key, value) ⇒ Object



62
63
64
# File 'lib/utopia/content/document.rb', line 62

def []= key, value
	@attributes[key] = value
end

#contentObject

The content of the node



219
220
221
# File 'lib/utopia/content/document.rb', line 219

def content
	@end_tags.last.content
end

#controllerObject

A helper method for accessing controller variables from view:



73
74
75
# File 'lib/utopia/content/document.rb', line 73

def controller
	@controller ||= Utopia::Controller[request]
end

#localizationObject



77
78
79
# File 'lib/utopia/content/document.rb', line 77

def localization
	@localization ||= Utopia::Localization[request]
end

#lookup_node(path) ⇒ Node

Lookup a node with the given path relative to the current node.

Returns:

  • (Node)

    The node if could be found.



212
213
214
215
216
# File 'lib/utopia/content/document.rb', line 212

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.

Returns:

  • (Node)

    The node for the given tag.



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/utopia/content/document.rb', line 192

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

#parentObject



223
224
225
# File 'lib/utopia/content/document.rb', line 223

def parent
	@end_tags[-2]
end

#parse_markup(markup) ⇒ Object



81
82
83
# File 'lib/utopia/content/document.rb', line 81

def parse_markup(markup)
	MarkupParser.parse(markup, self)
end

#render!(node, attributes) ⇒ Object



66
67
68
69
70
# File 'lib/utopia/content/document.rb', line 66

def render!(node, attributes)
	@body << render_node(node, attributes)
	
	return self
end

#render_node(node, attributes = {}) ⇒ Object



180
181
182
183
184
185
186
187
188
# File 'lib/utopia/content/document.rb', line 180

def render_node(node, attributes = {})
	@current = State.new(@current, nil, node, attributes)
	
	# 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

#tag(name, attributes = {}) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/utopia/content/document.rb', line 104

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



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/utopia/content/document.rb', line 128

def tag_begin(tag, node = nil)
	node ||= lookup_tag(tag)

	if node
		@current = State.new(@current, tag, node)

		node.tag_begin(self, state) 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



117
118
119
120
121
122
123
124
125
126
# File 'lib/utopia/content/document.rb', line 117

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



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/utopia/content/document.rb', line 156

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



152
153
154
# File 'lib/utopia/content/document.rb', line 152

def text(string)
	@current.text(string)
end

#write(string) ⇒ Object Also known as: cdata



146
147
148
# File 'lib/utopia/content/document.rb', line 146

def write(string)
	@current.write(string)
end