Next: Introduction, Previous: (dir), Up: (dir) [Contents][Index]
This is the ten Reference Manual, version 0.0.1, generated automatically by Declt version 4.0 beta 2 "William Riker" on Wed Jun 15 05:58:11 2022 GMT+0.
Next: Systems, Previous: The ten Reference Manual, Up: The ten Reference Manual [Contents][Index]
Yet another template system for Common Lisp.
TEN is a fork of ECO template system by Fernando Borretti.
Like ECO, TEN compiles templates to Lisp code, but has some differences:
My reasons for writing yet another template system for Common Lisp is to combine the simplicity and usability of ECO (the whole Lisp language at your disposal for writing the templates), with features available in more complex template systems like Djula that makes things easier for web development (inheritance, dot syntax, etc.).
A TEN template looks like this:
{% template ex1 () (user enabled &key items) %}
<html>
<head>
</head>
<body>
{{ user.name | string-capitalize }}
{% if enabled %}
Enabled
{% else %}
Disabled
{% end %}
{% when items %}
<ul>
{% loop for item in items do %}
<li>{{ item }}</li>
{% end %}
</ul>
{% end %}
{% when (not items) %}
There are no items
{% end %}
</body>
</html>
{% end %}
These are the types of tags:
{{ <var> }}
, becomes <var>
, and {{ <fn> &rest args }}
, that becomes (fn arg1 arg2 .. argn)
.{% <expr> %} body {% end %}
, becomes (<expr> body)
.{#
and #}
to comment out a piece of template.Control tags control which parts of the tamplate are rendered; their return value is ignored.
The value returned by output tags are interpolated into the template. The function called can be any Lisp function, or another template (because templates are compiled to functions).
For example:
{{ user }}
=> user
{{ name user }}
=> (name user)
{% when (name user) %} ... {% end %}
=> (when (name user) ...)
The if
tag is a special case: it supports using an else
tag to separate the true and
false branches. For example:
{% if posts %}
<h1>Recent Posts</h1>
... loop over posts ...
{% else %}
No recent posts.
{% end %}
Also, more advanced control expressions are possible, like let
, case
, cond
, etc.
Templates are defined with the following syntax:
{% template name (&rest options) (&rest args) %}
... body ...
{% end %}
Template options are:
:extends
: The template to extend from.:dot-syntax
: If T, templates are compiled with dot syntax enabled. Dot syntax is implemented via the Lisp library access
. Default is T.:package
: The package in which to compile and export the template. By default, templates are compiled and exported in TEN-TEMPLATES
package.:export
: When T, export the generated template function. Otherwise, the template is not exported. Default is T.:escape-html
: Whether to escape html in output tags. Default is T.:output-whitespace
. Default is T. When NIL, expressions that just spit whitespace are discarded.For manually compiling templates, use ten:compile-template
function.
But more useful is to include them in the ASDF system definition of your project.
First, add :ten
as ASDF system definition dependency:
:defsystem-depends-on (:ten)
Then, use :ten-template
in to include the template files:
(:ten-template "filename")
The default file extension is "ten", but another can be specified via the :file-extension
option; and the template package can be specified with the :package
option. Look at ten.examples ASDF system for an example.
You can also compile all the templates in some directory using this ASDF recipe:
:perform (asdf:compile-op :after (o c)
(dolist (template (uiop:directory-files (asdf:system-relative-pathname :my-app "templates/*.ten")))
(uiop:symbol-call :ten 'compile-template template)))
Templates are compiled into functions and exported in the indicated package. The default package is ten-templates
, but that can be changed from either the ASDF system definition, the ten:compile-template
parameters, or the {% template %}
options.
When developing your project it is useful to be able to compile templates in an interactive way.
If you are using Emacs + SLIME, load ten.el
file.
Then use M-X ten-compile-template
when on the template buffer to compile templates. Note that you may want to have :package
option specified in the template so that it gets compiled into the correct package.
For debugging, you can inspect the expanded template using ten:expand-template
function. In Emacs, go to template buffer an do M-x ten-expand-template
.
If you enable ten
minor mode, template compilation gets conveniently bound to C-c C-c
, and template expansion to C-c RET
. Best is to automatically enable the minor mode for template files adding something like (add-hook 'web-mode-hook 'ten-mode)
to your .emacs
initialization file.
To make a template inherit from anohter, use the :extends
option in template definition.
Templates are organized in sections
. sections
are the parts of the templates that are inherited.
Use {{super}}
inside a section
to render the parent section
.
TEN leverages CLOS for implementing template inheritance. Templates are compiled to classes and generic functions render-template
and render-section
.
Have a look at some examples of template inheritance.
To include other templates, just use the output tag with the name of the included template. Remember that templates are compiled to functions; just call those functions from the template to include them.
Have a look at an example.
When dot syntax is enabled (it is, by default), it is possible to conveniently access objects with dot syntax in templates:
{{ object.key1.key2 }}
that gets translated by access library to:
(access:accesses obj 'key1 'key2)
Have a look at an example.
TEN implements some convenient syntax for filters.
{{ value | func1 arg1 .. argN| func2 arg1 .. argN| .. | funcN arg1 .. argN}}
Filters are just normal functions that get applied to the value.
Filters are translated to functions application like this:
(funcN (.. (func2 (func1 value arg1 .. argN) arg1 .. argN))) arg1 .. argN)
In general, filter functions are expected to receive the value to be filtered as first parameter.
But, for several Lisp functions that's not the case. In those cases, it is possible to use _
to indicate where the filter function should receive the value.
For example, string-trim
receives the string to trim as second value, so, to apply it as filter we do:
{{str | string-trim '(#\%) _}}
Filters syntax is completly optional, you can disregard it and just apply functions instead:
{{ string-trim '(#\%) (string-capitalize str) }}
Have a look at some examples of filters.
Load and have a look at the examples.
(require :ten.examples)
Example templates get compiled and exported to ten/examples
package.
ten-templates
, if the package specified doesn't :use
ten
or ten-template
packages, then you may run into problems trying to compile your templates. That may be because the template
and section
macros are not found in the specified package. In that case, make sure to prefix your template
and section
declarations with ten:
, like:{% ten:template my-template (:package my-package) %}
{% ten:section my-section %}
{% end %}
{% end %}
cond
and case
, require that you turn :output-whitespace
to NIL
. Otherwise, template compilation puts write-string
expressions right in the middle of the case
and cond
bodies. Have a look at this template.MIT
Next: Files, Previous: Introduction, Up: The ten Reference Manual [Contents][Index]
The main system appears first, followed by any subsystem dependency.
Template System for Common Lisp
Mariano Montone <marianomontone@gmail.com>
MIT
# TEN
[](https://travis-ci.org/mmontone/ten)
[](http://quickdocs.org/ten/)
[](./LICENSE)
Yet another template system for Common Lisp.
TEN is a fork of [ECO template system](https://github.com/eudoxia0/eco) by Fernando Borretti.
Like ECO, TEN compiles templates to Lisp code, but has some differences:
- Two types of tags only. Control and output.
- Support for templates inheritance.
- Dot syntax for accessing template data.
- Convenient syntax for applying filters.
- Configurable syntax delimiters (planned, not done yet).
My reasons for writing yet another template system for Common Lisp is to combine the simplicity and usability of ECO (the whole Lisp language at your disposal for writing the templates), with features available in more complex template systems like [Djula](https://mmontone.github.io/djula/) that makes things easier for web development (inheritance, dot syntax, etc.).
## Usage
A TEN template looks like this:
“‘jinja
{% template ex1 () (user enabled &key items) %}
<html>
<head>
</head>
<body>
{{ user.name | string-capitalize }}
{% if enabled %}
Enabled
{% else %}
Disabled
{% end %}
{% when items %}
<ul>
{% loop for item in items do %}
<li>{{ item }}</li>
{% end %}
</ul>
{% end %}
{% when (not items) %}
There are no items
{% end %}
</body>
</html>
{% end %}
“‘
These are the types of tags:
- *Output tags*: ‘{{ <var> }}‘, becomes ‘<var>‘, and ‘{{ <fn> &rest args }}‘, that becomes ‘(fn arg1 arg2 .. argn)‘.
- *Control tags*: ‘{% <expr> %} body {% end %}‘, becomes ‘(<expr> body)‘.
- *Comments tags*: Use ‘{#‘ and ‘#}‘ to comment out a piece of template.
Control tags control which parts of the tamplate are rendered; their return value is ignored.
The value returned by output tags are interpolated into the template. The function called can be any
Lisp function, or another template (because templates are compiled to functions).
For example:
* ‘{{ user }}‘ => ‘user‘
* ‘{{ name user }}‘ => ‘(name user)‘
* ‘{% when (name user) %} ... {% end %}‘ => ‘(when (name user) ...)‘
The ‘if‘ tag is a special case: it supports using an ‘else‘ tag to separate the true and
false branches. For example:
“‘lisp
{% if posts %}
<h1>Recent Posts</h1>
... loop over posts ...
{% else %}
No recent posts.
{% end %}
“‘
Also, more [advanced control expressions](https://github.com/mmontone/ten/blob/master/examples/control.html) are possible, like ‘let‘, ‘case‘, ‘cond‘, etc.
## Template definition
Templates are defined with the following syntax:
“‘
{% template name (&rest options) (&rest args) %}
... body ...
{% end %}
“‘
Template options are:
- ‘:extends‘ : The template to extend from.
- ‘:dot-syntax‘: If T, templates are compiled with dot syntax enabled. Dot syntax is implemented via the Lisp library ‘access‘. Default is T.
- ‘:package‘: The package in which to compile and export the template. By default, templates are compiled and exported in ‘TEN-TEMPLATES‘ package.
- ‘:export‘: When T, export the generated template function. Otherwise, the template is not exported. Default is T.
- ‘:escape-html‘: Whether to escape html in output tags. Default is T.
- ‘:output-whitespace‘. Default is T. When NIL, expressions that just spit whitespace are discarded.
## Template compilation
For manually compiling templates, use ‘ten:compile-template‘ function.
But more useful is to include them in the ASDF system definition of your project.
First, add ‘:ten‘ as ASDF system definition dependency:
‘:defsystem-depends-on (:ten)‘
Then, use ‘:ten-template‘ in to include the template files:
“‘lisp
(:ten-template "filename")
“‘
The default file extension is "ten", but another can be specified via the ‘:file-extension‘ option; and the template package can be specified with the ‘:package‘ option. Look at [ten.examples ASDF system](https://github.com/mmontone/ten/blob/master/ten.examples.asd) for an example.
You can also compile all the templates in some directory using this ASDF recipe:
“‘lisp
:perform (asdf:compile-op :after (o c)
(dolist (template (uiop:directory-files (asdf:system-relative-pathname :my-app "templates/*.ten")))
(uiop:symbol-call :ten ’compile-template template)))
“‘
Templates are compiled into functions and exported in the indicated package. The default package is ‘ten-templates‘, but that can be changed from either the ASDF system definition, the ‘ten:compile-template‘ parameters, or the ‘{% template %}‘ options.
When developing your project it is useful to be able to compile templates in an interactive way.
If you are using Emacs + SLIME, load ‘ten.el‘ file.
Then use ‘M-X ten-compile-template‘ when on the template buffer to compile templates. Note that you may want to have ‘:package‘ option specified in the template so that it gets compiled into the correct package.
For debugging, you can inspect the expanded template using ‘ten:expand-template‘ function. In Emacs, go to template buffer an do ‘M-x ten-expand-template‘.
If you enable ‘ten‘ minor mode, template compilation gets conveniently bound to ‘C-c C-c‘, and template expansion to ‘C-c RET‘. Best is to automatically enable the minor mode for template files adding something like ‘(add-hook ’web-mode-hook ’ten-mode)‘ to your ‘.emacs‘ initialization file.
## Inheritance
To make a template inherit from anohter, use the ‘:extends‘ option in template definition.
Templates are organized in ‘sections‘. ‘sections‘ are the parts of the templates that are inherited.
Use ‘{{super}}‘ inside a ‘section‘ to render the parent ‘section‘.
TEN leverages CLOS for implementing template inheritance. Templates are compiled to classes and generic functions ‘render-template‘ and ‘render-section‘.
Have a look at some [examples of template inheritance](https://github.com/mmontone/ten/blob/master/examples/inheritance.html).
## Includes
To include other templates, just use the output tag with the name of the included template. Remember that templates are compiled to functions; just call those functions from the template to include them.
Have a look at [an example](https://github.com/mmontone/ten/blob/master/examples/include.html).
## Dot syntax
When dot syntax is enabled (it is, by default), it is possible to conveniently access objects with dot syntax in templates:
‘{{ object.key1.key2 }}‘
that gets translated by [access](https://github.com/AccelerationNet/access) library to:
‘(access:accesses obj ’key1 ’key2)‘
Have a look at [an example](https://github.com/mmontone/ten/blob/master/examples/dot-syntax.html).
## Filters
TEN implements some convenient syntax for filters.
‘{{ value | func1 arg1 .. argN| func2 arg1 .. argN| .. | funcN arg1 .. argN}}‘
Filters are just normal functions that get applied to the value.
Filters are translated to functions application like this:
‘(funcN (.. (func2 (func1 value arg1 .. argN) arg1 .. argN))) arg1 .. argN)‘
In general, filter functions are expected to receive the value to be filtered as first parameter.
But, for several Lisp functions that’s not the case. In those cases, it is possible to use ‘_‘ to indicate where the filter function should receive the value.
For example, ‘string-trim‘ receives the string to trim as second value, so, to apply it as filter we do:
‘{{str | string-trim ’(#\%) _}}‘
Filters syntax is completly optional, you can disregard it and just apply functions instead:
‘{{ string-trim ’(#\%) (string-capitalize str) }}‘
Have a look at some [examples of filters](https://github.com/mmontone/ten/tree/master/examples/filters.html).
## Examples
Load and have a look at the [examples](https://github.com/mmontone/ten/tree/master/examples).
“‘lisp
(require :ten.examples)
“‘
Example templates get compiled and exported to ‘ten/examples‘ package.
## Troubleshooting
1) When specifying a template package other than ‘ten-templates‘, if the package specified doesn’t ‘:use‘ ‘ten‘ or ‘ten-template‘ packages, then you may run into problems trying to compile your templates. That may be because the ‘template‘ and ‘section‘ macros are not found in the specified package. In that case, make sure to prefix your ‘template‘ and ‘section‘ declarations with ‘ten:‘, like:
“‘django
{% ten:template my-template (:package my-package) %}
{% ten:section my-section %}
{% end %}
{% end %}
“‘
2) Some "complex" expressions, like ‘cond‘ and ‘case‘, require that you turn ‘:output-whitespace‘ to ‘NIL‘. Otherwise, template compilation puts ‘write-string‘ expressions right in the middle of the ‘case‘ and ‘cond‘ bodies. Have a look at [this template](https://github.com/mmontone/ten/blob/master/examples/control.html).
## License
MIT
0.0.1
Next: Packages, Previous: Systems, Up: The ten Reference Manual [Contents][Index]
Files are sorted by type and then listed depth-first from the systems components trees.
Next: ten/parser.lisp, Previous: ten/ten.asd, Up: Lisp [Contents][Index]
ten (system).
Next: ten/template.lisp, Previous: ten/package.lisp, Up: Lisp [Contents][Index]
package.lisp (file).
ten (system).
Next: ten/compiler.lisp, Previous: ten/parser.lisp, Up: Lisp [Contents][Index]
parser.lisp (file).
ten (system).
Next: ten/asdf.lisp, Previous: ten/template.lisp, Up: Lisp [Contents][Index]
template.lisp (file).
ten (system).
Next: ten/i18n.lisp, Previous: ten/compiler.lisp, Up: Lisp [Contents][Index]
compiler.lisp (file).
ten (system).
Next: ten/ten.lisp, Previous: ten/asdf.lisp, Up: Lisp [Contents][Index]
asdf.lisp (file).
ten (system).
_ (function).
Previous: ten/i18n.lisp, Up: Lisp [Contents][Index]
i18n.lisp (file).
ten (system).
Next: Definitions, Previous: Files, Up: The ten Reference Manual [Contents][Index]
Packages are listed by definition order.
Next: ten/compiler, Previous: ten-templates, Up: Packages [Contents][Index]
common-lisp.
Next: ten/parser, Previous: ten, Up: Packages [Contents][Index]
Next: ten/template, Previous: ten/compiler, Up: Packages [Contents][Index]
Previous: ten/parser, Up: Packages [Contents][Index]
common-lisp.
Next: Indexes, Previous: Packages, Up: The ten Reference Manual [Contents][Index]
Definitions are sorted by export status, category, package, and then by lexicographic order.
Next: Internals, Previous: Definitions, Up: Definitions [Contents][Index]
Next: Symbol macros, Previous: Public Interface, Up: Public Interface [Contents][Index]
The package where template expressions are evaluated and the template function is exported
Next: Macros, Previous: Special variables, Up: Public Interface [Contents][Index]
Next: Ordinary functions, Previous: Symbol macros, Up: Public Interface [Contents][Index]
The main template creation macro.
Arguments:
- EXTENDS: the name of the template to extend from.
- PACKAGE: the package within which the compiled template is to be defined.
- EXPORT: when T, the generated template function is exported.
- ESCAPE-HTML: whether to escape HTML or not. Default is controlled by *ESCAPE-HTML*, which is true by default.
- OUTPUT-WHITESPACE: whether to output whitespaces or not. Default is controlled by *OUTPUT-WHITESPACE*, which is true by default.
- CREATE-STRING-WRITING-FUNCTION: controls whether a function that writes the template to a string should be created. Default is T.
- CREATE-STREAM-WRITING-FUNCTION: controls whether a function that writes the template to *TEMPLATE-OUTPUT* stream should be created. Default is false.
IMPORTANT: some of this macro arguments are processed by CALL-WITH-TEMPLATE-HEADER-OPTIONS, not here. That’s why we declare some of them as ignored.
Next: Generic functions, Previous: Macros, Up: Public Interface [Contents][Index]
Compile a template. If a pathname is given, compiles the file content. Otherwise, compiles the given string.
Escape a string.
Expand a template to Lisp code. Useful for debugging.
Next: Standalone methods, Previous: Ordinary functions, Up: Public Interface [Contents][Index]
automatically generated reader method
body.
automatically generated reader method
code.
automatically generated reader method
code.
Next: Classes, Previous: Generic functions, Up: Public Interface [Contents][Index]
Previous: Standalone methods, Up: Public Interface [Contents][Index]
Previous: Public Interface, Up: Definitions [Contents][Index]
Next: Ordinary functions, Previous: Internals, Up: Internals [Contents][Index]
Export the templates by default
The translation backend.
Next: Generic functions, Previous: Special variables, Up: Internals [Contents][Index]
Next: Classes, Previous: Ordinary functions, Up: Internals [Contents][Index]
Previous: Definitions, Up: The ten Reference Manual [Contents][Index]
Jump to: | _
A B C D E F G L M P R S T V W |
---|
Jump to: | _
A B C D E F G L M P R S T V W |
---|
Next: Data types, Previous: Functions, Up: Indexes [Contents][Index]
Jump to: | *
+
B C S |
---|
Jump to: | *
+
B C S |
---|
Jump to: | <
A C F I P S T |
---|
Jump to: | <
A C F I P S T |
---|