Programming with the CamlTemplate Library

## 4 Programming with the CamlTemplate Library

When reading this section, you will probably find it helpful to refer to the CamlTemplate API documentation, which is generated by ocamldoc and provided in the `doc/api` directory of the CamlTemplate distribution.

### 4.1 The General Procedure

The general procedure is as follows:

1. Create a template cache using `Cache.create`.
2. Create a data model consisting of values of type `Model.tvalue`.
3. Load a template using `Cache.get_template`.
4. Pass the template to the `merge` function to generate output.

Here is `Hello, world!' with a template. The template is as follows:

    Here is the message: ${message}

And here is a program that uses it:

    open Printf ;;
    open CamlTemplate.Model ;;

    let _ =
      (* Make a template cache. *)
      let cache = CamlTemplate.Cache.create () in
        (* Create a model. *)
      let model = Hashtbl.create 4 in
        Hashtbl.add model "message"
          (Tstr "Hello, world!");
        try
          (* Get the template. *)
          let tmpl =
            CamlTemplate.Cache.get_template
              cache "hello.tmpl"
              (* Make a buffer for the output. *)
          and buf = Buffer.create 256 in
            (* Generate output. *)
            CamlTemplate.merge tmpl model buf;
            print_string (Buffer.contents buf)
        with
            CamlTemplate.Syntax_error msg ->
              eprintf "\n%s\n" msg
          | CamlTemplate.Template_error msg ->
              eprintf "\n%s\n" msg ;;

There are other examples in the `examples` directory of the distribution.

### 4.2 Template Data Models

A template data model is a tree of values; these values can be scalars (strings, integers, floats or booleans), lists, hashtables or functions. The root of the tree must be a hashtable. In a template, an identifier by itself is the name of an entry in that root hashtable.
Tabular data can be represented as a list of hashes of scalars. Each element in the list represents a row in the table, and consists of a hash in which the names are column names and the values are cell values. Such a model can be handled as shown in Section 2.3.

### 4.3 Loading and Caching Templates

Once loaded and parsed, templates are cached; the `Cache` module provides functions for creating template caches, getting templates from them and configuring the behaviour of a cache (e.g. how often it is refreshed). By default, templates are loaded from files, but you can provide a class of type `source_loader` to load them from another source.
The `#include` and `#open` statements fetch the included or opened template from the cache when the enclosing template is merged. Therefore, if an `#include` or `#open` refers to a template that doesn't exist, this won't be detected until the outer template is merged.
Macros are stored in the templates in which they are defined. When a template containing a macro definition changes, the macro definition is updated as well.

### 4.4 Threads

CamlTemplate provides optional support for multithreaded programs. If you need thread support, in addition to linking your program with the `camlTemplate` library, you must also link in `camlTemplate_mt.cmo` (for bytecode programs) or `camlTemplate_mt.cmx` (for native-code programs). This ensures that the following are true:

- Multiple threads can safely use the same template cache concurrently.
- Multiple threads can safely pass the same template (or different templates) to the `merge` function.
- Multiple templates running in different threads can safely use the same model, as long as no template function changes the model. (Note that none of the template statements, including `#set` and `#var`, can change the model.) Values set using `#set` and `#var` are visible only to the thread that set them.

### 4.5 Error Handling

The `get_template` function raises `Syntax_error` if it cannot parse a template. It may also raise other exceptions if it fails to read template source code because of an I/O error.
If a template cannot be merged because of a run-time error (e.g. a wrong data type), the `merge` function raises `Template_error`.
If a Caml function called from a template is unable to complete successfully, it can raise `Tfun_error`; this causes `merge` to raise `Template_error`.