xref: /aosp_15_r20/external/escapevelocity/README.md (revision d396a58ff57b0a501fa89b1f08ee8f4bb5aa1e48)
1*d396a58fSAndroid Build Coastguard Worker# EscapeVelocity summary
2*d396a58fSAndroid Build Coastguard Worker
3*d396a58fSAndroid Build Coastguard WorkerEscapeVelocity is a templating engine that can be used from Java. It is a reimplementation of a subset of
4*d396a58fSAndroid Build Coastguard Workerfunctionality from [Apache Velocity](http://velocity.apache.org/).
5*d396a58fSAndroid Build Coastguard Worker
6*d396a58fSAndroid Build Coastguard WorkerThis is not an official Google product.
7*d396a58fSAndroid Build Coastguard Worker
8*d396a58fSAndroid Build Coastguard WorkerFor a fuller explanation of Velocity's functioning, see its
9*d396a58fSAndroid Build Coastguard Worker[User Guide](http://velocity.apache.org/engine/releases/velocity-1.7/user-guide.html)
10*d396a58fSAndroid Build Coastguard Worker
11*d396a58fSAndroid Build Coastguard WorkerIf EscapeVelocity successfully produces a result from a template evaluation, that result should be
12*d396a58fSAndroid Build Coastguard Workerthe exact same string that Velocity produces. If not, that is a bug.
13*d396a58fSAndroid Build Coastguard Worker
14*d396a58fSAndroid Build Coastguard WorkerEscapeVelocity has no facilities for HTML escaping and it is not appropriate for producing
15*d396a58fSAndroid Build Coastguard WorkerHTML output that might include portions of untrusted input.
16*d396a58fSAndroid Build Coastguard Worker
17*d396a58fSAndroid Build Coastguard Worker
18*d396a58fSAndroid Build Coastguard Worker## Motivation
19*d396a58fSAndroid Build Coastguard Worker
20*d396a58fSAndroid Build Coastguard WorkerVelocity has a convenient templating language. It is easy to read, and it has widespread support
21*d396a58fSAndroid Build Coastguard Workerfrom tools such as editors and coding websites. However, *using* Velocity can prove difficult.
22*d396a58fSAndroid Build Coastguard WorkerIts use to generate Java code in the [AutoValue][AutoValue] annotation processor required many
23*d396a58fSAndroid Build Coastguard Worker[workarounds][VelocityHacks]. The way it dynamically loads classes as part of its standard operation
24*d396a58fSAndroid Build Coastguard Workermakes it hard to [shade](https://maven.apache.org/plugins/maven-shade-plugin/) it, which in the case
25*d396a58fSAndroid Build Coastguard Workerof AutoValue led to interference if Velocity was used elsewhere in a project.
26*d396a58fSAndroid Build Coastguard Worker
27*d396a58fSAndroid Build Coastguard WorkerEscapeVelocity has a simple API that does not involve any class-loading or other sources of
28*d396a58fSAndroid Build Coastguard Workerproblems. It and its dependencies can be shaded with no difficulty.
29*d396a58fSAndroid Build Coastguard Worker
30*d396a58fSAndroid Build Coastguard Worker## Loading a template
31*d396a58fSAndroid Build Coastguard Worker
32*d396a58fSAndroid Build Coastguard WorkerThe entry point for EscapeVelocity is the `Template` class. To obtain an instance, use
33*d396a58fSAndroid Build Coastguard Worker`Template.from(Reader)`. If a template is stored in a file, that file conventionally has the
34*d396a58fSAndroid Build Coastguard Workersuffix `.vm` (for Velocity Macros). But since the argument is a `Reader`, you can also load
35*d396a58fSAndroid Build Coastguard Workera template directly from a Java string, using `StringReader`.
36*d396a58fSAndroid Build Coastguard Worker
37*d396a58fSAndroid Build Coastguard WorkerHere's how you might make a `Template` instance from a template file that is packaged as a resource
38*d396a58fSAndroid Build Coastguard Workerin the same package as the calling class:
39*d396a58fSAndroid Build Coastguard Worker
40*d396a58fSAndroid Build Coastguard Worker```java
41*d396a58fSAndroid Build Coastguard WorkerInputStream in = getClass().getResourceAsStream("foo.vm");
42*d396a58fSAndroid Build Coastguard Workerif (in == null) {
43*d396a58fSAndroid Build Coastguard Worker  throw new IllegalArgumentException("Could not find resource foo.vm");
44*d396a58fSAndroid Build Coastguard Worker}
45*d396a58fSAndroid Build Coastguard WorkerReader reader = new BufferedReader(new InputStreamReader(in));
46*d396a58fSAndroid Build Coastguard WorkerTemplate template = Template.parseFrom(reader);
47*d396a58fSAndroid Build Coastguard Worker```
48*d396a58fSAndroid Build Coastguard Worker
49*d396a58fSAndroid Build Coastguard Worker## Expanding a template
50*d396a58fSAndroid Build Coastguard Worker
51*d396a58fSAndroid Build Coastguard WorkerOnce you have a `Template` object, you can use it to produce a string where the variables in the
52*d396a58fSAndroid Build Coastguard Workertemplate are given the values you provide. You can do this any number of times, specifying the
53*d396a58fSAndroid Build Coastguard Workersame or different values each time.
54*d396a58fSAndroid Build Coastguard Worker
55*d396a58fSAndroid Build Coastguard WorkerSuppose you have this template:
56*d396a58fSAndroid Build Coastguard Worker
57*d396a58fSAndroid Build Coastguard Worker```
58*d396a58fSAndroid Build Coastguard WorkerThe $language word for $original is $translated.
59*d396a58fSAndroid Build Coastguard Worker```
60*d396a58fSAndroid Build Coastguard Worker
61*d396a58fSAndroid Build Coastguard WorkerYou might write this code:
62*d396a58fSAndroid Build Coastguard Worker
63*d396a58fSAndroid Build Coastguard Worker```java
64*d396a58fSAndroid Build Coastguard WorkerMap<String, String> vars = new HashMap<>();
65*d396a58fSAndroid Build Coastguard Workervars.put("language", "French");
66*d396a58fSAndroid Build Coastguard Workervars.put("original", "toe");
67*d396a58fSAndroid Build Coastguard Workervars.put("translated", "orteil");
68*d396a58fSAndroid Build Coastguard WorkerString result = template.evaluate(vars);
69*d396a58fSAndroid Build Coastguard Worker```
70*d396a58fSAndroid Build Coastguard Worker
71*d396a58fSAndroid Build Coastguard WorkerThe `result` string would then be: `The French word for toe is orteil.`
72*d396a58fSAndroid Build Coastguard Worker
73*d396a58fSAndroid Build Coastguard Worker## Comments
74*d396a58fSAndroid Build Coastguard Worker
75*d396a58fSAndroid Build Coastguard WorkerThe characters `##` introduce a comment. Characters from `##` up to and including the following
76*d396a58fSAndroid Build Coastguard Workernewline are omitted from the template. This template has comments:
77*d396a58fSAndroid Build Coastguard Worker
78*d396a58fSAndroid Build Coastguard Worker```
79*d396a58fSAndroid Build Coastguard WorkerLine 1 ## with a comment
80*d396a58fSAndroid Build Coastguard WorkerLine 2
81*d396a58fSAndroid Build Coastguard Worker```
82*d396a58fSAndroid Build Coastguard Worker
83*d396a58fSAndroid Build Coastguard WorkerIt is the same as this template:
84*d396a58fSAndroid Build Coastguard Worker```
85*d396a58fSAndroid Build Coastguard WorkerLine 1 Line 2
86*d396a58fSAndroid Build Coastguard Worker```
87*d396a58fSAndroid Build Coastguard Worker
88*d396a58fSAndroid Build Coastguard Worker## References
89*d396a58fSAndroid Build Coastguard Worker
90*d396a58fSAndroid Build Coastguard WorkerEscapeVelocity supports most of the reference types described in the
91*d396a58fSAndroid Build Coastguard Worker[Velocity User Guide](http://velocity.apache.org/engine/releases/velocity-1.7/user-guide.html#References)
92*d396a58fSAndroid Build Coastguard Worker
93*d396a58fSAndroid Build Coastguard Worker### Variables
94*d396a58fSAndroid Build Coastguard Worker
95*d396a58fSAndroid Build Coastguard WorkerA variable has an ASCII name that starts with a letter (a-z or A-Z) and where any other characters
96*d396a58fSAndroid Build Coastguard Workerare also letters or digits or hyphens (-) or underscores (_). A variable reference can be written
97*d396a58fSAndroid Build Coastguard Workeras `$foo` or as `${foo}`. The value of a variable can be of any Java type. If the value `v` of
98*d396a58fSAndroid Build Coastguard Workervariable `foo` is not a String then the result of `$foo` in a template will be `String.valueOf(v)`.
99*d396a58fSAndroid Build Coastguard WorkerVariables must be defined before they are referenced; otherwise an `EvaluationException` will be
100*d396a58fSAndroid Build Coastguard Workerthrown.
101*d396a58fSAndroid Build Coastguard Worker
102*d396a58fSAndroid Build Coastguard WorkerVariable names are case-sensitive: `$foo` is not the same variable as `$Foo` or `$FOO`.
103*d396a58fSAndroid Build Coastguard Worker
104*d396a58fSAndroid Build Coastguard WorkerInitially the values of variables come from the Map that is passed to `Template.evaluate`. Those
105*d396a58fSAndroid Build Coastguard Workervalues can be changed, and new ones defined, using the `#set` directive in the template:
106*d396a58fSAndroid Build Coastguard Worker
107*d396a58fSAndroid Build Coastguard Worker```
108*d396a58fSAndroid Build Coastguard Worker#set ($foo = "bar")
109*d396a58fSAndroid Build Coastguard Worker```
110*d396a58fSAndroid Build Coastguard Worker
111*d396a58fSAndroid Build Coastguard WorkerSetting a variable affects later references to it in the template, but has no effect on the
112*d396a58fSAndroid Build Coastguard Worker`Map` that was passed in or on later template evaluations.
113*d396a58fSAndroid Build Coastguard Worker
114*d396a58fSAndroid Build Coastguard Worker### Properties
115*d396a58fSAndroid Build Coastguard Worker
116*d396a58fSAndroid Build Coastguard WorkerIf a reference looks like `$purchase.Total` then the value of the `$purchase` variable must be a
117*d396a58fSAndroid Build Coastguard WorkerJava object that has a public method `getTotal()` or `gettotal()`, or a method called `isTotal()` or
118*d396a58fSAndroid Build Coastguard Worker`istotal()` that returns `boolean`. The result of `$purchase.Total` is then the result of calling
119*d396a58fSAndroid Build Coastguard Workerthat method on the `$purchase` object.
120*d396a58fSAndroid Build Coastguard Worker
121*d396a58fSAndroid Build Coastguard WorkerIf you want to have a period (`.`) after a variable reference *without* it being a property
122*d396a58fSAndroid Build Coastguard Workerreference, you can use braces like this: `${purchase}.Total`. If, after a property reference, you
123*d396a58fSAndroid Build Coastguard Workerhave a further period, you can put braces around the reference like this:
124*d396a58fSAndroid Build Coastguard Worker`${purchase.Total}.nonProperty`.
125*d396a58fSAndroid Build Coastguard Worker
126*d396a58fSAndroid Build Coastguard Worker### Methods
127*d396a58fSAndroid Build Coastguard Worker
128*d396a58fSAndroid Build Coastguard WorkerIf a reference looks like `$purchase.addItem("scones", 23)` then the value of the `$purchase`
129*d396a58fSAndroid Build Coastguard Workervariable must be a Java object that has a public method `addItem` with two parameters that match
130*d396a58fSAndroid Build Coastguard Workerthe given values. Unlike Velocity, EscapeVelocity requires that there be exactly one such method.
131*d396a58fSAndroid Build Coastguard WorkerIt is OK if there are other `addItem` methods provided they are not compatible with the
132*d396a58fSAndroid Build Coastguard Workerarguments provided.
133*d396a58fSAndroid Build Coastguard Worker
134*d396a58fSAndroid Build Coastguard WorkerProperties are in fact a special case of methods: instead of writing `$purchase.Total` you could
135*d396a58fSAndroid Build Coastguard Workerwrite `$purchase.getTotal()`. Braces can be used to make the method invocation explicit
136*d396a58fSAndroid Build Coastguard Worker(`${purchase.getTotal()}`) or to prevent method invocation (`${purchase}.getTotal()`).
137*d396a58fSAndroid Build Coastguard Worker
138*d396a58fSAndroid Build Coastguard Worker### Indexing
139*d396a58fSAndroid Build Coastguard Worker
140*d396a58fSAndroid Build Coastguard WorkerIf a reference looks like `$indexme[$i]` then the value of the `$indexme` variable must be a Java
141*d396a58fSAndroid Build Coastguard Workerobject that has a public `get` method that takes one argument that is compatible with the index.
142*d396a58fSAndroid Build Coastguard WorkerFor example, `$indexme` might be a `List` and `$i` might be an integer. Then the reference would
143*d396a58fSAndroid Build Coastguard Workerbe the result of `List.get(int)` for that list and that integer. Or, `$indexme` might be a `Map`,
144*d396a58fSAndroid Build Coastguard Workerand the reference would be the result of `Map.get(Object)` for the object `$i`. In general,
145*d396a58fSAndroid Build Coastguard Worker`$indexme[$i]` is equivalent to `$indexme.get($i)`.
146*d396a58fSAndroid Build Coastguard Worker
147*d396a58fSAndroid Build Coastguard WorkerUnlike Velocity, EscapeVelocity does not allow `$indexme` to be a Java array.
148*d396a58fSAndroid Build Coastguard Worker
149*d396a58fSAndroid Build Coastguard Worker### Undefined references
150*d396a58fSAndroid Build Coastguard Worker
151*d396a58fSAndroid Build Coastguard WorkerIf a variable has not been given a value, either by being in the initial Map argument or by being
152*d396a58fSAndroid Build Coastguard Workerset in the template, then referencing it will provoke an `EvaluationException`. There is
153*d396a58fSAndroid Build Coastguard Workera special case for `#if`: if you write `#if ($var)` then it is allowed for `$var` not to be defined,
154*d396a58fSAndroid Build Coastguard Workerand it is treated as false.
155*d396a58fSAndroid Build Coastguard Worker
156*d396a58fSAndroid Build Coastguard Worker### Setting properties and indexes: not supported
157*d396a58fSAndroid Build Coastguard Worker
158*d396a58fSAndroid Build Coastguard WorkerUnlke Velocity, EscapeVelocity does not allow `#set` assignments with properties or indexes:
159*d396a58fSAndroid Build Coastguard Worker
160*d396a58fSAndroid Build Coastguard Worker```
161*d396a58fSAndroid Build Coastguard Worker#set ($data.User = "jon")        ## Allowed in Velocity but not in EscapeVelocity
162*d396a58fSAndroid Build Coastguard Worker#set ($map["apple"] = "orange")  ## Allowed in Velocity but not in EscapeVelocity
163*d396a58fSAndroid Build Coastguard Worker```
164*d396a58fSAndroid Build Coastguard Worker
165*d396a58fSAndroid Build Coastguard Worker## Expressions
166*d396a58fSAndroid Build Coastguard Worker
167*d396a58fSAndroid Build Coastguard WorkerIn certain contexts, such as the `#set` directive we have just seen or certain other directives,
168*d396a58fSAndroid Build Coastguard WorkerEscapeVelocity can evaluate expressions. An expression can be any of these:
169*d396a58fSAndroid Build Coastguard Worker
170*d396a58fSAndroid Build Coastguard Worker* A reference, of the kind we have just seen. The value is the value of the reference.
171*d396a58fSAndroid Build Coastguard Worker* A string literal enclosed in double quotes, like `"this"`. A string literal must appear on
172*d396a58fSAndroid Build Coastguard Worker  one line. EscapeVelocity does not support the characters `$` or `\\` in a string literal.
173*d396a58fSAndroid Build Coastguard Worker* An integer literal such as `23` or `-100`. EscapeVelocity does not support floating-point
174*d396a58fSAndroid Build Coastguard Worker  literals.
175*d396a58fSAndroid Build Coastguard Worker* A Boolean literal, `true` or `false`.
176*d396a58fSAndroid Build Coastguard Worker* Simpler expressions joined together with operators that have the same meaning as in Java:
177*d396a58fSAndroid Build Coastguard Worker  `!`, `==`, `!=`, `<`, `<=`, `>`, `>=`, `&&`, `||`, `+`, `-`, `*`, `/`, `%`. The operators have the
178*d396a58fSAndroid Build Coastguard Worker  same precedence as in Java.
179*d396a58fSAndroid Build Coastguard Worker* A simpler expression in parentheses, for example `(2 + 3)`.
180*d396a58fSAndroid Build Coastguard Worker
181*d396a58fSAndroid Build Coastguard WorkerVelocity supports string literals with single quotes, like `'this`' and also references within
182*d396a58fSAndroid Build Coastguard Workerstrings, like `"a $reference in a string"`, but EscapeVelocity does not.
183*d396a58fSAndroid Build Coastguard Worker
184*d396a58fSAndroid Build Coastguard Worker## Directives
185*d396a58fSAndroid Build Coastguard Worker
186*d396a58fSAndroid Build Coastguard WorkerA directive is introduced by a `#` character followed by a word. We have already seen the `#set`
187*d396a58fSAndroid Build Coastguard Workerdirective, which sets the value of a variable. The other directives are listed below.
188*d396a58fSAndroid Build Coastguard Worker
189*d396a58fSAndroid Build Coastguard WorkerDirectives can be spelled with or without braces, so `#set` or `#{set}`.
190*d396a58fSAndroid Build Coastguard Worker
191*d396a58fSAndroid Build Coastguard Worker### `#if`/`#elseif`/`#else`
192*d396a58fSAndroid Build Coastguard Worker
193*d396a58fSAndroid Build Coastguard WorkerThe `#if` directive selects parts of the template according as a condition is true or false.
194*d396a58fSAndroid Build Coastguard WorkerThe simplest case looks like this:
195*d396a58fSAndroid Build Coastguard Worker
196*d396a58fSAndroid Build Coastguard Worker```
197*d396a58fSAndroid Build Coastguard Worker#if ($condition) yes #end
198*d396a58fSAndroid Build Coastguard Worker```
199*d396a58fSAndroid Build Coastguard Worker
200*d396a58fSAndroid Build Coastguard WorkerThis evaluates to the string ` yes ` if the variable `$condition` is defined and has a true value,
201*d396a58fSAndroid Build Coastguard Workerand to the empty string otherwise. It is allowed for `$condition` not to be defined in this case,
202*d396a58fSAndroid Build Coastguard Workerand then it is treated as false.
203*d396a58fSAndroid Build Coastguard Worker
204*d396a58fSAndroid Build Coastguard WorkerThe expression in `#if` (here `$condition`) is considered true if its value is not null and not
205*d396a58fSAndroid Build Coastguard Workerequal to the Boolean value `false`.
206*d396a58fSAndroid Build Coastguard Worker
207*d396a58fSAndroid Build Coastguard WorkerAn `#if` directive can also have an `#else` part, for example:
208*d396a58fSAndroid Build Coastguard Worker
209*d396a58fSAndroid Build Coastguard Worker```
210*d396a58fSAndroid Build Coastguard Worker#if ($condition) yes #else no #end
211*d396a58fSAndroid Build Coastguard Worker```
212*d396a58fSAndroid Build Coastguard Worker
213*d396a58fSAndroid Build Coastguard WorkerThis evaluates to the string ` yes ` if the condition is true or the string ` no ` if it is not.
214*d396a58fSAndroid Build Coastguard Worker
215*d396a58fSAndroid Build Coastguard WorkerAn `#if` directive can have any number of `#elseif` parts. For example:
216*d396a58fSAndroid Build Coastguard Worker
217*d396a58fSAndroid Build Coastguard Worker```
218*d396a58fSAndroid Build Coastguard Worker#if ($i == 0) zero #elseif ($i == 1) one #elseif ($i == 2) two #else many #end
219*d396a58fSAndroid Build Coastguard Worker```
220*d396a58fSAndroid Build Coastguard Worker
221*d396a58fSAndroid Build Coastguard Worker### `#foreach`
222*d396a58fSAndroid Build Coastguard Worker
223*d396a58fSAndroid Build Coastguard WorkerThe `#foreach` directive repeats a part of the template once for each value in a list.
224*d396a58fSAndroid Build Coastguard Worker
225*d396a58fSAndroid Build Coastguard Worker```
226*d396a58fSAndroid Build Coastguard Worker#foreach ($product in $allProducts)
227*d396a58fSAndroid Build Coastguard Worker  ${product}!
228*d396a58fSAndroid Build Coastguard Worker#end
229*d396a58fSAndroid Build Coastguard Worker```
230*d396a58fSAndroid Build Coastguard Worker
231*d396a58fSAndroid Build Coastguard WorkerThis will produce one line for each value in the `$allProducts` variable. The value of
232*d396a58fSAndroid Build Coastguard Worker`$allProducts` can be a Java `Iterable`, such as a `List` or `Set`; or it can be an object array;
233*d396a58fSAndroid Build Coastguard Workeror it can be a Java `Map`. When it is a `Map` the `#foreach` directive loops over every *value*
234*d396a58fSAndroid Build Coastguard Workerin the `Map`.
235*d396a58fSAndroid Build Coastguard Worker
236*d396a58fSAndroid Build Coastguard WorkerIf `$allProducts` is a `List` containing the strings `oranges` and `lemons` then the result of the
237*d396a58fSAndroid Build Coastguard Worker`#foreach` would be this:
238*d396a58fSAndroid Build Coastguard Worker
239*d396a58fSAndroid Build Coastguard Worker```
240*d396a58fSAndroid Build Coastguard Worker
241*d396a58fSAndroid Build Coastguard Worker  oranges!
242*d396a58fSAndroid Build Coastguard Worker
243*d396a58fSAndroid Build Coastguard Worker
244*d396a58fSAndroid Build Coastguard Worker  lemons!
245*d396a58fSAndroid Build Coastguard Worker
246*d396a58fSAndroid Build Coastguard Worker```
247*d396a58fSAndroid Build Coastguard Worker
248*d396a58fSAndroid Build Coastguard WorkerWhen the `#foreach` completes, the loop variable (`$product` in the example) goes back to whatever
249*d396a58fSAndroid Build Coastguard Workervalue it had before, or to being undefined if it was undefined before.
250*d396a58fSAndroid Build Coastguard Worker
251*d396a58fSAndroid Build Coastguard WorkerWithin the `#foreach`, a special variable `$foreach` is defined, such that you can write
252*d396a58fSAndroid Build Coastguard Worker`$foreach.hasNext`, which will be true if there are more values after this one or false if this
253*d396a58fSAndroid Build Coastguard Workeris the last value. For example:
254*d396a58fSAndroid Build Coastguard Worker
255*d396a58fSAndroid Build Coastguard Worker```
256*d396a58fSAndroid Build Coastguard Worker#foreach ($product in $allProducts)${product}#if ($foreach.hasNext), #end#end
257*d396a58fSAndroid Build Coastguard Worker```
258*d396a58fSAndroid Build Coastguard Worker
259*d396a58fSAndroid Build Coastguard WorkerThis would produce the output `oranges, lemons` for the list above. (The example is scrunched up
260*d396a58fSAndroid Build Coastguard Workerto avoid introducing extraneous spaces, as described in the [section](#spaces) on spaces
261*d396a58fSAndroid Build Coastguard Workerbelow.)
262*d396a58fSAndroid Build Coastguard Worker
263*d396a58fSAndroid Build Coastguard WorkerVelocity gives the `$foreach` variable other properties (`index` and `count`) but EscapeVelocity
264*d396a58fSAndroid Build Coastguard Workerdoes not.
265*d396a58fSAndroid Build Coastguard Worker
266*d396a58fSAndroid Build Coastguard Worker### Macros
267*d396a58fSAndroid Build Coastguard Worker
268*d396a58fSAndroid Build Coastguard WorkerA macro is a part of the template that can be reused in more than one place, potentially with
269*d396a58fSAndroid Build Coastguard Workerdifferent parameters each time. In the simplest case, a macro has no arguments:
270*d396a58fSAndroid Build Coastguard Worker
271*d396a58fSAndroid Build Coastguard Worker```
272*d396a58fSAndroid Build Coastguard Worker#macro (hello) bonjour #end
273*d396a58fSAndroid Build Coastguard Worker```
274*d396a58fSAndroid Build Coastguard Worker
275*d396a58fSAndroid Build Coastguard WorkerThen the macro can be referenced by writing `#hello()` and the result will be the string ` bonjour `
276*d396a58fSAndroid Build Coastguard Workerinserted at that point.
277*d396a58fSAndroid Build Coastguard Worker
278*d396a58fSAndroid Build Coastguard WorkerMacros can also have parameters:
279*d396a58fSAndroid Build Coastguard Worker
280*d396a58fSAndroid Build Coastguard Worker```
281*d396a58fSAndroid Build Coastguard Worker#macro (greet $hello $world) $hello, $world! #end
282*d396a58fSAndroid Build Coastguard Worker```
283*d396a58fSAndroid Build Coastguard Worker
284*d396a58fSAndroid Build Coastguard WorkerThen `#greet("bonjour", "monde")` would produce ` bonjour, monde! `. The comma is optional, so
285*d396a58fSAndroid Build Coastguard Workeryou could also write `#greet("bonjour" "monde")`.
286*d396a58fSAndroid Build Coastguard Worker
287*d396a58fSAndroid Build Coastguard WorkerWhen a macro completes, the parameters (`$hello` and `$world` in the example) go back to whatever
288*d396a58fSAndroid Build Coastguard Workervalues they had before, or to being undefined if they were undefined before.
289*d396a58fSAndroid Build Coastguard Worker
290*d396a58fSAndroid Build Coastguard WorkerAll macro definitions take effect before the template is evaluated, so you can use a macro at a
291*d396a58fSAndroid Build Coastguard Workerpoint in the template that is before the point where it is defined. This also means that you can't
292*d396a58fSAndroid Build Coastguard Workerdefine a macro conditionally:
293*d396a58fSAndroid Build Coastguard Worker
294*d396a58fSAndroid Build Coastguard Worker```
295*d396a58fSAndroid Build Coastguard Worker## This doesn't work!
296*d396a58fSAndroid Build Coastguard Worker#if ($language == "French")
297*d396a58fSAndroid Build Coastguard Worker#macro (hello) bonjour #end
298*d396a58fSAndroid Build Coastguard Worker#else
299*d396a58fSAndroid Build Coastguard Worker#macro (hello) hello #end
300*d396a58fSAndroid Build Coastguard Worker#end
301*d396a58fSAndroid Build Coastguard Worker```
302*d396a58fSAndroid Build Coastguard Worker
303*d396a58fSAndroid Build Coastguard WorkerThere is no particular reason to define the same macro more than once, but if you do it is the
304*d396a58fSAndroid Build Coastguard Workerfirst definition that is retained. In the `#if` example just above, the `bonjour` version will
305*d396a58fSAndroid Build Coastguard Workeralways be used.
306*d396a58fSAndroid Build Coastguard Worker
307*d396a58fSAndroid Build Coastguard WorkerMacros can make templates hard to understand. You may prefer to put the logic in a Java method
308*d396a58fSAndroid Build Coastguard Workerrather than a macro, and call the method from the template using `$methods.doSomething("foo")`
309*d396a58fSAndroid Build Coastguard Workeror whatever.
310*d396a58fSAndroid Build Coastguard Worker
311*d396a58fSAndroid Build Coastguard Worker## Block quoting
312*d396a58fSAndroid Build Coastguard Worker
313*d396a58fSAndroid Build Coastguard WorkerIf you have text that should be treated verbatim, you can enclose it in `#[[...]]#`. The text
314*d396a58fSAndroid Build Coastguard Workerrepresented by `...` will be copied into the output. `#` and `$` characters will have no
315*d396a58fSAndroid Build Coastguard Workereffect in that text.
316*d396a58fSAndroid Build Coastguard Worker
317*d396a58fSAndroid Build Coastguard Worker```
318*d396a58fSAndroid Build Coastguard Worker#[[ This is not a #directive, and this is not a $variable. ]]#
319*d396a58fSAndroid Build Coastguard Worker```
320*d396a58fSAndroid Build Coastguard Worker
321*d396a58fSAndroid Build Coastguard Worker## Including other templates
322*d396a58fSAndroid Build Coastguard Worker
323*d396a58fSAndroid Build Coastguard WorkerIf you want to include a template from another file, you can use the `#parse` directive.
324*d396a58fSAndroid Build Coastguard WorkerThis can be useful if you have macros that are shared between templates, for example.
325*d396a58fSAndroid Build Coastguard Worker
326*d396a58fSAndroid Build Coastguard Worker```
327*d396a58fSAndroid Build Coastguard Worker#set ($foo = "bar")
328*d396a58fSAndroid Build Coastguard Worker#parse("macros.vm")
329*d396a58fSAndroid Build Coastguard Worker#mymacro($foo) ## #mymacro defined in macros.vm
330*d396a58fSAndroid Build Coastguard Worker```
331*d396a58fSAndroid Build Coastguard Worker
332*d396a58fSAndroid Build Coastguard WorkerFor this to work, you will need to tell EscapeVelocity how to find "resources" such as
333*d396a58fSAndroid Build Coastguard Worker`macro.vm` in the example. You might use something like this:
334*d396a58fSAndroid Build Coastguard Worker
335*d396a58fSAndroid Build Coastguard Worker```
336*d396a58fSAndroid Build Coastguard WorkerResourceOpener resourceOpener = resourceName -> {
337*d396a58fSAndroid Build Coastguard Worker  InputStream inputStream = getClass().getResource(resourceName);
338*d396a58fSAndroid Build Coastguard Worker  if (inputStream == null) {
339*d396a58fSAndroid Build Coastguard Worker    throw new IOException("Unknown resource: " + resourceName);
340*d396a58fSAndroid Build Coastguard Worker  }
341*d396a58fSAndroid Build Coastguard Worker  return new BufferedReader(InputStreamReader(inputStream, StandardCharsets.UTF_8));
342*d396a58fSAndroid Build Coastguard Worker};
343*d396a58fSAndroid Build Coastguard WorkerTemplate template = Template.parseFrom("foo.vm", resourceOpener);
344*d396a58fSAndroid Build Coastguard Worker```
345*d396a58fSAndroid Build Coastguard Worker
346*d396a58fSAndroid Build Coastguard WorkerIn this case, the `resourceOpener` is used to find the main template `foo.vm`, as well as any
347*d396a58fSAndroid Build Coastguard Workertemplates it may reference in `#parse` directives.
348*d396a58fSAndroid Build Coastguard Worker
349*d396a58fSAndroid Build Coastguard Worker## <a name="spaces"></a> Spaces
350*d396a58fSAndroid Build Coastguard Worker
351*d396a58fSAndroid Build Coastguard WorkerFor the most part, spaces and newlines in the template are preserved exactly in the output.
352*d396a58fSAndroid Build Coastguard WorkerTo avoid unwanted newlines, you may end up using `##` comments. In the `#foreach` example above
353*d396a58fSAndroid Build Coastguard Workerwe had this:
354*d396a58fSAndroid Build Coastguard Worker
355*d396a58fSAndroid Build Coastguard Worker```
356*d396a58fSAndroid Build Coastguard Worker#foreach ($product in $allProducts)${product}#if ($foreach.hasNext), #end#end
357*d396a58fSAndroid Build Coastguard Worker```
358*d396a58fSAndroid Build Coastguard Worker
359*d396a58fSAndroid Build Coastguard WorkerThat was to avoid introducing unwanted spaces and newlines. A more readable way to achieve the same
360*d396a58fSAndroid Build Coastguard Workerresult is this:
361*d396a58fSAndroid Build Coastguard Worker
362*d396a58fSAndroid Build Coastguard Worker```
363*d396a58fSAndroid Build Coastguard Worker#foreach ($product in $allProducts)##
364*d396a58fSAndroid Build Coastguard Worker${product}##
365*d396a58fSAndroid Build Coastguard Worker#if ($foreach.hasNext), #end##
366*d396a58fSAndroid Build Coastguard Worker#end
367*d396a58fSAndroid Build Coastguard Worker```
368*d396a58fSAndroid Build Coastguard Worker
369*d396a58fSAndroid Build Coastguard WorkerSpaces are ignored between the `#` of a directive and the `)` that closes it, so there is no trace
370*d396a58fSAndroid Build Coastguard Workerin the output of the spaces in `#foreach ($product in $allProducts)` or `#if ($foreach.hasNext)`.
371*d396a58fSAndroid Build Coastguard WorkerSpaces are also ignored inside references, such as `$indexme[ $i ]` or `$callme( $i , $j )`.
372*d396a58fSAndroid Build Coastguard Worker
373*d396a58fSAndroid Build Coastguard WorkerIf you are concerned about the detailed formatting of the text from the template, you may want to
374*d396a58fSAndroid Build Coastguard Workerpost-process it. For example, if it is Java code, you could use a formatter such as
375*d396a58fSAndroid Build Coastguard Worker[google-java-format](https://github.com/google/google-java-format). Then you shouldn't have to
376*d396a58fSAndroid Build Coastguard Workerworry about extraneous spaces.
377*d396a58fSAndroid Build Coastguard Worker
378*d396a58fSAndroid Build Coastguard Worker[VelocityHacks]: https://github.com/google/auto/blob/ca2384d5ad15a0c761b940384083cf5c50c6e839/value/src/main/java/com/google/auto/value/processor/TemplateVars.java#L54
379*d396a58fSAndroid Build Coastguard Worker[AutoValue]: https://github.com/google/auto/tree/master/value
380