Class: Inversion::Template
- Inherits:
-
Object
- Object
- Inversion::Template
- Extended by:
- Configurability, Loggability
- Includes:
- DataUtilities, TemplateTiltAdditions
- Defined in:
- lib/inversion/tilt.rb,
lib/inversion/template.rb more...
Overview
The main template class.
Inversion templates are the primary objects you’ll be interacting with. Templates can be created from a string:
Inversion::Template.new( template_source )
or from a file:
Inversion::Template.load( 'path/to/template.tmpl' )
Template Options
Inversion supports the Configurability API, and registers itself with the templates
key. This means you can either add a templates
section to your Configurability config, or call ::configure yourself with a config Hash (or something that quacks like one).
To set options on a per-template basis, you can pass an options hash to either Inversion::Template::load or Inversion::Template::new, or set them from within the template itself using the config tag.
The available options are:
- :ignore_unknown_tags
-
Setting to false causes unknown tags used in templates to raise an Inversion::ParseError. Defaults to
true
. - :on_render_error
-
Dictates the behavior of exceptions during rendering. Defaults to
:comment
.- :ignore
-
Exceptions are silently ignored.
- :comment
-
Exceptions are rendered inline as comments.
- :propagate
-
Exceptions bubble up to the caller of Inversion::Template#render.
- :debugging_comments
-
Insert various Inversion parse and render statements while rendering. Defaults to
false
. - :comment_start
-
When rendering debugging comments, the comment is started with these characters. Defaults to
"<!--"
. - :comment_end
-
When rendering debugging comments, the comment is finished with these characters. Defaults to
"-->"
. - :template_paths
-
An array of filesystem paths to search for templates within, when loaded or included with a relative path. The current working directory is always the last checked member of this. Defaults to
[]
. - :escape_format
-
The escaping used by tags such as
escape
andpp
. Default::html
. - :strip_tag_lines
-
If a tag’s presence introduces a blank line into the output, this option removes it. Defaults to
true
. - :stat_delay
-
Templates know when they’ve been altered on disk, and can dynamically reload themselves in long running applications. Setting this option creates a purposeful delay between reloads for busy servers. Defaults to
0
(disabled). - :strict_attributes
-
Disable getting/setting attributes that aren’t explicitly declared with a tag. Trying to get/set an attribute that isn’t declared in the template with this option enabled will result in a NoMethodError being raised.
Defined Under Namespace
Modules: ContainerTag Classes: AttrTag, BeginTag, CallTag, CodeTag, CommentTag, ConfigTag, DefaultTag, ElseTag, ElsifTag, EndTag, EscapeTag, ForTag, FragmentTag, IfTag, ImportTag, IncludeTag, Node, PpTag, PublishTag, RescueTag, SubscribeTag, Tag, TextNode, TimeDeltaTag, UnlessTag, UriencodeTag, YieldTag
Constant Summary collapse
- Parser =
Alias to maintain backward compatibility with <0.2.0 code
Inversion::Parser
- VALID_ERROR_ACTIONS =
Valid actions for ‘on_render_error’
[ :ignore, :comment, :propagate, ]
- DEFAULT_CONFIG =
Default config values
{ # Loading/parsing options :ignore_unknown_tags => true, :template_paths => [], :stat_delay => 0, :strict_attributes => false, # Rendering options :on_render_error => :comment, :debugging_comments => false, :comment_start => '<!-- ', :comment_end => ' -->', :escape_format => :html, :strip_tag_lines => true, }.freeze
Class Attribute Summary collapse
-
.config ⇒ Object
Returns the value of attribute config.
-
.template_paths ⇒ Object
Returns the value of attribute template_paths.
Instance Attribute Summary collapse
-
#attributes ⇒ Object
readonly
The Hash of template attributes.
-
#fragments ⇒ Object
readonly
The Hash of rendered template fragments.
-
#node_tree ⇒ Object
readonly
The node tree parsed from the template source.
-
#options ⇒ Object
readonly
The Template’s configuration options hash.
-
#source ⇒ Object
readonly
The raw template source from which the object was parsed.
-
#source_file ⇒ Object
The Pathname of the file the source was read from.
Class Method Summary collapse
-
.add_extensions(*modules) ⇒ Object
Add one or more extension
modules
to Inversion::Template. -
.configure(config) ⇒ Object
Configure the templating system.
-
.load(path, parsestate = nil, opts = {}) ⇒ Object
Read a template object from the specified
path
.
Instance Method Summary collapse
-
#changed? ⇒ Boolean
Returns
true
if the template was loaded from a file and the file’s mtime is after the time the template was created. -
#initialize(source, parsestate = nil, opts = {}) ⇒ Template
constructor
Create a new Inversion:Template with the given
source
. -
#initialize_copy(other) ⇒ Object
Copy constructor – make copies of some internal data structures, too.
-
#inspect ⇒ Object
Return a human-readable representation of the template object suitable for debugging.
-
#reload ⇒ Object
If the template was loaded from a file, reload and reparse it from the same file.
-
#render(parentstate = nil, &block) ⇒ Object
(also: #to_s)
Render the template, optionally passing a render state (if, for example, the template is being rendered inside another template).
Methods included from DataUtilities
Methods included from TemplateTiltAdditions
Constructor Details
permalink #initialize(source, parsestate = nil, opts = {}) ⇒ Template
Create a new Inversion:Template with the given source
.
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/inversion/template.rb', line 264 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 @node_tree = [] # Parser expects this to always be an Array @options = self.class.config.merge( opts ) @attributes = {} @fragments = {} @source_file = nil @created_at = Time.now @last_checked = @created_at self.parse( source, parsestate ) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
permalink #method_missing(sym, *args, &block) ⇒ Object (protected)
Proxy method: handle attribute readers/writers for attributes that aren’t yet defined.
397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/inversion/template.rb', line 397 def method_missing( sym, *args, &block ) return super unless sym.to_s =~ /^([a-z]\w+)=?$/i attribute = $1 raise NoMethodError, "no tag attribute '%s' (strict mode)" % [ attribute ] if self.[:strict_attributes] self.install_accessors( attribute ) # Call the new method via #method to avoid a method_missing loop. return self.method( sym ).call( *args, &block ) end |
Class Attribute Details
permalink .config ⇒ Object
Returns the value of attribute config.
144 145 146 |
# File 'lib/inversion/template.rb', line 144 def config @config end |
permalink .template_paths ⇒ Object
Returns the value of attribute template_paths.
149 150 151 |
# File 'lib/inversion/template.rb', line 149 def template_paths @template_paths end |
Instance Attribute Details
permalink #attributes ⇒ Object (readonly)
The Hash of template attributes
305 306 307 |
# File 'lib/inversion/template.rb', line 305 def attributes @attributes end |
permalink #fragments ⇒ Object (readonly)
The Hash of rendered template fragments
308 309 310 |
# File 'lib/inversion/template.rb', line 308 def fragments @fragments end |
permalink #node_tree ⇒ Object (readonly)
The node tree parsed from the template source
314 315 316 |
# File 'lib/inversion/template.rb', line 314 def node_tree @node_tree end |
permalink #options ⇒ Object (readonly)
The Template’s configuration options hash
311 312 313 |
# File 'lib/inversion/template.rb', line 311 def @options end |
permalink #source ⇒ Object (readonly)
The raw template source from which the object was parsed.
299 300 301 |
# File 'lib/inversion/template.rb', line 299 def source @source end |
permalink #source_file ⇒ Object
The Pathname of the file the source was read from
302 303 304 |
# File 'lib/inversion/template.rb', line 302 def source_file @source_file end |
Class Method Details
permalink .add_extensions(*modules) ⇒ Object
Add one or more extension modules
to Inversion::Template. This allows tags to decorate the template class with new functionality.
Each one of the given modules
will be included as a mixin, and if it also contains a constant called ClassMethods and/or PrependedMethods, it will also be extended/prepended (respectively) with it.
Example
Add a layout attribute to templates from a ‘layout’ tag:
class Inversion::Template::LayoutTag < Inversion::Tag
module TemplateExtension
def layout
return @layout || 'default.tmpl'
end
module PrependedMethods
def initialize( * )
super
@layout = nil
end
end
Inversion::Template.add_extensions( TemplateExtension )
# ... more tag stuff
end
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/inversion/template.rb', line 245 def self::add_extensions( *modules ) self.log.info "Adding extensions to %p: %p" % [ self, modules ] modules.each do |mod| include( mod ) if mod.const_defined?( :ClassMethods ) submod = mod.const_get( :ClassMethods ) extend( submod ) end if mod.const_defined?( :PrependedMethods ) submod = mod.const_get( :PrependedMethods ) prepend( submod ) end end end |
permalink .configure(config) ⇒ Object
Configure the templating system.
154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/inversion/template.rb', line 154 def self::configure( config ) if config Inversion.log.debug "Merging config %p with current config %p" % [ config, self.config ] merged_config = DEFAULT_CONFIG.merge( config ) self.template_paths = Array( merged_config.delete(:template_paths) ) self.config = merged_config else defaults = DEFAULT_CONFIG.dup self.template_paths = defaults.delete( :template_paths ) self.config = defaults end end |
permalink .load(path, parsestate = nil, opts = {}) ⇒ Object
Read a template object from the specified path
.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/inversion/template.rb', line 169 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 ) opts[:template_paths] ||= self.template_paths search_path = opts[:template_paths] + [ Dir.pwd ] self.log.debug "Searching template paths: %p" % [ search_path ] # 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 = search_path.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, search_path ] if tmpl.nil? end # We trust files read from disk source = if opts.key?( :encoding ) tmpl.read( encoding: opts[:encoding] ) else tmpl.read end # Load the instance and set the path to the source template = self.new( source, parsestate, opts ) template.source_file = tmpl return template end |
Instance Method Details
permalink #changed? ⇒ Boolean
Returns true
if the template was loaded from a file and the file’s mtime is after the time the template was created.
330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/inversion/template.rb', line 330 def changed? return false unless file = self.source_file now = Time.now if now > ( @last_checked + self.[ :stat_delay ].to_i ) if file.mtime > @last_checked @last_checked = now return true end end return false end |
permalink #initialize_copy(other) ⇒ Object
Copy constructor – make copies of some internal data structures, too.
287 288 289 290 291 |
# File 'lib/inversion/template.rb', line 287 def initialize_copy( other ) @options = deep_copy( other. ) @attributes = deep_copy( other.attributes ) @fragments = deep_copy( other.fragments ) end |
permalink #inspect ⇒ Object
Return a human-readable representation of the template object suitable for debugging.
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
# File 'lib/inversion/template.rb', line 373 def inspect nodemap = if $DEBUG ", node_tree: %p" % [ self.node_tree.map(&:as_comment_body) ] else '' end return "#<%s:%08x (loaded from %s) attributes: %p, options: %p%s>" % [ self.class.name, self.object_id / 2, self.source_file ? self.source_file : "memory", self.attributes.keys, self., nodemap ] end |
permalink #reload ⇒ Object
If the template was loaded from a file, reload and reparse it from the same file.
318 319 320 321 322 323 324 325 |
# File 'lib/inversion/template.rb', line 318 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 |
permalink #render(parentstate = nil, &block) ⇒ Object Also known as: to_s
Render the template, optionally passing a render state (if, for example, the template is being rendered inside another template).
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/inversion/template.rb', line 346 def render( parentstate=nil, &block ) self.log.info "rendering template %#x" % [ self.object_id * 2 ] opts = self. opts.merge!( parentstate. ) if parentstate self.fragments.clear state = Inversion::RenderState.new( parentstate, self.attributes, opts, &block ) # self.log.debug " rendering node tree: %p" % [ @node_tree ] self.walk_tree {|node| state << node } self.log.info " done rendering template %#x: %0.4fs" % [ self.object_id/2, state.time_elapsed ] if parentstate parentstate.fragments.merge!( state.fragments ) else self.fragments.replace( state.rendered_fragments ) end return state.to_s end |