Module: Strelka::App::Templating
Overview
A templated content-generation plugin for Strelka::Apps. It uses the Inversion templating system.
It adds:
- a preloaded/cached template table
- a mechanism for fetching templates from the table
- a global layout template which is automatically wrapped around responses
Usage
To use it, just load the :templating plugin in your app:
plugins :templating
and declare one or more templates that your application will use:
templates :console => 'views/console.tmpl',
:proctable => 'partials/proctable.tmpl'
Then, inside your app, you can fetch a copy of one or more of the templates and return it as the reponse:
def handle_request( req )
super do
res = request.response
proctable = template :proctable
proctable.processes = ProcessList.fetch
tmpl = template :console
tmpl. = "Everything's up."
tmpl.proctable = proctable
res.body = tmpl
return res
end
end
You can also just return the template if you don't need to do anything else to the response.
When returning a template, either in the body of the response or directly, it will automatically set a few attributes for commonly-used objects:
- request
The current Strelka::HTTPRequest
- app
The application object (Strelka::App instance).
- strelka_version
Strelka.version_string( true )
- mongrel2_version
Mongrel2.version_string( true )
- ruby_version
The RUBY_VERSION of the running interpreter.
- route
If the :routing plugin is loaded, this will be set to the 'routing_info' of the chosen route. See Strelka::Router#add_route for details.
If your app will only be loading and returning a template without doing anything with it, you can return just its name:
def handle_request( req )
super { :console }
end
It will be loaded, set as the response body, and the above common objects added to it.
:TODO: Explain how returning things other than responses doesn't work well with :filters and maybe other plugins that run inside :templating.
Layouts
Very often, you'll want all or most of the views in your app to share a common page layout. To accomplish this, you can declare a layout template:
layout 'layout.tmpl'
Any template that you return will be set as the 'body' attribute of this layout template (which you'd place into the layout with ) and the layout rendered as the body of the response.
Note that if you want any of the "common objects" from above with a layout template, they'll be set on it since it's the top-level template, but you can still access them using the directive:
Template Locations
Inversion looks for templates in a load path much like Ruby does for libraries that
you 'require'. It contains just the current working directory by default. You can add
your own template directories via the config file (under template_paths in
the templates section), or programmatically from your application, but very often you'll
want to distribute templates with the application gem.
The plugin supports this by looking for a templates/ directory under your gem's
data directory. If it finds such a directory for any loaded gem that has a Strelka dependency,
it appends it to Inversion's template_paths. This also works for plugins, should you
write your own, and want to provide some default templates. See the 'laika-fancyerrors'
gem for an example of this.
Defined Under Namespace
Modules: ClassMethods
Instance Attribute Summary collapse
-
#layout ⇒ Object
The layout template (an Inversion::Template), if one was declared.
-
#template_map ⇒ Object
readonly
The map of template names to Inversion::Template instances.
Attributes included from Plugin
Class Method Summary collapse
-
.discover_template_dirs ⇒ Object
Return an Array of Pathnames to all directories named 'templates' under the data dirctories of loaded gems which have a dependency on Strelka.
-
.included(mod) ⇒ Object
Inclusion callback -- add the plugin's templates directory right before activation so loading the config doesn't clobber it.
Instance Method Summary collapse
-
#extract_template_from_response(response) ⇒ Object
Fetch the template from the
response(if there is one) and return it. -
#handle_request(request, &block) ⇒ Object
Intercept responses on the way back out and turn them into a Mongrel2::HTTPResponse with a String for its entity body.
-
#initialize ⇒ Object
Preload any templates registered with the template map.
-
#load_layout_template ⇒ Object
Load an Inversion::Template for the layout template and return it if one was declared.
-
#load_template_map ⇒ Object
Load instances for all the template paths specified in the App's class and return them in a hash keyed by name (Symbol).
-
#set_common_attributes(template, request) ⇒ Object
Set some default values from the
requestin the given top-leveltemplate. -
#template(name) ⇒ Object
Return the template keyed by the given
name. -
#wrap_in_layout(content, request) ⇒ Object
Wrap the specified
contenttemplate in the layout template and return it.
Methods included from Plugin
extended, plugin_name, run_inside, run_outside
Instance Attribute Details
#layout ⇒ Object
The layout template (an Inversion::Template), if one was declared
208 209 210 |
# File 'lib/strelka/app/templating.rb', line 208 def layout @layout end |
#template_map ⇒ Object (readonly)
The map of template names to Inversion::Template instances.
205 206 207 |
# File 'lib/strelka/app/templating.rb', line 205 def template_map @template_map end |
Class Method Details
.discover_template_dirs ⇒ Object
Return an Array of Pathnames to all directories named 'templates' under the data dirctories of loaded gems which have a dependency on Strelka.
128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/strelka/app/templating.rb', line 128 def self::discover_template_dirs directories = Strelka::Discovery.discover_data_dirs.values.flatten self.log.debug "Discovered data directories: %p" % [ directories ] return directories.inject( [] ) do |array, dir| pattern = File.join( dir, 'templates' ) self.log.debug " adding: %s" % [ pattern ] array += Pathname.glob( pattern ) end end |
.included(mod) ⇒ Object
Inclusion callback -- add the plugin's templates directory right before activation so loading the config doesn't clobber it.
143 144 145 146 147 148 149 150 151 |
# File 'lib/strelka/app/templating.rb', line 143 def self::included( mod ) # Add the plugin's template directory to Inversion's template path dirs = self.discover_template_dirs self.log.info "Discovered template directories: %p" % [ dirs ] Inversion::Template.template_paths.concat( dirs ) super end |
Instance Method Details
#extract_template_from_response(response) ⇒ Object
Fetch the template from the response (if there is one) and return it. If
response itself is a template.
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/strelka/app/templating.rb', line 268 def extract_template_from_response( response ) # Response is a template name if response.is_a?( Symbol ) && self.template_map.key?( response ) self.log.debug " response is a template name (Symbol); using the %p template" % [ response ] return self.template( response ) # Template object elsif response.respond_to?( :render ) self.log.debug " response is a #renderable %p; returning it as-is" % [ response.class ] return response # Template object already in a Response elsif response.is_a?( Mongrel2::Response ) && response.body.respond_to?( :render ) self.log.debug " response is a %p in the body of a %p" % [ response.body.class, response.class ] return response.body # Not templated; returned as-is else self.log.debug " response isn't templated; returning nil" # :TODO: Return the response instead of nil return nil end end |
#handle_request(request, &block) ⇒ Object
Intercept responses on the way back out and turn them into a Mongrel2::HTTPResponse with a String for its entity body.
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/strelka/app/templating.rb', line 243 def handle_request( request, &block ) response = super self.log.debug "Templating: examining %p response." % [ response.class ] template = self.extract_template_from_response( response ) or return response # Wrap the template in a layout if there is one template = self.wrap_in_layout( template, request ) # Set some default stuff on the top-level template self.set_common_attributes( template, request ) # Now render the response body self.log.debug " rendering the template into the response body" response = request.response unless response.is_a?( Mongrel2::Response ) response.body = template.render response.status ||= HTTP::OK return response end |
#initialize ⇒ Object
Preload any templates registered with the template map.
193 194 195 196 197 |
# File 'lib/strelka/app/templating.rb', line 193 def initialize( * ) super @template_map = self.load_template_map @layout = self.load_layout_template end |
#load_layout_template ⇒ Object
Load an Inversion::Template for the layout template and return it if one was declared.
If none was declared, returns nil.
234 235 236 237 238 |
# File 'lib/strelka/app/templating.rb', line 234 def load_layout_template return nil unless ( lt_path = self.class.layout_template ) enc = Encoding.default_internal || Encoding::UTF_8 return Inversion::Template.load( lt_path, encoding: enc ) end |
#load_template_map ⇒ Object
Load instances for all the template paths specified in the App's class and return them in a hash keyed by name (Symbol).
223 224 225 226 227 228 229 |
# File 'lib/strelka/app/templating.rb', line 223 def load_template_map return self.class.template_map.inject( {} ) do |map, (name, path)| enc = Encoding.default_internal || Encoding::UTF_8 map[ name ] = Inversion::Template.load( path, encoding: enc ) map end end |
#set_common_attributes(template, request) ⇒ Object
Set some default values from the request in the given top-level template.
309 310 311 312 313 314 315 316 |
# File 'lib/strelka/app/templating.rb', line 309 def set_common_attributes( template, request ) template.request = request template.app = self template.strelka_version = Strelka.version_string( true ) template.mongrel2_version = Mongrel2.version_string( true ) template.ruby_version = RUBY_VERSION template.route = request.notes[:routing][:route] end |
#template(name) ⇒ Object
Return the template keyed by the given name.
:TODO: Add auto-reloading,
213 214 215 216 217 218 |
# File 'lib/strelka/app/templating.rb', line 213 def template( name ) template = self.template_map[ name ] or raise ArgumentError, "no %p template registered!" % [ name ] template.reload if template.changed? return template.dup end |
#wrap_in_layout(content, request) ⇒ Object
Wrap the specified content template in the layout template and
return it. If there isn't a layout declared, just return content as-is.
296 297 298 299 300 301 302 303 304 305 |
# File 'lib/strelka/app/templating.rb', line 296 def wrap_in_layout( content, request ) return content unless self.layout self.layout.reload if self.layout.changed? l_template = self.layout.dup self.log.debug " wrapping response in layout %p" % [ l_template ] l_template.body = content return l_template end |