This is the parser for Inversion templates. It takes template source and returns a tree of Inversion::Template::Node objects (if parsing is successful).
Default values for parser configuration options.
Valid tagends by tagstart
The pattern for matching a tag opening
The pattern for matching a tag.
Create a new Inversion::Parser with the specified config options.
# File lib/inversion/parser.rb, line 41 def initialize( template, options={} ) @template = template @options = DEFAULT_OPTIONS.merge( options ) end
Parse the given source into one or more Inversion::Template::Nodes and return it as an Array.
# File lib/inversion/parser.rb, line 57 def parse( source, inherited_state=nil ) state = nil if inherited_state inherited_state.template = @template state = inherited_state else state = Inversion::Parser::State.new( @template, self.options ) end self.log.debug "Starting parse of template source (%0.2fK, %s)" % [ source.bytesize/1024.0, source.encoding ] last_pos = last_linenum = last_colnum = 0 source.scan( TAG_PATTERN ) do |*| match = Regexp.last_match start_pos, end_pos = match.offset( 0 ) linenum = match.pre_match.count( "\n" ) + 1 colnum = match.pre_match.length - (match.pre_match.rindex("\n") || -1) # Error on <?...?] and vice-versa. unless match[:tagend] == MATCHING_BRACKETS[match[:tagstart]] raise Inversion::ParseError, "malformed tag %p: mismatched start and end brackets at line %d, column %d" % [ match[0], linenum, colnum ] end # Check for nested tags if match[0].index( TAG_OPEN, 2 ) raise Inversion::ParseError, "unclosed or nested tag %p at line %d, column %d" % [ match[0], linenum, colnum ] end self.log.debug " found a tag at offset: %d (%p) (line %d, col %d)" % [ start_pos, abbrevstring(match[0]), linenum, colnum ] # If there were characters between the end of the last match and # the beginning of the tag, create a text node with them unless last_pos == start_pos text = match.pre_match[ last_pos..-1 ] self.log.debug " adding literal text node: %p" % [ abbrevstring(text) ] state << Inversion::Template::TextNode.new( text, last_linenum, last_colnum ) end self.log.debug " creating tag with tagname: %p, body: %p" % [ match[:tagname], match[:body] ] tag = Inversion::Template::Tag.create( match[:tagname], match[:body], linenum, colnum ) if tag.nil? unless state.options[ :ignore_unknown_tags ] raise Inversion::ParseError, "Unknown tag %p at line %d, column %d" % [ match[:tagname], linenum, colnum ] end tag = Inversion::Template::TextNode.new( match[0], linenum, colnum ) end self.log.debug " created tag: %p" % [ tag ] state << tag # Keep offsets for the next match last_pos = end_pos last_linenum = linenum + match[0].count( "\n" ) last_colnum = match[0].length - ( match[0].rindex("\n") || -1 ) end # If there are any characters left over after the last tag remainder = source[ last_pos..-1 ] if remainder && !remainder.empty? self.log.debug "Remainder after last tag: %p" % [ abbrevstring(remainder) ] # Detect unclosed tags if remainder.index( "<?" ) || remainder.index( "[?" ) raise Inversion::ParseError, "unclosed tag after line %d, column %d" % [ last_linenum, last_colnum ] end # Add any remaining text as a text node state << Inversion::Template::TextNode.new( remainder, last_linenum, last_colnum ) end return state.tree end
Generated with the Darkfish Rdoc Generator 2.