Putting code and html together (either html in the code or vice versa) becomes unwieldy and ugly after a certain level of complexity (a little after “hello world”), and for this reason, web developers have traditionally used templates to separate off all the display work. There is debate over exactly how much power a templating system should have (should it be able to execute arbitrary code, or only adhere to a small set of tools), and the construction of a templating system is relatively easy, so templating systems are many and diverse. We have included with Arrow our own templating system – complete, extensible and (we think) intuitive – but have also made it easy for you to use any other templating system. If you already have a favorite, and have no interest in seeing another, (even if you might like it,) you can skip past the tutorial on ours and learn how to use your own
Template handling is, to some degree, integrated with the Arrow server. The arrow config file has a templates section.
The Arrow Templating System uses preprocessing tags to distinguish template directives. These are
both <?...?>
and [?...?]
. The square bracket version is meant to be
used inside of other html tags (e.g., <a href="[?attr link?]">
...)
attr_accessor
in Ruby,
this defines a method attribute on the template object which can
be used to insert one or more objects into the template. Each object
will be stringified and then joined together with the empty string,
and the resultant String will replace each instance of the
<attr>
tag. If the tag specified a
fmtstring, it will be used in the stringification instead
of #to_s
.<call>
directive, but
HTML-escapes the String just before it is inserted into the output
(e.g., turns all <
and >
characters
into into the corresponding <
and
>
entities).<call>
directive, but URL-encodes
the String just before it is inserted into the output.else
and elsif
s are optional, the
elsif
s can be repeated any number of times (including
zero), and the statement can be any template variable,
method chain off a template variable, or regular expression match of a
template variable (like <?if var.method =~ /regex/
?>
).<?for a,b=1 in a_hash ?>
),
array-slurping arguments (*args
) and hashified
arguments.for
directive, useful for calling block-accepting methods besides
#each
.<?import foo ?>
in it would
cause the sub-template’s foo to be set to the container
template’s foo at the point at which it is rendered.
The times for this race were:<br/>
<?include table.tmpl as thisrace ?>
Total times:<br/>
<?include table.tmpl as totals ?>
In the applet:
tmpl.thisrace.rows << ["fred" => 1.10], ["wilma" => "1.05"]
tmpl.totals.rows << ["fred" => 5.77], ["wilma" => 4.95]
First, we need to tell Arrow where to look for templates:
1 templates: 2 path: 3 - "/www/templates"
The path
config item takes one or more directories to use when searching for a template. An applet
registers which templates it will use when it’s loaded via one or more template
directives. If
they’re not absolute paths (i.e., begin with /
), then they’re searched for relative to the paths
in the templates.path
:
1 class HelloApplet < Arrow::Applet 2 # Applet signature 3 template :hello => 'hello-world.tmpl' 4 end 5 # ~> -:2: uninitialized constant Arrow (NameError)
When the applet is running, it can now load the appropriate template by using its #load_template
method and passing the key assigned to the template it wishes to load. You can then fill it with
data and make it the return value of an action:
1 def_action :templated do |txn, *args| 2 self.log.debug "In the 'templated' action of the %s applet." % 3 self.signature.name 4 5 # Get a copy of the ':hello' template 6 templ = self.load_template( :hello ) 7 8 # Fill in some values 9 templ.txn = txn 10 templ.time = Time.now.to_s 11 templ.applet = self 12 13 return templ 14 end 15 # ~> -:2: undefined method `def_action' for main:Object (NoMethodError)
So now we need to create a /www/templates/hello-world.tmpl
file made to display our excitingly
original page.
1 <html> 2 <head> 3 <title><?attr message ?></title> 4 </head> 5 <body> 6 7 <h1><?attr message ?></h1> 8 9 </body> 10 </html>
Which is, for the most part, just static XHTML that will be displayed verbatim. The template directives designate places where the display will be determined by the data that had been saved into the Arrow::Template object in the action itself. This template makes use of the attr, call, if, and include directives, as described above.
(Describe the details of rendering, and how to influence how things are rendered.)
(Describe in general terms how to add directives by putting files in an arrow/template/
directory)
(How to build a template directive, step-by-step)
(Describe how to change templating systems by using a different template.loader
)
(How to write a loader for your templating system of choice)