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



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

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.



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

def include_stack
  @include_stack
end

#node_stackObject (readonly)

The stack of containers



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

def node_stack
  @node_stack
end

#optionsObject (readonly)

The parse options in effect for this parse state



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

def options
  @options
end

#templateObject

The template object for this parser state



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

def template
  @template
end

Instance Method Details

#<<(node) ⇒ Object

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



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

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.



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

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.



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

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.



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

def current_node
	return self.node_stack.last
end

#initialize_copy(original) ⇒ Object

Copy constructor – duplicate inner structures.



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

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)


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

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.



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

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.



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

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.



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

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