9.4 Velocimacro Miscellany

Can I use a directive or another Velocimacro as an argument to a Velocimacro?
Example : #center( #bold("hello") )

No. A directive isn't a valid argument to a directive, and for most practical purposes, a Velocimacro is a directive.

However, there are things you can do. One easy solution is to take advantage of the fact that 'doublequote' (") renders its contents. So you could do something like

#set($stuff = "#bold('hello')" )
#center( $stuff )

You can save a step...

#center( "#bold( 'hello' )" )

Please note that in the latter example the arg is evaluated inside the Velocimacro, not at the calling level. In other words, the argument to the Velocimacro is passed in in its entirety and evaluated within the Velocimacro it was passed into. This allows you to do things like :

#macro( inner $foo )
  inner : $foo
#end

#macro( outer $foo )
  #set($bar = "outerlala")
  outer : $foo
#end

#set($bar = 'calltimelala')
#outer( "#inner($bar)" )

Where the output is

Outer : inner : outerlala

because the evaluation of the "#inner($bar)" happens inside #outer(), so the $bar value set inside #outer() is the one that's used.

This is an intentional and jealously guarded feature - args are passed 'by name' into Velocimacros, so you can hand Velocimacros things like stateful references such as

#macro( foo $color )
  <tr bgcolor=$color><td>Hi</td></tr>
  <tr bgcolor=$color><td>There</td></tr>
#end

#foo($bar.rowColor() )

And have rowColor() called repeatedly, rather than just once. To avoid that, invoke the method outside of the Velocimacro, and pass the value into the Velocimacro.

#set($color = $bar.rowColor())
#foo( $color )
Can I register Velocimacros via #parse() ?

Currently, Velocimacros must be defined before they are first used in a template. This means that your #macro() declarations should come before using the Velocimacros.

This is important to remember if you try to #parse() a template containing inline #macro() directives. Because the #parse() happens at runtime, and the parser decides if a Velocimacro-looking element in the template is a Velocimacro at parsetime, #parse()-ing a set of Velocimacro declarations won't work as expected. To get around this, simply use the velocimacro.library facility to have Velocity load your Velocimacros at startup.

What is Velocimacro Autoreloading?

There is a property, meant to be used in development, not production:

velocimacro.library.autoreload

which defaults to false. When set to true along with

<type>.resource.loader.cache = false

(where <type> is the name of the resource loader that you are using, such as 'file') then the Velocity engine will automatically reload changes to your Velocimacro library files when you make them, so you do not have to dump the servlet engine (or application) or do other tricks to have your Velocimacros reloaded.

Here is what a simple set of configuration properties would look like.

file.resource.loader.path = templates
file.resource.loader.cache = false
velocimacro.library.autoreload = true

Don't keep this on in production.