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.



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

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.



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

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.



92
93
94
# File 'lib/utopia/content/document.rb', line 92

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.



100
101
102
# File 'lib/utopia/content/document.rb', line 100

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.



96
97
98
# File 'lib/utopia/content/document.rb', line 96

def first
  @first
end

#requestObject (readonly)

The Rack::Request for this document.



84
85
86
# File 'lib/utopia/content/document.rb', line 84

def request
  @request
end

Class Method Details

.render(node, request, attributes) ⇒ Object



40
41
42
# File 'lib/utopia/content/document.rb', line 40

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

Instance Method Details

#[](key) ⇒ Object



56
57
58
# File 'lib/utopia/content/document.rb', line 56

def [] key
	@attributes[key]
end

#[]=(key, value) ⇒ Object



60
61
62
# File 'lib/utopia/content/document.rb', line 60

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

#contentObject

The content of the node



215
216
217
# File 'lib/utopia/content/document.rb', line 215

def content
	@end_tags.last.content
end

#controllerObject

A helper method for accessing controller variables from view:



71
72
73
# File 'lib/utopia/content/document.rb', line 71

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

#localizationObject



75
76
77
# File 'lib/utopia/content/document.rb', line 75

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.



210
211
212
# File 'lib/utopia/content/document.rb', line 210

def lookup_node(path)
	@current.node.lookup_node(path)
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.



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

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



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

def parent
	@end_tags[-2]
end

#parse_markup(markup) ⇒ Object



79
80
81
# File 'lib/utopia/content/document.rb', line 79

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

#render!(node, attributes) ⇒ Object



64
65
66
67
68
# File 'lib/utopia/content/document.rb', line 64

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

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



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

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



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

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



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

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



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

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



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

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



150
151
152
# File 'lib/utopia/content/document.rb', line 150

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

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



144
145
146
# File 'lib/utopia/content/document.rb', line 144

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