The base class for Inversion tags that parse the body section of the tag using a Ruby parser.
It provides a tag_pattern declarative method that is used to
specify a pattern of tokens to match, and a block for handling tag
instances that match the pattern.
class Inversion::Template::MyTag < Inversion::Template::CodeTag # Match a tag that looks like: <?my "string of stuff" ?> tag_pattern 'tstring_beg $(tstring_content) tstring_end' do |tag, match| tag.string = match.string( 1 ) end end
The tokens in the tag_pattern are Ruby token names used by the
parser. If you’re creating your own tag, you can dump the tokens for a
particular snippet using the ‘inversion’ command-line tool that comes with
the gem:
$ inversion tagtokens 'attr.dump! {|thing| thing.length }' ident<"attr"> period<"."> ident<"dump!"> sp<" "> lbrace<"{"> op<"|"> ident<"thing"> op<"|"> sp<" "> ident<"thing"> period<"."> ident<"length"> sp<" "> rbrace<"}">
:todo: Finish the ::tag_pattern docs: placeholders, regex limitations, etc.
the body of the tag
the identifiers in the code contained in the tag
Declare a token_pattern for tag bodies along with a
callback that will be called when a tag matching the pattern
is instantiated.
# File lib/inversion/template/codetag.rb, line 94
def self::tag_pattern( token_pattern, &callback ) #:yield:
pattern = TokenPattern.compile( token_pattern )
@tag_patterns = [] unless defined?( @tag_patterns )
@tag_patterns << [ pattern, callback ]
end
Return the tag patterns for this class, or those of its superclass if it doesn’t override them.
# File lib/inversion/template/codetag.rb, line 86
def self::tag_patterns
return @tag_patterns if defined?( @tag_patterns )
return self.superclass.tag_patterns
end
Initialize a new tag that expects Ruby code in its body. Calls
the tag’s parse_pi_body method with the specified body.
# File lib/inversion/template/codetag.rb, line 107
def initialize( body, linenum=nil, colnum=nil ) # :notnew:
super
@body = body.strip
@identifiers = []
@matched_pattern = self.match_tag_pattern( body )
end
Match the given body against one of the tag’s tag patterns,
calling the block associated with the first one that matches and returning
the matching pattern.
# File lib/inversion/template/codetag.rb, line 139
def match_tag_pattern( body )
self.class.tag_patterns.each do |tp, callback|
if match = tp.match( body.strip )
self.log.debug "Matched tag pattern: %p, match is: %p" % [ tp, match ]
callback.call( self, match )
return tp
end
end
self.log.error "Failed to match %p with %d patterns." %
[ body, self.class.tag_patterns.length ]
valid_patterns = self.class.tag_patterns.map( &:first ).map( &:source ).join( "\n ")
tokenized_src = Ripper.lex( body ).collect do |tok|
self.log.debug " lexed token: #{tok.inspect}"
"%s<%s>" % [ tok[1].to_s[3..-1], tok[2] ]
end.join(' ')
raise Inversion::ParseError, "malformed %s: expected one of:\n %s\ngot:\n %s" %
[ self.tagname, valid_patterns, tokenized_src ]
end