EMMA Coverage Report (generated Tue May 18 22:13:27 CDT 2004)
[all classes][org.apache.velocity.runtime.directive]

COVERAGE SUMMARY FOR SOURCE FILE [Macro.java]

nameclass, %method, %block, %line, %
Macro.java100% (1/1)100% (9/9)66%  (151/229)82%  (40/49)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Macro100% (1/1)100% (9/9)66%  (151/229)82%  (40/49)
getArgArray (Node): String [] 100% (1/1)51%  (46/90)71%  (12/17)
processAndRegister (RuntimeServices, Node, String): void 100% (1/1)62%  (55/89)75%  (12/16)
<static initializer> 100% (1/1)100% (3/3)100% (1/1)
Macro (): void 100% (1/1)100% (3/3)100% (1/1)
getASTAsStringArray (Node): List 100% (1/1)100% (32/32)100% (9/9)
getName (): String 100% (1/1)100% (2/2)100% (1/1)
getType (): int 100% (1/1)100% (2/2)100% (1/1)
init (RuntimeServices, InternalContextAdapter, Node): void 100% (1/1)100% (6/6)100% (2/2)
render (InternalContextAdapter, Writer, Node): boolean 100% (1/1)100% (2/2)100% (1/1)

1package org.apache.velocity.runtime.directive;
2 
3/*
4 * Copyright 2000-2002,2004 The Apache Software Foundation.
5 * 
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 * 
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 * 
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 
19import java.io.Writer;
20import java.io.IOException;
21 
22import java.util.List;
23import java.util.ArrayList;
24 
25import org.apache.velocity.context.InternalContextAdapter;
26 
27import org.apache.velocity.runtime.parser.node.Node;
28import org.apache.velocity.runtime.parser.node.NodeUtils;
29import org.apache.velocity.runtime.parser.Token;
30import org.apache.velocity.runtime.parser.ParseException;
31import org.apache.velocity.runtime.parser.ParserTreeConstants;
32import org.apache.velocity.runtime.RuntimeServices;
33 
34/**
35 *   Macro.java
36 *
37 *  Macro implements the macro definition directive of VTL.
38 *
39 *  example :
40 *
41 *  #macro( isnull $i )
42 *     #if( $i )
43 *         $i
44 *      #end
45 *  #end
46 *
47 *  This object is used at parse time to mainly process and register the 
48 *  macro.  It is used inline in the parser when processing a directive.
49 *
50 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
51 * @version $Id: Macro.java,v 1.16.4.1 2004/03/03 23:22:56 geirm Exp $
52 */
53public class Macro extends Directive
54{
55    private static  boolean debugMode = false;
56 
57    /**
58     * Return name of this directive.
59     */
60    public String getName()
61    {
62        return "macro";
63    }        
64    
65    /**
66     * Return type of this directive.
67     */
68    public int getType()
69    {
70        return BLOCK;
71    }        
72    
73    /**
74     *   render() doesn't do anything in the final output rendering.
75     *   There is no output from a #macro() directive.
76     */
77    public boolean render(InternalContextAdapter context,
78                           Writer writer, Node node)
79        throws IOException 
80    {
81        /*
82         *  do nothing : We never render.  The VelocimacroProxy object does that
83         */
84 
85        return true;
86    }
87 
88    public void init(RuntimeServices rs, InternalContextAdapter context,
89                     Node node)
90       throws Exception
91    {
92        super.init(rs, context, node);
93 
94        /*
95         * again, don't do squat.  We want the AST of the macro 
96         * block to hang off of this but we don't want to 
97         * init it... it's useless...
98         */
99     
100        return;
101    }
102 
103    /**
104     *  Used by Parser.java to process VMs withing the parsing process
105     *
106     *  processAndRegister() doesn't actually render the macro to the output
107     *  Processes the macro body into the internal representation used by the
108     *  VelocimacroProxy objects, and if not currently used, adds it
109     *  to the macro Factory
110     */ 
111    public static void processAndRegister(RuntimeServices rs,  Node node,
112                                          String sourceTemplate)
113        throws IOException, ParseException
114    {
115        /*
116         *  There must be at least one arg to  #macro,
117         *  the name of the VM.  Note that 0 following 
118         *  args is ok for naming blocks of HTML
119         */
120 
121        int numArgs = node.jjtGetNumChildren();
122 
123        /*
124         *  this number is the # of args + 1.  The + 1
125         *  is for the block tree
126         */
127 
128        if (numArgs < 2) 
129        {
130            
131            /*
132             *  error - they didn't name the macro or
133             *  define a block
134             */
135            
136            rs.error("#macro error : Velocimacro must have name as 1st " + 
137                "argument to #macro(). #args = " + numArgs);
138 
139            throw new MacroParseException("First argument to #macro() must be " +
140                    " macro name.");
141        }
142 
143        /*
144         *  lets make sure that the first arg is an ASTWord
145         */
146 
147        int firstType = node.jjtGetChild(0).getType();
148 
149        if(firstType != ParserTreeConstants.JJTWORD)
150        {
151            Token t = node.jjtGetChild(0).getFirstToken();
152 
153            throw new MacroParseException("First argument to #macro() must be a"
154                    + " token without surrounding \' or \", which specifies"
155                    + " the macro name.  Currently it is a "
156                    + ParserTreeConstants.jjtNodeName[firstType]);
157 
158        }
159 
160        /*
161         *  get the arguments to the use of the VM
162         */
163 
164        String argArray[] = getArgArray(node);
165         
166        /*
167         *   now, try and eat the code block. Pass the root.
168         */
169        
170        List macroArray = 
171            getASTAsStringArray(node.jjtGetChild(numArgs - 1));
172  
173        /*
174         *  make a big string out of our macro
175         */
176  
177        StringBuffer temp  = new StringBuffer();
178 
179        for (int i=0; i < macroArray.size(); i++)
180        {
181            temp.append(macroArray.get(i));
182        }
183 
184        String macroBody = temp.toString();
185   
186        /*
187         * now, try to add it.  The Factory controls permissions, 
188         * so just give it a whack...
189         */
190 
191        boolean bRet = rs.addVelocimacro(argArray[0], macroBody,
192                        argArray, sourceTemplate);
193 
194        return;
195    }
196 
197  
198    /**
199     *  creates an array containing the literal
200     *  strings in the macro arguement
201     */
202    private static String[] getArgArray(Node node)
203    {
204        /*
205         *  remember : this includes the block tree
206         */
207        
208        int numArgs = node.jjtGetNumChildren();
209        
210        numArgs--;  // avoid the block tree...
211        
212        String argArray[] = new String[numArgs];
213        
214        int i = 0;
215        
216        /*
217         *  eat the args
218         */
219        
220        while (i < numArgs)
221        {
222            argArray[i] = node.jjtGetChild(i).getFirstToken().image;
223 
224            /*
225             *  trim off the leading $ for the args after the macro name.
226             *  saves everyone else from having to do it
227             */
228 
229            if (i > 0)
230            {
231                if (argArray[i].startsWith("$"))
232                {
233                    argArray[i] = argArray[i]
234                        .substring(1, argArray[i].length());
235                }
236            }
237 
238            i++;
239        }
240        
241        if (debugMode)
242        {
243            System.out.println("Macro.getArgArray() : #args = " + numArgs);
244            System.out.print(argArray[0] + "(");
245            
246            for (i = 1; i < numArgs; i++)
247            {
248                System.out.print(" " + argArray[i]);
249            }
250 
251            System.out.println(" )");
252        }
253        
254        return argArray;
255    }
256 
257    /**
258     *  Returns an array of the literal rep of the AST
259     */
260    private static List getASTAsStringArray(Node rootNode)
261    {
262        /*
263         *  this assumes that we are passed in the root 
264         *  node of the code block
265         */
266        
267        Token t = rootNode.getFirstToken();
268        Token tLast = rootNode.getLastToken();
269 
270        /*
271         *  now, run down the part of the tree bounded by
272         *  our first and last tokens
273         */
274 
275        ArrayList list = new ArrayList();
276 
277        t = rootNode.getFirstToken();
278 
279        while (t != tLast)
280        {
281            list.add(NodeUtils.tokenLiteral(t));
282            t = t.next;
283        }
284 
285        /*
286         *  make sure we get the last one...
287         */
288 
289        list.add(NodeUtils.tokenLiteral(t));
290 
291        return list;
292    }
293}

[all classes][org.apache.velocity.runtime.directive]
EMMA 2.0.4015 (stable) (C) Vladimir Roubtsov