Hi Chris,

You are right - for a solution that is part of the standard, it would be
better to use a nested context to avoid the "args." prefix. I already
used macros with only one args parameter - so for me it didn't make
sense to do this.

When adding this functionality, I think it would be best to just add an
optional map parameter to the parse directive - this way users don't
have to learn any new directive and it would be easy to adopt this
feature. Also setting a different base directory for where parse takes
the templates from would be useful. This way you can keep the reusable
code in one place and you don't have to write the full path when using
the parse directive.

Since you are adding the arguments to the context, it might make sense
to create another directive - something like #default that takes a map
and defaults variables in the context to map entries. When you have many
parameters for a macro, being able to efficiently set default values is
crucial.

To allow a content to be rendered (what I did with #callBlock and
#content), you will need a new directive since it has to be a
blockDirective.

You wrote:
I think you can choose to use the wrapped versus outer context however
you want... I did not really understand why this was true:

>     // the callStack is needed for the ContentDirective - when the
content is rendered,
>     // we have to move one level back in the callStack

This is because when you render the content of the callBlock directive
(using #content), you have to reset the args map to what it was before
the directive was called - it's essential for nested callBlock
statements and recursions. But it should be possible to do the same
thing with nested contexts. 

Frankly I don't have much time now to contribute a lot to the project -
I am just sharing what I've done. If that functionality makes it into
the base product I think it would be a great enhancement.

Cheers,

Guido

-----Original Message-----
From: Christopher Schultz [mailto:[EMAIL PROTECTED] 
Sent: Wednesday, March 05, 2008 9:00 PM
To: Velocity Developers List
Subject: Re: A simple macro replacement with user directives

Guido,

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

It definitely is. Thanks for investigating /and providing code/!

> 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.

What about wrapping the current VelocityContext in another one that
contains the argument map? That would allow you to use your template
either through your #call directive or with #parse (because it would
remove the need for the "$args." prefix).

It would be an easy fix. Starting with CallDirective.java:120:

>     Object oldArgs = context.put(ARGUMENTS_VARIABLE_NAME, args);

Change this to:

       // Wrap the outer context with a new one
       Context subContext = new VelocityContext(context);

       // Copy the arguments into the inner context
       for(Iterator i=args.entrySet().iterator(); i.hasNext(); ) {
           Map.Entry entry = (Map.Entry)i.next();
           subContext.put((String)entry.getKey(), entry.getValue());
       }

I think you can choose to use the wrapped versus outer context however
you want... I did not really understand why this was true:

>     // the callStack is needed for the ContentDirective - when the
content is rendered,
>     // we have to move one level back in the callStack

... so it's up to you. ;)

Of course, you'd want to use the wrapped context, here:

>       template.merge(context, writer);

        template.merge(subContext, writer);

And this line is unnecessary, since subContext will simply fall out of
scope:

>     context.put(ARGUMENTS_VARIABLE_NAME, oldArgs);

I'm also not sure about the push and pop of template names if you use a
wrapped context. I don't know enough about the internals of Velocity to
know if they are required or not.

Let me know if you think these are reasonable improvements.

-chris



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to