velocity-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Deinhammer, Guido" <GDeinham...@thegoldensource.com>
Subject A simple macro replacement with user directives
Date Wed, 05 Mar 2008 13:53:19 GMT
Hi,

I followed the discussion here on Macros - and thought you might be
interested in what I have done to overcome most of their shortcomings.

I understand my writing turned out a little lengthy, but if you are
using macros, it should be worth the read...

Basically I am working on a web-based UI and we use velocity to render
html. We have a number of fairly complex macros - some are recursive -
and when I did a check on the memory consumption that finally made me
rethink whether velocity is suited to what we do at all. The problem is
that it includes the parsed nodetree of a macro wherever it is called
(https://issues.apache.org/jira/browse/VELOCITY-223). In our project
that resulted in up to 10MB of heap memory for a screen and we have
around 800 of them. This would mean that we can cache only around 15
screens in the ResourceCache.
This finally made me change all our (mostly generated) velocity
templates.
Before that there were a few other inconveniences that we got used to -
parameter passing is not ideal - we have often well over 20 parameters
many of them can be defaulted, so the normal macro parameters are not
very useful for us - but that is easy enough to work around - just pass
a single map to your macro - and inside the macro you can use a Java
tool or a user directive to default the values in the argument map with
values of a second - defaultValue map.
That made the maros a lot easier to use for us - but the memory problem
remains.
Another problem was that the caller cannot pass a body, or velocity
markup to the macro - that would be very convenient if you want to
implement e.g. a collapsible section
(https://issues.apache.org/jira/browse/VELOCITY-558 or
https://issues.apache.org/jira/browse/VELOCITY-583)

Other's reported using a variable for the name of the macro doesn't
work. 

So I thought instead of using a macro call I could just implement a
directive that renders another .vm file with the same context and the
same Writer - similar to parse but with the option of passing
parameters. So that's what I did. And with the three directives I have
attached you can do something like this:

#call($myMacro {"arg1": true, "arg2":false})

The $myMacro variable has to resolve to a fileName (you can set the
directory for this, so you don't have to give the full path, and you can
skip the .vm ending). The second parameter is a map that is added to the
context under the name "args" - the "macro" can access the parameters
with $args.arg1. The "macro" itself, is nothing but a .vm file 

You can also do this:

#callBlock(collapsibleSection {"isCollapsed":$collapsed, "title":"My
Section"})
 My section content.....
#end

Where your collapsibleSection.vm file could look like this:

<table><th><td>$args.title</td></th>
#if($args.open)
  #content()
#end
</table>
#end

Where the #content() directive will just render the body of the
callBlock directive - in this case " My section content.....".


So have a look at the attached code, if you have similar problems with
macros - it is quite short and should be easy to understand.
Maybe something like this should be added for the 1.6 version - or the
whole macro concept could be converted to a solution like that - leaving
the existing syntax intact.


Best regards,

Guido Deinhammer

Btw: we have also added another cool directive that allows partial page
rendering...but I didn't have time to write it up yet...

Mime
View raw message