The Ocgi library

The cgi_template tool

Principle

cgi_template is a tool to generate OCaml code from templates. Basically, it takes a template file foo.html and ouputs foo.ml and foo.mli. The generated module has the following interface:
val string : ... -> unit -> string
val print : ... -> Format.formatter -> string
where ... are parameters of the template.

Parameters

The parameters of the template are indicated in the template by a specific syntax. Here is an example of template, in file foo.html:
<h1><{title}></h1>
<div class="date"><{?date}></div>
<{text}>
Then, the command
cgi_template foo.html
creates the Foo module with the following interface (foo.mli):
val string : title:string -> ?date:string -> text:string -> unit -> string
val print : title:string -> ?date:string -> text:string -> Format.formatter -> unit
Parameters of a template are indicated in the template between <{ and }>. The parameter name must be a valid OCaml short identifier. A question mark indicates that the parameter is optional and its default value is the empty string.

Inserting OCaml code

OCaml code can be inserted in templates, between <[ and ]>. This code must be a valid OCaml expression of type string. Example:
Current time is
<[
let t = Unix.localtime (Unix.time ()) in 
Printf.sprintf "%02d:%02d" t.Unix.tm_hour t.Unix.tm_min
]>.

Describing form fields

If at least one form field is described in the template (see below), then the interface of the generated module will include, in addition to the string and print functions:
type t = 
  { 
    ... (* one field per form field described in the template *)
  }

val read : Ocgi.Env.cgi_env -> t
val reform : ... -> Ocgi.Env.cgi_env -> string
The read function takes a cgi environment and returns a record of type t. If errors occur while analyzing the cgi arguments to fill the record, the function raises the Ocgi.Args.Read_errors exception.
The reform function acts like the string function, but can use the given cgi environment to pre-fill form fields. This function is useful to display the form when an error occured, for example a mandatory field not filled, with the fields containing the values the user typed in.
Form fields are described with the following syntax:
<!--input kind="entry" name="myfield" -->
This describes a form field named "myfield", whose value must be given when instanciating the template (since we have "myfield" and not "?myfield"). The "kind" attribute determines the "type" attribute in the final HTML code. Here are the possible values for the "kind" attribute:
Value of the "kind" attribute Value of "type" attribute in the final HTML
"entry""text"
"text""textarea"
"select""select"
"hidden""hidden"
"check""checkbox"
"file""file"
"password""password"
A parameter is added to the string, print and reform functions for each form field described in the template.
Other attributes can be specified in the form field description.
type="int"
can be used to indicate that the record field corresponding to this form field should be of type int or int option depending of the "mandatory" attribute (see below).
trans="int_of_string"
can be used to specify OCaml returning the correct type from a string. By default, the type of record field is string and the translation function is the identity.
mandatory="\"Missing parameter myfield!\""
can be used to indicate that the parameter is mandatory, and that a Ocgi.Args.Missing_argument exception will be raised when trying to get this form field value in the read function (the exception will then be embedded in the Ocgi.Args.Read_errors exception). The value of the "mandatory" attribute is the error message in parameter of the Ocgi.Args.Missing_argument exception. When the "mandatory" attribute is not specified, the record field corresponding to the form field is an option type.
Other attributes specified in the form field description are kept in the final HTML when instanciating the template.
For the "mandatory" and "trans" attributes, another syntax can be used which does not need quotes to be escaped:
mandatory=[["Missing parameter myfield!"]]

Headers and footers

OCaml code can be specified to be inserted as header or footer of the generated .ml and .mli files.
To specify headers, use the following syntax at the beginning of the template:
<!--mlheader=[[
open Ocgi
]]-->
<!--mliheader=[[
open Ocgi
]]-->
For footer, use the following syntax at the end of the template:
<!--mlfooter=[[
let f x = ....
]]-->
<!--mlifooter=[[
val f : ....
]]-->