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