Object
The main template class. Instances of this class are created by parsing template source and combining the resulting node tree with a set of attributes that can be used to populate it when rendered.
Add the mixin to Template
Configure the templating system.
# File lib/inversion/template.rb, line 64 def self::configure( config ) Inversion.log.debug "Merging config %p with current config %p" % [ config, self.config ] self.config = self.config.merge( config ) end
Read a template object from the specified path.
# File lib/inversion/template.rb, line 71 def self::load( path, parsestate=nil, opts={} ) # Shift the options hash over if there isn't a parse state if parsestate.is_a?( Hash ) opts = parsestate parsestate = nil end tmpl = nil path = Pathname( path ) template_paths = Array( self.config[:template_paths] ) + [ Dir.pwd ] # Unrestricted template location. if path.absolute? tmpl = path # Template files searched under paths specified in 'template_paths', then # the current working directory. First match wins. else tmpl = template_paths.collect {|dir| Pathname(dir) + path }.find do |fullpath| fullpath.exist? end raise RuntimeError, "Unable to find template %p within configured paths %p" % [ path.to_s, template_paths ] if tmpl.nil? end # We trust files read from disk source = tmpl.read source.untaint # Load the instance and set the path to the source template = self.new( source, parsestate, opts ) template.source_file = tmpl return template end
Create a new Inversion:Template with the given source.
# File lib/inversion/template.rb, line 111 def initialize( source, parsestate=nil, opts={} ) if parsestate.is_a?( Hash ) self.log.debug "Shifting template options: %p" % [ parsestate ] opts = parsestate parsestate = nil else self.log.debug "Parse state is: %p" % [ parsestate ] end @source = source @parser = Inversion::Parser.new( self, opts ) @node_tree = [] # Parser expects this to always be an Array @init_options = opts @options = nil @attributes = {} @source_file = nil @created_at = Time.now self.parse( source, parsestate ) end
Returns true if the template was loaded from a file and the file's mtime is after the time the template was created.
# File lib/inversion/template.rb, line 166 def changed? return false unless file = self.source_file return ( file.mtime > @created_at ) end
Return a human-readable representation of the template object suitable for debugging.
# File lib/inversion/template.rb, line 195 def inspect return "#<%s:%08x (loaded from %s) attributes: %p, node_tree: %p, options: %p>" % [ self.class.name, self.object_id / 2, self.source_file ? self.source_file : "memory", self.attributes, self.node_tree.map(&:as_comment_body), self.options, ] end
If the template was loaded from a file, reload and reparse it from the same file.
# File lib/inversion/template.rb, line 154 def reload file = self.source_file or raise Inversion::Error, "template was not loaded from a file" self.log.debug "Reloading from %s" % [ file ] source = file.read self.parse( source ) end
Render the template, optionally passing a render state (if, for example, the template is being rendered inside another template).
# File lib/inversion/template.rb, line 174 def render( parentstate=nil, &block ) self.log.info "rendering template 0x%08x" % [ self.object_id/2 ] state = Inversion::RenderState.new( parentstate, self.attributes, self.options, &block ) # Pre-render hook self.walk_tree {|node| node.before_rendering(state) } # self.log.debug " rendering node tree: %p" % [ @node_tree ] self.walk_tree {|node| state << node } # Post-render hook self.walk_tree {|node| node.after_rendering(state) } self.log.info " done rendering template 0x%08x" % [ self.object_id/2 ] return state.to_s end
Add attributes for the given node's identifiers.
# File lib/inversion/template.rb, line 256 def add_attributes_from_node( node ) if node.respond_to?( :identifiers ) node.identifiers.each do |id| next if @attributes.key?( id.to_sym ) @attributes[ id.to_sym ] = nil end end end
Search for identifiers in the template's node tree and declare an accessor for each one that's found.
# File lib/inversion/template.rb, line 244 def define_attribute_accessors self.walk_tree do |node| self.add_attributes_from_node( node ) end self.attributes.each do |key, _| self.install_accessors( key ) end end
Install reader and writer methods for the attribute associated with the specified key.
# File lib/inversion/template.rb, line 267 def install_accessors( key ) reader, writer = self.make_attribute_accessors( key ) self.singleton_class.send( :define_method, key, &reader ) self.singleton_class.send( :define_method, "#{key}=", &writer ) end
Make method bodies
# File lib/inversion/template.rb, line 276 def make_attribute_accessors( key ) key = key.to_sym reader = lambda { self.attributes[key] } writer = lambda {|newval| self.attributes[key] = newval } return reader, writer end
Proxy method: handle attribute readers/writers for attributes that aren't yet defined.
# File lib/inversion/template.rb, line 213 def method_missing( sym, *args, &block ) return super unless sym.to_s =~ /^([a-z]\w+)=?$/ attribute = $1 self.install_accessors( attribute ) # Call the new method via #method to avoid a method_missing loop. return self.method( sym ).call( *args, &block ) end
Parse the given source into the template node tree.
# File lib/inversion/template.rb, line 224 def parse( source, parsestate=nil ) @options = self.class.config.merge( @init_options ) @attributes.clear @node_tree = @parser.parse( source, parsestate ) @source = source self.define_attribute_accessors end
Generated with the Darkfish Rdoc Generator 2.