# clj-jtwig [Twig](http://twig.sensiolabs.org/) templates in Clojure, provided by [Jtwig](http://jtwig.org). clj-jtwig is a simple Clojure wrapper around Jtwig to make using it in Clojure applications simple. It also provides some extra functions on top of what Jtwig provides already. As well, it adds a simple template caching layer that works out-of-the-box when rendering templates from files. For more information on Twig templates, you can refer to the [Twig documentation](http://twig.sensiolabs.org/documentation) and the [Jtwig documentation](http://jtwig.org/documentation). Please note that Jtwig is not yet a full implementation of Twig, so some things you see on the Twig documentation might not yet be available in Jtwig, and as a result, not available in clj-jtwig. ## Usage **WARNING: This library is still in early development. May not be ready for production use!** ### Leiningen !["clj-jtwig version"](https://clojars.org/clj-jtwig/latest-version.svg) #### Java 6 Jtwig targets Java 7 so you can't use it on Java 6. If you are deploying applications into a Java 6 environment and want to still use clj-jtwig, you can use the version maintained in [this branch](https://github.com/gered/clj-jtwig/tree/java6). It makes use of an otherwise vanilla Jtwig library that has been very slightly modified so that it compiles for Java 6. No other changes have been made and this fork is only being maintained by me *purely* for use with clj-jtwig. *It is not supported by the Jtwig developers.* !["clj-jtwig version"](https://clojars.org/clj-jtwig-java6/latest-version.svg) ### Rendering Templates Getting up and running with clj-jtwig is easy: ```clojure (ns yourapp.core (:require [clj-jtwig.core :refer [render]])) (defn say-hello [name] (render "Hello {{name}}!" {:name name}) (say-hello "Gered") ; returns "Hello Gered!" ``` You can also render from files by providing a full path and filename to `clj-jtwig.core/render-file`. Most of the time you'll want to render from a resource file that is bundled along with your app, in which case you can provide a path and filename relative to the classpath to `clj-jtwig.core/render-resource`. ```clojure (render-file "/Users/gered/say-hello.twig" {:name "Gered"}) ; 'say-hello.twig' in this case would be located at '[your-app]/resources/say-hello.twig' (render-resource "say-hello.twig" {:name "Gered"}) ``` From these examples we can see that the second argument to `render`, `render-file` and `render-resource` is a map of variables that can be referred to in the template (basically it is the template 'model'). You can nest data and refer to it using 'dot' syntax like in Java. ```jinja City of residence: {{address.city}} ``` If a variable's name has any special characters (such as a `-` character), you can access it using 'subscript' syntax instead. ```jinja Customer name: {{customer['full-name']}} ``` If a "root" variable has special characters in it's name, you can also access it using the same syntax, but you will need to access it off of the `model` variable which all variables set in the template are bound to. ```jinja Order number: {{model['customer-order'].orderNumber}} ``` Otherwise, you normally don't need to include `model`, it is implicit. ### Web Apps For web apps built on [Ring](https://github.com/ring-clojure/ring) and [Compojure](https://github.com/weavejester/compojure), you can do something like: ```clojure (ns yourwebapp.views (:require [clj-jtwig.core :refer [render-resource]] [ring.util.response :refer [content-type response]] [compojure.response :refer [Renderable]])) (deftype JtwigRenderable [template-filename params] Renderable (render [this request] (-> (render-resource template-filename params) (response) (content-type "text/html; charset=utf-8")))) ; params is an optional map that will get passed to clj-jtwig.core/render-resource. this is will ; need to contain any variables you want to use in 'template-filename' (defn render [template-filename & [params]] (JtwigRenderable. template-filename params)) ``` And then in your routes: ```clojure (ns yourwebapp.routes (:use compojure.core) (:require [yourwebapp.views :refer [render]])) (defn home-page [] ; in this case, 'home.html' would be located at '[yourwebapp]/resources/views/home.html' (render "views/home.html" {:name "Gered"})) (defroutes yourwebapp-routes (GET "/" [] (home-page))) ``` You will also probably want to add `clj-jtwig.web.middleware/wrap-servlet-context-path` to your [Ring middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware) so that template functions such as `path`, `javascript` and `stylesheet` can automatically prepend the servlet context path to urls you provide to your web app's resources. If you need to output the servlet context path in one of your templates (e.g. for use with Javascript code that performs AJAX requests), then you can either update the `render` function example provided above to `assoc` the value of `clj-jtwig.web.middleware/*servlet-context-path*` to the `params` map. Then you can refer to this value in your templates the same way as any other value you pass in. Or you can do something like this in one of your templates: ```html ``` Which will make a global variable `context` available to your Javascript code which will have the value of the servlet context path. ### Functions Adding custom functions is easy: ```clojure (ns yourapp.core (:require [clj-jtwig.core :refer [render]] [clj-jtwig.functions :refer [deftwigfn]])) (deftwigfn "sayHello" [name] (str "Hello " name "!")) ``` Then your functions can be used in your templates: ```clojure (render "{{ sayHello(name) }}" {:name "Gered"}) ; "Hello Gered!" ; or you can call it using the 'pipe' (filter) syntax (render "{{ name|sayHello }}" {:name "Gered"}) ; "Hello Gered!" ; you can also nest functions and/or chain filters together (render "{{ name|upper|sayHello }}" {:name "Gered"}) ; "Hello GERED!" (render "{{ sayHello(upper(name)) }}" {:name "Gered"}) ; "Hello GERED!" ``` For convenience, you can also define one or more aliases for functions: ```clojure (ns yourapp.core (:require [clj-jtwig.core :refer [render]] [clj-jtwig.functions :refer [defaliasedtwigfn]])) (defaliasedtwigfn "sayHello" [name] ["sayHi"] (str "Hello " name "!")) ; elsewhere in your app's code ... (render "{{ sayHello(name) }}" {:name "Gered"}) ; "Hello Gered!" (render "{{ sayHi(name) }}" {:name "Gered"}) ; "Hello Gered!" ``` The `deftwigfn` and `defaliasedtwigfn` are macros that call `clj-jtwig.functions/add-function!` under the hood. If you prefer, that function can be used directly. Those macros are simply a convenience so you can write template functions in a 'defn'-style syntax. #### Standard Library Functions A number of functions are provided out of the box by Jtwig. A few more are provided to fill in some gaps by clj-jtwig. The following is a list of all the functions available with clj-jtwig. | Function | Description |----------|------------ | abs | `abs(number)`
Returns the absolute value of a number. | batch | `batch(items, batch_size)`
`batch(items, batch_size, filler_item)`
"Batches" items by returning a list of lists with the given number of items. If you provide a second parameter, it is used to fill missing items. | blank_if_null | `blank_if_null(value)`
If the value given is null, returns a blank string instead of "null". | butlast | `butlast(collection)`
`butlast(string)`
`butlast(values, ...)`
Returns all items except for the last one from a collection, series of values, or a string. If a string is passed, it will be treated as a collection of chars. | capitalize | `capitalize(string)`
Capitalizes a value. The first character will be uppercase, all others lowercase. | center | `center(string, max_width)`
`center(string, max_width, padding_string)`
Pads a string with whitespace on the left and right as necessary to 'center' the given value. If the padding_string argument is provided, that string will be used to pad instead of whitespace. | concat | `concat(values, ...)`
Concatenates any number of values together as strings. | convert_encoding | `convert_encoding(string, output_charset, input_charset)`
Converts a string from one encoding to another. The first argument is the expected output charset and the second one is the input charset. | date_format | `date_format(date)`
`date_format(date, format)`
Formats a date to a given format. The format specifier is the same as supported by `SimpleDateFormat`. If the format argument is not specified, the format used will be `yyyy-MM-dd HH:mm:ss`. The date argument should be an instance of `java.util.Date`. | date_modify | `date_modify(date, modifier)`
Modifies a date with a given modifier string. The modifier string can be things like "+1 day" or "+30 minutes". Recognized modifiers are 'seconds', 'minutes', 'hours', 'days', 'months' or 'years'. The date argument should be an instance of `java.util.Date`. A new instance of `java.util.Date` is returned. | default | `default(value, default_value)`
Returns the passed default value if the value is undefined or empty, otherwise the value of the variable. | dump | `dump(value)`
Uses `clojure.pprint/pprint` to dump the entire value of a variable to a string and returns that string. | escape | `escape(string)`
`escape(string, strategy)`
Escapes a string for safe insertion into the final output. The optional strategy parameter specifies the escape strategy: 'html' (default), 'js' or 'xml'. | first | `first(collection)`
`first(string)`
`first(values, ...)`
Returns the first "element" of a collection, series of values, or a string (in which case the first character is returned). | format | `format(format_string, values, ...)`
Formats a given string by replacing the placeholders (placeholders follow the `String.format` notation). The values provided will be used in order for each placeholder in the string. | javascript | `javascript(url)`
Returns a `