If you haven't already read part 1, I strongly suggest doing so before proceeding with this article, as we will be building upon the code from part 1 in the following. I will not waste time on how to get the server going, or how to setup a dispatcher. We will jump straight into the template fray.
But first things first:
The instructions on how to compile and run the program are the same as for part 1 of the article.
So what exactly is the point of using templates to generate your content, instead of just building the HTML directly in the Ada code? Well there are several good reasons for using templates:
- With templates you don't have to re-compile due to changes in the HTML.
- With templates you get a very strong separation between logic and view.
- With templates you can easily localize content by simply loading a different template file based on user preferences/IP address/whatever.
- Your HTML people won't need to learn a single line of Ada. They can stick to what they are good at.
There are probably more good reasons, but the ones mentioned above should be more than enough to convince you that using a template system is a good idea.
Lets take a peek at a very simple template file:
As you can see it looks very much like normal HTML except for the special
@_RESOURCE_@tag (third line from below), which is what turns this otherwise plain looking HTML snippet into a proper template:
@_RESOURCE_@is a template tag that is replaced by some value defined in the Ada code. As you might've guessed this template is used to generate the "404 not found" content, so lets see how the Ada code looks now that we've moved the HTML into a template. This is our new
Generate_Contentfunction from the
If you compare it to the
src/not_found.adbfile from part 1 you'll notice that the changes really aren't that huge, but lets start at the top: At line 5 we
with AWS.Templates;to bring in the templates parser module. With that we now have all the templating power at our fingertips.
The next change happens in the declarative part of
Generate_Contentwhere we now have a
Use AWS.Templates;line and a
Translations : Translate_Set;line. A
Translate_Setis basically a dictionary to which you add your tags and their associated values, and to see how that is done we go down two lines to the
Insert (Translations, Assoc ("RESOURCE", Resource));line. Starting from the inside we associate the value of the
Resourcestring with the template tag
Assocprocedure and then we add the association to
Note that if you insert an association that already exists, then the existing association is overwritten by the new association.
In order to use the
Translationsdictionary we've created, we must call the
Translationsare required, so that is exactly what we're going to give
Parsethen goes to work, matching all the added associations to the tags found in the template file, which in our case means replacing
@_RESOURCE_@with the value of
And that is all. The 404 not found content is now fully templated.
Next lets take a peek at
src/hello_world.adbwhere we use a few more features from the
Let me start by saying that my Fibonacci implementation probably isn't fast nor elegant, but it works and it doesn't clutter the example with a whole bunch of code, and really the interesting part here is not how the Fibonacci sequence is generated but how it is added to the
Translations Translate_Set. For this we have the
Vector_Tag, which in all its simplicity allows us to build lists of values. As you can see we have two such vector tags:
Position. These two are populated by the
Appendcalls in the
Appendadd the values of
Positionand Fibonacci respectively. In case you're wondering about what kinds of data you can append to a vector, here's the specification of all the
Note the last one: Yes, you can append a vector tag to a vector tag, making it possible to build multi-dimensional arrays.
Adding our vector tags to
Translationsis still done using the
Insertprocedure, so nothing new there.
Finally we generate the content with
Parse, where it is worth noting that we've now added the
Cached => Trueparameter. What this does is allow the
AWS.Templatesmodule to cache the template itself. If you do this the server no longer read and parse the template file on every hit. The downside is that if you make changes to the template file, you will have to restart the server for the changes to be registered.
Now lets see how we deal with vector tags and do some other tricks in the template file:
Lines starting with
At line three we define a macro with the name
F. When you call macros you can give them parameters which are then referenced in the macro as
ncorresponds to the N.th. parameter passed to the macro.
Moving on we add the visitors browser to the HTML using the
@_BROWSER_@, and just below that we build the Fibonacci table, and here we encounter the
@@TABLE@@tag. Code between the
@@END_TABLE@@tags are repeated as many times as there are values in the
@@TABLE@@acts very much like an implicit iterator. Much fun can be had with the
@@TABLE@@tag - this example is the very simplest way to utilize it. Check the manual for more extensive examples.
There's a few more tricks in this template worth mentioning. The templates parser module sports a bunch of constants and filters, one of these being
@_NOW_@which is replaced with a time stamp in the format "YYYY-MM-DD HH:MM:SS". At the next line we reverse the contents of
@_REVERSE:VAR_@filter. There's a whole bunch of filters available and multiple filters can be applied to tags for pure awesomeness. As an added bonus you can even create your own filters.
And that was all I had about the templates parser module, but before I end this article I'd like to direct your attention to this new dispatcher in
The goal of this dispatcher is to return the contents of the
exe/templates/hello_world.tmplfile to the user as
Hello_World.Hello_World_Templatefunction takes care of that:
That right there is an Ada 2012 expression function. Since all this function does is call
AWS.Response.Filewe don't really need a body. Expression functions provides a shorthand to declare a function whose body consists of a single return statement. That is IMHO one very nice feature of Ada 2012.
And with that final piece of
AWS.Response.Filemagic I will close this article. Stay tuned for part 3, where I plan on showing you a bit about how to handle HTTP request parameters using the Ada Web Server.