diff --git a/README.md b/README.md index 84394d3..b6677e6 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,49 @@ -This is a Java implementation of the [Mustache template -language](http://mustache.github.com/). There exists [another Java -implementation of Mustache](http://github.com/spullara/mustache.java), but the -motivations for this version are sufficiently different as to justify (in the -author's mind, anyhow) the duplication. +This is a Java implementation of the [Mustache template language](http://mustache.github.com/). +There exists [another Java implementation of Mustache](http://github.com/spullara/mustache.java), +but the motivations for this version are sufficiently different as to justify (in the author's +mind, anyhow) the duplication. Motivations =========== - * Zero dependencies. You can include this single tiny library in your project - and start making use of templates. - * Usability on a variety of target platforms. The other Java Mustache - implementation requires that a Java compiler be available to compile - templates into Java classes. This implementation makes no such requirements - and as a result is usable on Android, or other exciting places where a Java - compiler is not available. It is even possible to avoid the use of - reflection and provide all of your data as a series of nested Maps, if - desired. + * Zero dependencies. You can include this single tiny library in your project and start making + use of templates. + * Usability on a variety of target platforms. The other Java Mustache implementation requires + that a Java compiler be available to compile templates into Java classes. This implementation + makes no such requirements and as a result is usable on Android, or other exciting places where + a Java compiler is not available. It is even possible to avoid the use of reflection and + provide all of your data as a series of nested Maps, if desired. - * [Proguard](http://proguard.sourceforge.net/) and - [JarJar](http://code.google.com/p/jarjar/) friendly. Though the library - will reflectively access your data (if you desire it), the library makes no - other internal use of reflection or by name instantiation of classes. So - you can embed it using Proguard or JarJar without any annoying surprises. + * [Proguard](http://proguard.sourceforge.net/) and [JarJar](http://code.google.com/p/jarjar/) + friendly. Though the library will reflectively access your data (if you desire it), the library + makes no other internal use of reflection or by name instantiation of classes. So you can embed + it using Proguard or JarJar without any annoying surprises. - * Minimal API footprint. There are really only two methods you need to know - about: `compile` and `execute`. You can even chain them together in cases - where performance is of no consequence. + * Minimal API footprint. There are really only two methods you need to know about: `compile` and + `execute`. You can even chain them together in cases where performance is of no consequence. -Its existence justified by the above motivations, this implementation then -strives to provide additional benefits: +Its existence justified by the above motivations, this implementation then strives to provide +additional benefits: * It is available via Maven Central, see below for details. - * It is reasonably performant. Templates are parsed separately from - execution. A template will specialize its variables on (class of context, - name) pairs so that if a variable is first resolved to be (for example) a - field of the context object, that will be attempted directly on subsequent - template invocations, and the slower full resolution will only be tried if - accessing the variable as a field fails. + * It is reasonably performant. Templates are parsed separately from execution. A template will + specialize its variables on (class of context, name) pairs so that if a variable is first + resolved to be (for example) a field of the context object, that will be attempted directly on + subsequent template invocations, and the slower full resolution will only be tried if accessing + the variable as a field fails. Get It ====== -JMustache is available via Maven Central and can thus be easily added to your -Maven, Ivy, etc. projects by adding a dependency on -`com.samskivert:jmustache:1.9`. Or download the [pre-built jar -file](http://repo1.maven.org/maven2/com/samskivert/jmustache/1.9/jmustache-1.9.jar). +JMustache is available via Maven Central and can thus be easily added to your Maven, Ivy, etc. +projects by adding a dependency on `com.samskivert:jmustache:1.9`. Or download the +[pre-built jar file](http://repo1.maven.org/maven2/com/samskivert/jmustache/1.9/jmustache-1.9.jar). Usage ===== -Using JMustache is very simple. Supply your template as a `String` or a -`Reader` and get back a `Template` that you can execute on any context: +Using JMustache is very simple. Supply your template as a `String` or a `Reader` and get back a +`Template` that you can execute on any context: String text = "One, two, {{three}}. Three sir!"; Template tmpl = Mustache.compiler().compile(text); @@ -65,8 +58,8 @@ Use `Reader` and `Writer` if you're doing something more serious: Mustache.compiler().compile(template).execute(data, out); } -The execution context can be any Java object. Variables will be resolved via -the following mechanisms: +The execution context can be any Java object. Variables will be resolved via the following +mechanisms: * If the context is a `Map`, `Map.get` will be used. * If a non-void method with the same name as the variable exists, it will be called. @@ -96,23 +89,25 @@ Example: // Elvis: 75 // Madonna: 52 -As you can see from the example, the fields (and methods) need not be public. -The `persons` field in the anonymous class created to act as a context is -accessible. Note that the use of non-public fields will not work in a sandboxed -security environment. +As you can see from the example, the fields (and methods) need not be public. The `persons` field +in the anonymous class created to act as a context is accessible. Note that the use of non-public +fields will not work in a sandboxed security environment. Sections behave as you would expect: * `Boolean` values enable or disable the section. - * Array, `Iterator`, or `Iterable` values repeatedly execute the section with each element used as the context for each iteration. Empty collections result in zero instances of the section being included in the template. - * An unresolvable or null value is treated as false (by default, see _Default Values_ for more details). + * Array, `Iterator`, or `Iterable` values repeatedly execute the section with each element used as + the context for each iteration. Empty collections result in zero instances of the section being + included in the template. + * An unresolvable or null value is treated as false (by default, see _Default Values_ for more + details). * Any other object results in a single execution of the section with that object as a context. See the code in [MustacheTest.java](http://github.com/samskivert/jmustache/blob/master/src/test/java/com/samskivert/mustache/MustacheTest.java) -for concrete examples. See also the [Mustache -documentation](http://mustache.github.com/mustache.5.html) for details on the -template syntax. +for concrete examples. See also the +[Mustache documentation](http://mustache.github.com/mustache.5.html) for details on the template +syntax. Partials -------- @@ -129,16 +124,14 @@ If you wish to make use of partials (e.g. `{{>subtmpl}}`) you must provide a String tmpl = "...{{>subtmpl}}..."; c.compile(tmpl).execute(); -The above snippet will load `new File(templateDir, "subtmpl")` when compiling -the template. +The above snippet will load `new File(templateDir, "subtmpl")` when compiling the template. Lambdas ------- -JMustache implements lambdas by passing you a `Template.Fragment` instance -which you can use to execute the fragment of the template that was passed to -the lambda. You can decorate the results of the fragment execution, as shown in -the standard Mustache documentation on lambdas: +JMustache implements lambdas by passing you a `Template.Fragment` instance which you can use to +execute the fragment of the template that was passed to the lambda. You can decorate the results of +the fragment execution, as shown in the standard Mustache documentation on lambdas: String tmpl = "{{#bold}}{{name}} is awesome.{{/bold}}"; Mustache.compiler().compile(tmpl).execute(new Object() { @@ -154,8 +147,8 @@ the standard Mustache documentation on lambdas: // result: Willy is awesome. -You can also obtain the results of the fragment execution to do things like -internationalization or caching: +You can also obtain the results of the fragment execution to do things like internationalization or +caching: Object ctx = new Object() { Mustache.Lambda i18n = new Mustache.Lambda() { @@ -170,16 +163,16 @@ internationalization or caching:

{{#i18n}}title{{/i18n}

{{#i18n}}welcome_msg{{/i18n}} -Currently there is no support for "unexecuting" the template and obtaining the -original Mustache template text contained in the section. File a feature -request with a sane use case if you have one. +Currently there is no support for "unexecuting" the template and obtaining the original Mustache +template text contained in the section. File a feature request with a sane use case if you have +one. Default Values -------------- -By default, an exception will be thrown any time a variable cannot be resolved, -or resolves to null. You can change this behavior in two ways. If you want to -provide a value for use in all such circumstances, use `defaultValue()`: +By default, an exception will be thrown any time a variable cannot be resolved, or resolves to +null. You can change this behavior in two ways. If you want to provide a value for use in all such +circumstances, use `defaultValue()`: String tmpl = "{{exists}} {{nullValued}} {{doesNotExist}}?"; Mustache.compiler().defaultValue("what").compile(tmpl).execute(new Object() { @@ -190,9 +183,8 @@ provide a value for use in all such circumstances, use `defaultValue()`: // result: Say what what? -If you only wish to provide a default value for variables that resolve to null, -and wish to preserve exceptions in cases where variables cannot be resolved, -use `nullValue()`: +If you only wish to provide a default value for variables that resolve to null, and wish to +preserve exceptions in cases where variables cannot be resolved, use `nullValue()`: String tmpl = "{{exists}} {{nullValued}} {{doesNotExist}}?"; Mustache.compiler().nullValue("what").compile(tmpl).execute(new Object() { @@ -202,9 +194,9 @@ use `nullValue()`: }); // throws MustacheException when executing the template because doesNotExist cannot be resolved -When using a `Map` as a context, `nullValue()` will only be used when the map -contains a mapping to `null`. If the map lacks a mapping for a given variable, -then it is considered unresolvable and throws an exception. +When using a `Map` as a context, `nullValue()` will only be used when the map contains a mapping to +`null`. If the map lacks a mapping for a given variable, then it is considered unresolvable and +throws an exception. Map map = new HashMap(); map.put("exists", "Say"); @@ -214,20 +206,18 @@ then it is considered unresolvable and throws an exception. Mustache.compiler().nullValue("what").compile(tmpl).execute(map); // throws MustacheException when executing the template because doesNotExist cannot be resolved -Note that section behavior deviates from the above specification (for -historical reasons and because it's kind of useful). By default, a section that -is not resolvable or resolves to null will be omitted (and conversely, an -inverse section that is not resolvable or resolves to null will be included). -If you use `defaultValue()`, this behavior is preserved. If you use -`nullValue()`, sections that refer to an unresolvable variable will now throw -an exception (sections that refer to a resolvable, but null-valued variable, -will behave as before). +Note that section behavior deviates from the above specification (for historical reasons and +because it's kind of useful). By default, a section that is not resolvable or resolves to null will +be omitted (and conversely, an inverse section that is not resolvable or resolves to null will be +included). If you use `defaultValue()`, this behavior is preserved. If you use `nullValue()`, +sections that refer to an unresolvable variable will now throw an exception (sections that refer to +a resolvable, but null-valued variable, will behave as before). Extensions ========== -JMustache extends the basic Mustache template language with some additional -functionality. These additional features are enumerated below: +JMustache extends the basic Mustache template language with some additional functionality. These +additional features are enumerated below: Not escaping HTML by default ---------------------------- @@ -280,9 +270,8 @@ Special variables ----------------- ### this -You can use the special variable `this` to refer to the context object itself -instead of one of its members. This is particularly useful when iterating over -lists. +You can use the special variable `this` to refer to the context object itself instead of one of its +members. This is particularly useful when iterating over lists. Mustache.compiler().compile("{{this}}").execute("hello"); // returns: hello Mustache.compiler().compile("{{#names}}{{this}}{/names}}").execute(new Object() { @@ -298,19 +287,17 @@ Note that you can also use the special variable `.` to mean the same thing. }); // result: TomDickHarry -`.` is apparently supported by other Mustache implementations, though it does -not appear in the official documentation. +`.` is apparently supported by other Mustache implementations, though it does not appear in the +official documentation. ### -first and -last -You can use the special variables `-first` and `-last` to perform special -processing for list elements. `-first` resolves to `true` when inside a section -that is processing the first of a list of elements. It resolves to `false` at -all other times. `-last` resolves to `true` when inside a section that is -processing the last of a list of elements. It resolves to `false` at all other +You can use the special variables `-first` and `-last` to perform special processing for list +elements. `-first` resolves to `true` when inside a section that is processing the first of a list +of elements. It resolves to `false` at all other times. `-last` resolves to `true` when inside a +section that is processing the last of a list of elements. It resolves to `false` at all other times. -One will often make use of these special variables in an inverted section, as -follows: +One will often make use of these special variables in an inverted section, as follows: String tmpl = "{{#things}}{{^-first}}, {{/-first}}{{this}}{{/things}}"; Mustache.compiler().compile(tmpl).execute(new Object() { @@ -318,16 +305,14 @@ follows: }); // result: one, two, three -Note that the values of `-first` and `-last` refer only to the inner-most -enclosing section. If you are processing a section within a section, there is -no way to find out whether you are in the first or last iteration of an outer -section. +Note that the values of `-first` and `-last` refer only to the inner-most enclosing section. If you +are processing a section within a section, there is no way to find out whether you are in the first +or last iteration of an outer section. ### -index -The `-index` special variable contains 1 for the first iteration through a -section, 2 for the second, 3 for the third and so forth. It contains 0 at all -other times. Note that it also contains 0 for a section that is populated by a -singleton value rather than a list. +The `-index` special variable contains 1 for the first iteration through a section, 2 for the +second, 3 for the third and so forth. It contains 0 at all other times. Note that it also contains +0 for a section that is populated by a singleton value rather than a list. String tmpl = "My favorite things:\n{{#things}}{{-index}}. {{this}}\n{{/things}}"; Mustache.compiler().compile(tmpl).execute(new Object() { @@ -342,9 +327,8 @@ singleton value rather than a list. Compound variables ------------------ -In addition to resolving simple variables using the context, you can use -compound variables to extract data from sub-objects of the current context. For -example: +In addition to resolving simple variables using the context, you can use compound variables to +extract data from sub-objects of the current context. For example: Mustache.compiler().compile("Hello {{field.who}}!").execute(new Object() { public Object field = new Object() { @@ -358,22 +342,21 @@ By taking advantage of reflection and bean-property-style lookups, you can do ko Mustache.compiler().compile("Hello {{class.name}}!").execute(new Object()); // result: Hello java.lang.Object! -Note that compound variables are essentially short-hand for using singleton -sections. The above examples could also be represented as: +Note that compound variables are essentially short-hand for using singleton sections. The above +examples could also be represented as: Hello {{#field}}{{who}}{{/field}}! Hello {{#class}}{{name}}{{/class}}! -Note also that one semantic difference exists between nested singleton sections -and compound variables: after resolving the object for the first component of -the compound variable, parent contexts will not be searched when resolving -subcomponents. +Note also that one semantic difference exists between nested singleton sections and compound +variables: after resolving the object for the first component of the compound variable, parent +contexts will not be searched when resolving subcomponents. Newline trimming ---------------- -If the opening or closing section tag are the only thing on a line, any newline -following the tag is trimmed. This allows for civilized templates, like: +If the opening or closing section tag are the only thing on a line, any newline following the tag +is trimmed. This allows for civilized templates, like: Favorite foods: {{#people}} @@ -389,21 +372,20 @@ which produces output like: rather than: Favorite foods: - + - Elvis Presley likes peanut butter. - + - Mahatma Gandhi likes aloo dum. + - -which would be produced without the newline trimming. Note: the current -implementation does not handle Windows-style CRLF data. If you're a Windows -user, how about sending me a patch? +which would be produced without the newline trimming. Note: the current implementation does not +handle Windows-style CRLF data. If you're a Windows user, how about sending me a patch? Nested Contexts --------------- -If a variable is not found in a nested context, it is resolved in the next -outer context. This allows usage like the following: +If a variable is not found in a nested context, it is resolved in the next outer context. This +allows usage like the following: String template = "{{outer}}:\n{{#inner}}{{outer}}.{{this}}\n{{/inner}}"; Mustache.compiler().compile(template).execute(new Object() { @@ -416,17 +398,15 @@ outer context. This allows usage like the following: // foo.baz // foo.bif -Note that if a variable _is_ defined in an inner context, it shadows the same -name in the outer context. There is presently no way to access the variable -from the outer context. +Note that if a variable _is_ defined in an inner context, it shadows the same name in the outer +context. There is presently no way to access the variable from the outer context. Invertible Lambdas ------------------ -For some applications, it may be useful for lambdas to be executed for an -inverse section rather than having the section omitted altogether. This allows -for proper conditional substitution when statically translating templates into -other languages or contexts: +For some applications, it may be useful for lambdas to be executed for an inverse section rather +than having the section omitted altogether. This allows for proper conditional substitution when +statically translating templates into other languages or contexts: String template = "{{#condition}}result if true{{/condition}}\n" + "{{^condition}}result if false{{/condition}}"; @@ -460,9 +440,8 @@ InvertibleLambda whenever you need a single function with two modes of operation Standards Mode -------------- -The more intrusive of these extensions, specifically the searching of parent -contexts and the use of compound varables, can be disabled when creating a -compiler, like so: +The more intrusive of these extensions, specifically the searching of parent contexts and the use +of compound varables, can be disabled when creating a compiler, like so: Map ctx = new HashMap(); ctx.put("foo.bar", "baz"); @@ -472,7 +451,7 @@ compiler, like so: Limitations =========== -In the name of simplicity, some features of Mustache were omitted or -simplified: +In the name of simplicity, some features of Mustache were omitted or simplified: - * `{{= =}}` only supports one or two character delimiters. This is just because I'm lazy and it simplifies the parser. + * `{{= =}}` only supports one or two character delimiters. This is just because I'm lazy and it + simplifies the parser.