On Thu, Mar 6, 2008 at 6:21 AM, Deinhammer, Guido <[EMAIL PROTECTED]> wrote: > 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.
i thought this at first, but i'm not so sure now. taking a map of arguments isn't the only difference. having a chained context, setting a base directory (unique from the resource loader system), and taking the first arg as a literal #call( foo ) instead of a string #parse( "foo.vm" ). Regarding #callBlock, there's been talk of a #macroblock too. I wonder if we should just focus on a #block( foo ) here's da block #end directive to define blocks, and leave the user to pass the blocks into the macro or #call on their own. > 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. true. that might be useful in general. Will, how would these ideas fit with your IncludeEventHandler? > 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. I can't really see that ever being part of a standard distribution. Also, it could be probably done easily as a tool (or extension of/addition to the ContextTool). > 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] > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]