Class: Inversion::Parser::State

Inherits:
Object
  • Object
show all
Extended by:
Loggability
Defined in:
lib/inversion/parser.rb

Overview

Parse state object class. State objects keep track of where in the parse tree new nodes should be appended, and manages inclusion.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(template, options = {}) ⇒ State

Create a new State object



174
175
176
177
178
179
180
# File 'lib/inversion/parser.rb', line 174

def initialize( template, options={} )
	@template      = template
	@options       = options.dup
	@tree          = []
	@node_stack    = [ @tree ]
	@include_stack = []
end

Instance Attribute Details

#include_stackObject (readonly)

The stack of templates that have been loaded for this state; for loop detection.



204
205
206
# File 'lib/inversion/parser.rb', line 204

def include_stack
  @include_stack
end

#node_stackObject (readonly)

The stack of containers



207
208
209
# File 'lib/inversion/parser.rb', line 207

def node_stack
  @node_stack
end

#optionsObject (readonly)

The parse options in effect for this parse state



198
199
200
# File 'lib/inversion/parser.rb', line 198

def options
  @options
end

#templateObject

The template object for this parser state



201
202
203
# File 'lib/inversion/parser.rb', line 201

def template
  @template
end

Instance Method Details

#<<(node) ⇒ Object

Append operator: add nodes to the correct part of the parse tree.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/inversion/parser.rb', line 211

def <<( node )
	# self.log.debug "Appending %p" % [ node ]

	node.before_appending( self )
	self.node_stack.last << node

	if node.is_container?
		# Containers get pushed onto the stack so they get appended to
		self.node_stack.push( node )
	else
		# Container nodes' #after_appending gets called in #pop
		node.after_appending( self )
	end

	return self
rescue Inversion::ParseError => err
	raise err, "%s at %s" % [ err.message, node.location ]
end

#append_tree(newtree) ⇒ Object

Append another Array of nodes onto this state’s node tree.



232
233
234
235
236
# File 'lib/inversion/parser.rb', line 232

def append_tree( newtree )
	newtree.each do |node|
		self.node_stack.last << node
	end
end

#clear_nodesObject

Clear any parsed nodes from the state, leaving the options and include_stack intact.



279
280
281
282
# File 'lib/inversion/parser.rb', line 279

def clear_nodes
	@tree       = []
	@node_stack = [ @tree ]
end

#current_nodeObject

Return the node that is currently being appended to, or nil if there aren’t any opened container nodes.



273
274
275
# File 'lib/inversion/parser.rb', line 273

def current_node
	return self.node_stack.last
end

#initialize_copy(original) ⇒ Object

Copy constructor – duplicate inner structures.



184
185
186
187
188
189
190
# File 'lib/inversion/parser.rb', line 184

def initialize_copy( original )
	@template      = original.template
	@options       = original.options.dup
	@tree          = @tree.map( &:dup )
	@node_stack    = [ @tree ]
	@include_stack = original.include_stack.dup
end

#is_well_formed?Boolean Also known as: well_formed?

Check to see if all open tags have been closed.

Returns:

  • (Boolean)


250
251
252
# File 'lib/inversion/parser.rb', line 250

def is_well_formed?
	return self.node_stack.length == 1
end

#load_subtemplate(path) ⇒ Object

Load a subtemplate from the specified path, checking for recursive-dependency.



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/inversion/parser.rb', line 286

def load_subtemplate( path )
	if self.include_stack.include?( path )
		stack_desc = ( self.include_stack + [path] ).join( ' --> ' )
		msg = "Recursive load of %p detected: from %s" % [ path, stack_desc ]

		self.log.error( msg )
		raise Inversion::StackError, msg
	end

	# self.log.debug "Include stack is: %p" % [ self.include_stack ]

	substate = self.dup
	substate.clear_nodes
	substate.include_stack.push( path )

	return Inversion::Template.load( path, substate, self.options )
end

#popObject

Pop one level off of the node stack and return it.



257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/inversion/parser.rb', line 257

def pop
	closed_node = self.node_stack.pop

	# If there's nothing on the node stack, we've popped the top-level
	# Array, which means there wasn't an opening container.
	raise Inversion::ParseError, "unbalanced end: no open tag" if
		self.node_stack.empty?

	closed_node.after_appending( self )

	return closed_node
end

#treeObject

Returns the tree if it’s well formed.



240
241
242
243
244
245
246
# File 'lib/inversion/parser.rb', line 240

def tree
	unless self.is_well_formed?
		raise Inversion::ParseError, "Unclosed container tag: %s, from %s" %
			[ self.node_stack.last.tagname, self.node_stack.last.location ]
	end
	return @tree
end