Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Handlebar templates | |
| 2 | |
| 3 This repository contains utilities around a templating system that I called "Han dlebar". They're a logic-less templating language based on [mustache](http://mus tache.github.com/) (obviously) which is itself based on [ctemplate](http://code. google.com/p/ctemplate) apparently. | |
|
mkearney1
2013/11/15 02:04:23
Would be nice to have an updated README once dust
not at google - send to devlin
2013/11/15 05:25:55
Agree x100. there's the docs on github.com/kalman/
| |
| 4 | |
| 5 The original and reference implementation is written in Java, with a JavaScript (via CoffeeScript) port and a Python port. The tests are cross-platform but cont rolled from Java with junit; this means that all implementations are hopefully u p to date (or else some tests are failing). | |
| 6 | |
| 7 The goal of handlebar is to provide the most complete and convenient way to writ e logic-less templates across the whole stack of a web application. Write templa tes once, statically render content on the Java/Python server, then as content i s dynamically added render it using the same templates on the JavaScript client. | |
| 8 | |
| 9 ## Overview | |
| 10 | |
| 11 A template is text plus "mustache" control characters (thank you mustache for th e cool terminology I have adopted). | |
| 12 | |
| 13 A template is rendered by passing it JSON data. I say "JSON" but what I really m ean is JSON-like data; the actual input will vary depending on the language bind ings (Java uses reflection over properties and maps, JavaScript uses objects, Py thon uses dictionaries). | |
| 14 | |
| 15 Generally speaking there are two classes of mustaches: "self closing" ones like `{{foo}}` `{{{foo}}}` `{{*foo}}`, and "has children" ones like `{{#foo}}...{{/fo o}}` `{{?foo}}...{{/foo}}` `{{^foo}}...{{/foo}}` where the `...` is arbitrary ot her template data. | |
| 16 | |
| 17 In both cases the `foo` represents a path into the JSON structure, so | |
| 18 | |
| 19 {{foo.bar.baz}} | |
| 20 | |
| 21 is valid for JSON like | |
| 22 | |
| 23 {"foo": {"bar": {"baz": 42 }}} | |
| 24 | |
| 25 (here it would resolve to `42`). | |
| 26 | |
| 27 All libraries also have the behaviour where descending into a section of the JSO N will "push" the sub-JSON onto the top of the "context stack", so given JSON li ke | |
| 28 | |
| 29 {"foo": {"bar": {"foo": 42 }}} | |
| 30 | |
| 31 the template | |
| 32 | |
| 33 {{foo.bar.foo}} {{?foo}}{{bar.foo}} {{?bar}{{foo}}{{/bar}} {{/foo}} | |
| 34 | |
| 35 will correctly resolve all references to be `42`. | |
| 36 | |
| 37 There is an additional identifier `@` representing the "tip" of that context sta ck, useful when iterating using the `{{#foo}}...{{/foo}}` structure; `{ "list": [1,2,3] }` with `{{#list}} {{@}} {{/list}}` will print ` 1 2 3 `. | |
| 38 | |
| 39 Finally, note that the `{{/foo}}` in `{{#foo}}...{{/foo}}` is actually redundant , and that `{{#foo}}...{{/}}` would be sufficient. Depdencing on the situation o ne or the other will tend to be more readable (explicitly using `{{/foo}}` will perform more validation). | |
| 40 | |
| 41 ## Structures ("mustaches") | |
| 42 | |
| 43 ### `{{foo.bar}}` | |
| 44 | |
| 45 Prints out the HTML-escaped value at path `foo.bar`. | |
| 46 | |
| 47 ### `{{{foo.bar}}}` | |
| 48 | |
| 49 Prints out value at path `foo.bar` (no escaping). | |
| 50 | |
| 51 ### `{{*foo.bar}}}` | |
| 52 | |
| 53 Prints out the JSON serialization of the object at path `foo.bar` (no escaping; this is designed for JavaScript client bootstrapping). | |
| 54 | |
| 55 ### `{{+foo.bar}}` | |
| 56 | |
| 57 Inserts the sub-template (aka "partial template") found at path `foo.bar`. Curre ntly, all libraries actually enforce that this is a pre-compiled template (rathe r than a plain string for example) for efficiency. This lets you do something li ke: | |
| 58 | |
| 59 template = Handlebar('{{#list}} {{+partial}} {{/}}') | |
| 60 partial = Handlebar('{{foo}}...') | |
| 61 json = { | |
| 62 'list': [ | |
| 63 { 'foo': 42 }, | |
| 64 { 'foo': 56 }, | |
| 65 { 'foo': 10 } | |
| 66 ] | |
| 67 } | |
| 68 print(template.render(json, {'partial': partial}).text) | |
| 69 > 42... 56... 10... | |
| 70 | |
| 71 Very useful for dynamic web apps, and also just very useful. | |
| 72 | |
| 73 ### `{{#foo.bar}}...{{/}}` | |
| 74 | |
| 75 Runs `...` for each item in an array found at path `foo.bar`, or each key/value pair in an object. | |
| 76 | |
| 77 ### `{{?foo.bar}}...{{/}}` | |
| 78 | |
| 79 Runs `...` if `foo.bar` resolves to a "value", which is defined based on types. | |
| 80 | |
| 81 * `null` is never considered a value. | |
| 82 * `true` is a valid, `false` isn't. | |
| 83 * Any number other than `0` is a value. | |
| 84 * Any non-empty string is a value. | |
| 85 * Any non-empty array is a value. | |
| 86 * Any non-empty object is a value. | |
| 87 | |
| 88 ### `{{^foo.bar}}...{{/}}` | |
| 89 | |
| 90 Runs `...` if `foo.bar` _doesn't_ resolve to a "value". The exact opposite of `{ {?foo.bar}}...{{/}}`. | |
| 91 | |
| 92 ### `{{:foo.bar}}{{=case1}}...{{=case2}}___{{/}}` | |
| 93 | |
| 94 Ooh a switch statement! Prints `...` if the string found at `foo.bar` is the str ing `"case1"`, `___` if it's `"case2"`, etc. | |
| 95 | |
| 96 ## That's all | |
| 97 | |
| 98 But at the moment this is currently under heavy weekend development. Which is to say a constant trickle of code as I need it. | |
| 99 | |
| 100 Soon: better fault tolerance all round, comments, tidier syntax, less whitespace y output, and moving the Java and JavaScript/CoffeeScript implementations and te sts into this repository! And maybe some kind of online playground at some point . | |
| OLD | NEW |