yui/yui3 — pull request #230 by rgrove (2012-08-25 02:44:50+00:00)
Title: Y.template() - Simple ERB/Underscore-style JavaScript templates

While working on a new widget recently, I found myself wanting a string-based templating solution that was more advanced than `Y.Lang.sub()` or `Y.substitute()`, but without the overhead of `Y.Handlebars`. I needed support for interpolation, if/else branching, and looping, but only for a few very small templates. Underscore-style templates (more familiar as ERB-style templates to Rubyists) seemed like exactly the right fit.

These commits add a new `template` module which provides a `Y.template()` method. Pass in a string template and `Y.template()` will return a compiled template function. Execute the function and pass in a data object to get back a rendered template.

Within a template, `<% ... %>` is used to insert a block of JavaScript code, `<%= ... %>` evaluates and prints an expression as HTML-escaped output, and `<%== ... %>` evaluates and prints an expression as raw, unescaped output. Properties on the data object passed to a template function are made available within the template as local variables.

Here's a simple template that renders a list:

```rhtml

<% Y.Array.each(items, function (item) { %>

<%= item %>

<% }); %>

```

And here's the code to compile the template and render it (assume `listTemplate` is a string containing the template above):

```js
YUI().use('template', function (Y) {
var compiled = Y.template(listTemplate),
html;

// Render the compiled template to HTML.
html = compiled({
classNames: {list: 'yui3-list'},
items : ['one', 'two', 'three', 'four']
});

// And again, with a different set of data.
html = compiled({
classNames: {list: 'yui3-list'},
items : ['a', 'b', 'c', 'd']
});
});
```

Precompilation is supported too, so `Y.template()` can be used to precompile templates at build time or on the server.

```js
// `source` is a string containing JavaScript code that will evaluate to
// a template function. It can be written to a file, served to a remote
// client, etc.
var source = Y.template(listTemplate).source;
```

The complete source for `Y.template()` (minus doc comments) is about 50 lines of code, making it actually _shorter_ than the source for `Y.substitute()`, despite being vastly more powerful. It's also fast. You can see a comparison benchmark at http://jsperf.com/y-template-vs-others.

### Running Locally

The built `template` and `yui` modules are intentionally not included in this pull request in order to keep the diffs clean. Before testing this change, you'll need to build them.

```bash
$ cd src/template && shifter
$ cd src/yui && shifter
```