Even if the expression passed to evaluate is small, it will still go to
a JavaCC parser, means the call is overloaded with unnecessary
operations. Unnecessary because there is no expression involved here,
the macro parameters are already in the node parameter when /public
boolean render( InternalContextAdapter context, Writer writer, Node
node)/ is invoked for the #call directive.

In a custom directive you can always get a reference to a macro with

/VelocimacroProxy velocimacro = (VelocimacroProxy) 
rsvc.getVelocimacro(macroName, context.getCurrentTemplateName());/

but this is not initialized. If you call 'render' it will throw a NPE
since nodeTree is initialized by init(). A VelocimacroProxy is
initialized during parsing, when the parser finds  #XXX(...), but in
this case I should initialize the macro before the call. The problem is,
calling init will bring a parsing operation of the macro body(every time
when a call is done).

It's not clear for me, I don't have the big picture, but it seems
Velocity it is optimized for early binding, when a template is
"compiled" it knows exactly what to call to apply the template as faster
as possible.

Massip, Etienne wrote:
A dynamic call of a parameter-given name is a minimal parsing, but still is, preventing 
any kind of "compile-time linkage" from being done.

The "expression" seems to be known only at template-parsing-time, isn't it ?

I think

#call('render'+$component.type $component)

makes very little difference with

#evaluate('#render' + $component.type + '($component)')

If the evaluate directive really performs poorly, then maybe it should be a 
good idea to speed it up other than create a new and specialized one ?

-----Message d'origine-----
De : Adrian Tarau [mailto:[EMAIL PROTECTED]
Envoyé : mardi 19 février 2008 16:14
À : Velocity Developers List
Objet : Re: Call a velocity macro

Velocity.evaluate or Velocity.invokeVelocimacro(which calls evaluate) doesn't 
provide support to pass objects as parameters and is not suitable to be called 
from a template.

The new directive #evaluate is actually Velocity.evaluate.  It is still an 
evaluate, which means expression parsing. I would like to avoid that.
If you will call "call/invoke" directive too often I think it will perform 
badly, due the fact that a parsing step is performed.

In this case, a call to a velocity macro, we don't need the parsing step. We know the 
"expression", and what we need is to prepare the node without parsing.I don't 
know much about the velocity internals, but I presume it should be possible.
And I think such a directive should be part of the core, I mean it will be easy to 
implement a "switch"(is what I need actually) based on some variable. Like in 
my case :

#macro(renderLabel $component)
....
#end

#macro(renderTextField $component)
....
#end

#macro(renderRadioButton $component)
....
#end

.....

#call('render'+$component.type $component)

where 'type' is 'label', 'text-field', 'radio-button'(of course there is a 
normalization of the type value, first character upper case, '-' makes the next 
character uppercase, etc).

Instead of lots of tests with #if, it will be better(and faster) to have this 
'switch'.At least it looks better, the template is cleaner and it is (it will 
be)also faster.

Thanks.

        /Reader reader = *new* BufferedReader(*new* StringReader(sourceText));
        String templateName = context.getCurrentTemplateName();
        SimpleNode nodeTree = *null*;

        *try*
        {
            *nodeTree* = rsvc.parse(reader, templateName);
        }
        *catch* (ParseException pex)
        {
            //// use the line/column from the template
            Info info = *new* Info( templateName, node.getLine(), 
node.getColumn() );
            *throw*  *new* ParseErrorException( pex.getMessage(), info );
        }
        *catch* (TemplateInitException pex)
        {
            Info info = *new* Info( templateName, node.getLine(), 
node.getColumn() );
            *throw*  *new* ParseErrorException( pex.getMessage(), info );
        }/



Massip, Etienne wrote:

Hello

Take a look at the actual RenderTool 
(http://velocity.apache.org/tools/releases/1.4/generic/RenderTool.html).

Or at the new evaluate directive, although still in developement 
(http://velocity.apache.org/engine/devel/vtl-reference-guide.html#aevaluate_-_dynamically_evaluates_a_string_or_reference).

Etienne

-----Message d'origine-----
De : Adrian Tarau [mailto:[EMAIL PROTECTED] Envoyé : mardi 19
février 2008 07:29 À : dev@velocity.apache.org Objet : Call a velocity
macro

Hello,



I have the following problem : I would like to call a macro but the macro name 
must be a variable.



Ex: instead of #renderLabel($component) to have #call("renderLabel"
$component) - of course "renderLabel" can be any (existing) macro name.



I started to create a directive #call, but of course the render method
fails because the nodeTree is not initialized. nodeTree is initialized
during parsing like this



public class ASTDirective extends SimpleNode {



...

           directive = rsvc.getVelocimacro( directiveName,
context.getCurrentTemplateName());



            try

            {

                directive.init( rsvc, context, this );

            }



..

{





Any thoughts? I think such a directive is very useful, I don't know why is not 
part of the library.

Thanks.



CallDirective source code :



public class CallDirective extends Directive {



    public String getName() {

        return "call";

    }



    public int getType() {

        return LINE;

    }



    public boolean render(InternalContextAdapter context, Writer
writer, Node node) throws IOException, ResourceNotFoundException,
ParseErrorException, MethodInvocationException {

        if (node.jjtGetNumChildren() < 1) {

            rsvc.error("#" + getName() + " : invalid number of
parameters, must be at least the macro name and 0..N parameters");

            return false;

        }

        String macroName = (String)
node.jjtGetChild(0).value(context);

        VelocimacroProxy velocimacro = (VelocimacroProxy)
rsvc.getVelocimacro(macroName, context.getCurrentTemplateName());

        if (velocimacro == null) {

            rsvc.error("A macro with name '" + macroName + " in
context '" +
context.getCurrentTemplateName() + "' doesn't exists");

            return false;

        }

        return velocimacro.render(context, writer, node);

    }

}


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



Reply via email to