Author: nbubna
Date: Sat Feb 21 05:41:24 2009
New Revision: 746438

URL: http://svn.apache.org/viewvc?rev=746438&view=rev
Log:
VELOCITY-704 initial implementation of scope controls

Modified:
    velocity/engine/trunk/src/java/org/apache/velocity/Template.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Block.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/BlockMacro.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Break.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Directive.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Evaluate.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Include.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Literal.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Parse.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
    
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java

Modified: velocity/engine/trunk/src/java/org/apache/velocity/Template.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/Template.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/Template.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/Template.java Sat Feb 21 
05:41:24 2009
@@ -34,6 +34,9 @@
 import org.apache.velocity.exception.ResourceNotFoundException;
 import org.apache.velocity.exception.TemplateInitException;
 import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.directive.Scope;
+import org.apache.velocity.runtime.directive.StopCommand;
 import org.apache.velocity.runtime.parser.ParseException;
 import org.apache.velocity.runtime.parser.node.SimpleNode;
 import org.apache.velocity.runtime.parser.node.ASTStop.StopThrowable;
@@ -64,6 +67,13 @@
  */
 public class Template extends Resource
 {
+    /*
+     * The name of the variable to use when placing
+     * the scope object into the context.
+     */
+    private String scopeName = "template";
+    private boolean provideScope = true;
+
     private VelocityException errorCondition = null;
 
     /** Default constructor */
@@ -216,6 +226,9 @@
              */
 
             ((SimpleNode)data).init( ica, rsvc);
+
+            String property = 
scopeName+'.'+RuntimeConstants.PROVIDE_SCOPE_CONTROL;
+            provideScope = rsvc.getBoolean(property, provideScope);
         }
         finally
         {
@@ -332,6 +345,10 @@
                 }
             }
 
+            if (provideScope)
+            {
+                ica.put(scopeName, new Scope(this, ica.get(scopeName)));
+            }
             try
             {
                 ica.pushCurrentTemplateName( name );
@@ -339,6 +356,13 @@
 
                 ( (SimpleNode) data ).render( ica, writer);
             }
+            catch (StopCommand stop)
+            {
+                if (!stop.isFor(this))
+                {
+                    throw stop;
+                }
+            }
             catch (StopThrowable st)
             {
               // The stop throwable is thrown by ASTStop (the #stop directive)
@@ -358,6 +382,27 @@
                  */
                 ica.popCurrentTemplateName();
                 ica.setCurrentResource( null );
+
+                if (provideScope)
+                {
+                    Object obj = ica.get(scopeName);
+                    if (obj instanceof Scope)
+                    {
+                        Scope scope = (Scope)obj;
+                        if (scope.getParent() != null)
+                        {
+                            ica.put(scopeName, scope.getParent());
+                        }
+                        else if (scope.getReplaced() != null)
+                        {
+                            ica.put(scopeName, scope.getReplaced());
+                        }
+                        else
+                        {
+                            ica.remove(scopeName);
+                        }
+                    }
+                }
             }
         }
         else

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
 (original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
 Sat Feb 21 05:41:24 2009
@@ -169,6 +169,12 @@
      */
     String EVALUATE_CONTEXT_CLASS = "directive.evaluate.context.class";
 
+    /**
+     * Used to suppress various scope control objects.
+     * @since 1.7
+     */
+    String PROVIDE_SCOPE_CONTROL = "provide.scope.control";
+
     /*
      * ----------------------------------------------------------------------
      *  R E S O U R C E   M A N A G E R   C O N F I G U R A T I O N

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java 
(original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java 
Sat Feb 21 05:41:24 2009
@@ -49,6 +49,8 @@
 import org.apache.velocity.exception.TemplateInitException;
 import org.apache.velocity.exception.VelocityException;
 import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.directive.Scope;
+import org.apache.velocity.runtime.directive.StopCommand;
 import org.apache.velocity.runtime.log.Log;
 import org.apache.velocity.runtime.log.LogManager;
 import org.apache.velocity.runtime.parser.ParseException;
@@ -189,6 +191,11 @@
      */
     private Introspector introspector = null;
 
+    /*
+     * Settings for provision of root scope for evaluate(...) calls.
+     */
+    private String evaluateScopeName = "evaluate";
+    private boolean provideEvaluateScope = true;
 
     /*
      *  Opaque reference to something specificed by the
@@ -255,6 +262,7 @@
             initializeParserPool();
 
             initializeIntrospection();
+            initializeEvaluateScopeSettings();
             /*
              *  initialize the VM Factory.  It will use the properties
              * accessable from Runtime, so keep this here at the end.
@@ -1215,6 +1223,12 @@
         }
     }
 
+    private void initializeEvaluateScopeSettings()
+    {
+        String property = evaluateScopeName+'.'+PROVIDE_SCOPE_CONTROL;
+        provideEvaluateScope = getBoolean(property, provideEvaluateScope);
+    }
+
     /**
      * Renders the input string using the context into the output writer.
      * To be used when a template is dynamically constructed, or want to use
@@ -1344,8 +1358,20 @@
 
             try
             {
+                if (provideEvaluateScope)
+                {
+                    Object previous = ica.get(evaluateScopeName);
+                    context.put(evaluateScopeName, new Scope(this, previous));
+                }
                 nodeTree.render(ica, writer);
-            } 
+            }
+            catch (StopCommand stop)
+            {
+                if (!stop.isFor(this))
+                {
+                    throw stop;
+                }
+            }
             catch (StopThrowable st)
             {
                 // The stop throwable is thrown by ASTStop (the #stop 
directive)
@@ -1362,6 +1388,26 @@
         finally
         {
             ica.popCurrentTemplateName();
+            if (provideEvaluateScope)
+            {
+                Object obj = ica.get(evaluateScopeName);
+                if (obj instanceof Scope)
+                {
+                    Scope scope = (Scope)obj;
+                    if (scope.getParent() != null)
+                    {
+                        ica.put(evaluateScopeName, scope.getParent());
+                    }
+                    else if (scope.getReplaced() != null)
+                    {
+                        ica.put(evaluateScopeName, scope.getReplaced());
+                    }
+                    else
+                    {
+                        ica.remove(evaluateScopeName);
+                    }
+                }
+            }
         }
 
         return true;

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Block.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Block.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Block.java 
(original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Block.java 
Sat Feb 21 05:41:24 2009
@@ -75,6 +75,35 @@
         block = node.jjtGetChild(node.jjtGetNumChildren() - 1);
     }
 
+    public boolean render(InternalContextAdapter context, Writer writer)
+    {
+        preRender(context);
+        try
+        {
+            return block.render(context, writer);
+        }
+        catch (IOException e)
+        {
+            String msg = "Failed to render " + id(context) + " to writer "
+              + " at " + Log.formatFileString(this);
+
+            log.error(msg, e);
+            throw new RuntimeException(msg, e);
+        }
+        catch (StopCommand stop)
+        {
+            if (!stop.isFor(this))
+            {
+                throw stop;
+            }
+            return true;
+        }
+        finally
+        {
+            postRender(context);
+        }
+    }
+
     /**
      * Creates a string identifying the source and location of the block
      * definition, and the current template being rendered if that is
@@ -113,37 +142,26 @@
          */
         public boolean render(InternalContextAdapter context, Writer writer)
         {
-            try
+            depth++;
+            if (depth > parent.maxDepth)
             {
-                depth++;
-                if (depth > parent.maxDepth)
-                {
-                    /* this is only a debug message, as recursion can
-                     * happen in quasi-innocent situations and is relatively
-                     * harmless due to how we handle it here.
-                     * this is more to help anyone nuts enough to intentionally
-                     * use recursive block definitions and having problems
-                     * pulling it off properly.
-                     */
-                    parent.log.debug("Max recursion depth reached for " + 
parent.id(context)
-                        + " at " + Log.formatFileString(parent));
-                    depth--;
-                    return false;
-                }
-                else
-                {
-                    parent.block.render(context, writer);
-                    depth--;
-                    return true;
-                }
+                /* this is only a debug message, as recursion can
+                 * happen in quasi-innocent situations and is relatively
+                 * harmless due to how we handle it here.
+                 * this is more to help anyone nuts enough to intentionally
+                 * use recursive block definitions and having problems
+                 * pulling it off properly.
+                 */
+                parent.log.debug("Max recursion depth reached for " + 
parent.id(context)
+                    + " at " + Log.formatFileString(parent));
+                depth--;
+                return false;
             }
-            catch (IOException e)
+            else
             {
-                String msg = "Failed to render " + parent.id(context) + " to 
writer "
-                  + " at " + Log.formatFileString(parent);
-                
-                parent.log.error(msg, e);
-                throw new RuntimeException(msg, e);
+                parent.render(context, writer);
+                depth--;
+                return true;
             }
         }
 

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/BlockMacro.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/BlockMacro.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/BlockMacro.java
 (original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/BlockMacro.java
 Sat Feb 21 05:41:24 2009
@@ -67,10 +67,19 @@
         this.name = name;
     }
     
-    // This is required, but not actually used.
     public String getName()
     {
-        throw new UnsupportedOperationException("BlockMacro is not actually a 
named macro.");
+        return key;
+    }
+
+    /**
+     * Override to use the macro name, since it is within an
+     * #...@mymacro() ... #end block that the scope in question
+     * would be used.
+     */
+    public String getScopeName()
+    {
+        return name;
     }
 
     /**

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Break.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Break.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Break.java 
(original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Break.java 
Sat Feb 21 05:41:24 2009
@@ -68,6 +68,15 @@
     }
 
     /**
+     * Since there is no processing of content,
+     * there is never a need for an internal scope.
+     */
+    public boolean isScopeProvided()
+    {
+        return false;
+    }
+
+    /**
      *  simple init - init the tree and get the elementKey from
      *  the AST
      * @param rs

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Directive.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Directive.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Directive.java
 (original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Directive.java
 Sat Feb 21 05:41:24 2009
@@ -22,6 +22,7 @@
 import java.io.Writer;
 import java.io.IOException;
 
+import org.apache.velocity.runtime.RuntimeConstants;
 import org.apache.velocity.runtime.RuntimeServices;
 
 import org.apache.velocity.context.InternalContextAdapter;
@@ -37,12 +38,14 @@
  * Base class for all directives used in Velocity.
  *
  * @author <a href="mailto:[email protected]";>Jason van Zyl</a>
+ * @author Nathan Bubna
  * @version $Id$
  */
 public abstract class Directive implements DirectiveConstants, Cloneable
 {
     private int line = 0;
     private int column = 0;
+    private boolean provideScope = true;
     private String templateName;
 
     /**
@@ -112,6 +115,24 @@
     }
 
     /**
+     * @returns the name to be used when a scope control is provided for this
+     * directive.
+     */
+    public String getScopeName()
+    {
+        return getName();
+    }
+
+    /**
+     * @return true if there will be a scope control injected into the context
+     * when rendering this directive.
+     */
+    public boolean isScopeProvided()
+    {
+        return provideScope;
+    }
+
+    /**
      * How this directive is to be initialized.
      * @param rs
      * @param context
@@ -124,10 +145,8 @@
     {
         rsvc = rs;
 
-        //        int i, k = node.jjtGetNumChildren();
-
-        //for (i = 0; i < k; i++)
-        //    node.jjtGetChild(i).init(context, rs);
+        String property = 
getScopeName()+'.'+RuntimeConstants.PROVIDE_SCOPE_CONTROL;
+        this.provideScope = rsvc.getBoolean(property, true);
     }
 
     /**
@@ -145,4 +164,56 @@
                                     Writer writer, Node node )
            throws IOException, ResourceNotFoundException, ParseErrorException,
                 MethodInvocationException;
+
+
+    /**
+     * This creates and places the scope control for this directive
+     * into the context (if scope provision is turned on).
+     */
+    protected void preRender(InternalContextAdapter context)
+    {
+        if (isScopeProvided())
+        {
+            String name = getScopeName();
+            Object previous = context.get(name);
+            context.put(name, new Scope(this, previous));
+        }
+    }
+
+    /**
+     * This cleans up any scope control for this directive after rendering,
+     * assuming the scope control was turned on.
+     */
+    protected void postRender(InternalContextAdapter context)
+    {
+        if (isScopeProvided())
+        {
+            String name = getScopeName();
+            Object obj = context.get(name);
+            
+            // the user can override the scope with a #set,
+            // since that means they don't care about a replaced value
+            // and obviously aren't too keen on their scope control,
+            // and especially since #set is meant to be handled globally,
+            // we'll assume they know what they're doing and not worry
+            // about replacing anything superseded by this directive's scope
+            if (obj instanceof Scope)
+            {
+                Scope scope = (Scope)obj;
+                if (scope.getParent() != null)
+                {
+                    context.put(name, scope.getParent());
+                }
+                else if (scope.getReplaced() != null)
+                {
+                    context.put(name, scope.getReplaced());
+                }
+                else
+                {
+                    context.remove(name);
+                }
+            }
+        }
+    }
+                
 }

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Evaluate.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Evaluate.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Evaluate.java
 (original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Evaluate.java
 Sat Feb 21 05:41:24 2009
@@ -198,11 +198,20 @@
 
                 try 
                 {
+                    preRender(ica);
+
                     /*
                      *  now render, and let any exceptions fly
                      */
                     nodeTree.render( ica, writer );
                 }
+                catch (StopCommand stop)
+                {
+                    if (!stop.isFor(this))
+                    {
+                        throw stop;
+                    }
+                }
                 catch (StopThrowable st)
                 {
                     // The stop throwable is thrown by ASTStop (the #stop 
directive)
@@ -221,12 +230,11 @@
             finally
             {
                 ica.popCurrentTemplateName();
+                postRender(ica);
             }
-
             return true;
         }
 
-        
         return false;
     }
 

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java
 (original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java
 Sat Feb 21 05:41:24 2009
@@ -331,7 +331,18 @@
         Object o = context.get(elementKey);
         Object savedCounter = context.get(counterName);
         Object nextFlag = context.get(hasNextName);
-        
+
+        /*
+         * roll our own scope class instead of using preRender(ctx)'s
+         */
+        ForeachScope foreach = null;
+        if (isScopeProvided())
+        {
+            String name = getScopeName();
+            foreach = new ForeachScope(this, context.get(name));
+            context.put(name, foreach);
+        }
+
         /*
          * Instantiate the null holder context if a null value
          * is returned by the foreach iterator.  Only one instance is
@@ -341,6 +352,13 @@
 
         while (!maxNbrLoopsExceeded && i.hasNext())
         {
+            if (isScopeProvided())
+            {
+                // update the scope control
+                foreach.index++;
+                foreach.hasNext = i.hasNext();
+            }
+
             // TODO: JDK 1.5+ -> Integer.valueOf()
             put(context, counterName , new Integer(counter));
             Object value = i.next();
@@ -366,6 +384,19 @@
                     node.jjtGetChild(3).render(context, writer);
                 }
             }
+            catch (StopCommand stop)
+            {
+                if (stop.isFor(this))
+                {
+                    break;
+                }
+                else
+                {
+                    // clean up first
+                    clean(context, o, savedCounter, nextFlag);
+                    throw stop;
+                }
+            }
             catch (Break.BreakException ex)
             {
                 // encountered #break directive inside #foreach loop
@@ -378,40 +409,43 @@
             // ASSUMPTION: counterInitialValue is not negative!
             maxNbrLoopsExceeded = (counter - counterInitialValue) >= 
maxNbrLoops;
         }
+        clean(context, o, savedCounter, nextFlag);
+        return true;
+    }
 
+    protected void clean(InternalContextAdapter context,
+                         Object o, Object savedCounter, Object nextFlag)
+    {
         /*
-         * restores the loop counter (if we were nested)
-         * if we have one, else just removes
+         *  restores element key if exists
+         *  otherwise just removes
          */
-
-        if (savedCounter != null)
+        if (o != null)
         {
-            context.put(counterName, savedCounter);
+            context.put(elementKey, o);
         }
         else
         {
-            context.remove(counterName);
+            context.remove(elementKey);
         }
 
-
         /*
-         *  restores element key if exists
-         *  otherwise just removes
+         * restores the loop counter (if we were nested)
+         * if we have one, else just removes
          */
-
-        if (o != null)
+        if (savedCounter != null)
         {
-            context.put(elementKey, o);
+            context.put(counterName, savedCounter);
         }
         else
         {
-            context.remove(elementKey);
+            context.remove(counterName);
         }
 
         /*
          * restores the "hasNext" boolean flag if it exists
          */         
-        if( nextFlag != null )
+        if (nextFlag != null)
         {
             context.put(hasNextName, nextFlag);
         }
@@ -420,6 +454,7 @@
             context.remove(hasNextName);
         }
 
-        return true;
+        // clean up after the ForeachScope
+        postRender(context);
     }
 }

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Include.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Include.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Include.java
 (original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Include.java
 Sat Feb 21 05:41:24 2009
@@ -94,6 +94,15 @@
     }
 
     /**
+     * Since there is no processing of content,
+     * there is never a need for an internal scope.
+     */
+    public boolean isScopeProvided()
+    {
+        return false;
+    }
+
+    /**
      *  simple init - init the tree and get the elementKey from
      *  the AST
      * @param rs

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Literal.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Literal.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Literal.java
 (original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Literal.java
 Sat Feb 21 05:41:24 2009
@@ -62,6 +62,15 @@
     }
 
     /**
+     * Since there is no processing of content,
+     * there is never a need for an internal scope.
+     */
+    public boolean isScopeProvided()
+    {
+        return false;
+    }
+
+    /**
      * Store the literal rendition of a node using
      * the Node.literal().
      * @param rs

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java 
(original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java 
Sat Feb 21 05:41:24 2009
@@ -71,6 +71,15 @@
     }
 
     /**
+     * Since this class does no processing of content,
+     * there is never a need for an internal scope.
+     */
+    public boolean isScopeProvided()
+    {
+        return false;
+    }
+
+    /**
      *   render() doesn't do anything in the final output rendering.
      *   There is no output from a #macro() directive.
      * @param context

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Parse.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Parse.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Parse.java 
(original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Parse.java 
Sat Feb 21 05:41:24 2009
@@ -75,6 +75,16 @@
     }
 
     /**
+     * Overrides the default to use "template", so that all templates
+     * can use the same scope reference, whether rendered via #parse
+     * or direct merge.
+     */
+    public String getScopeName()
+    {
+        return "template";
+    }
+
+    /**
      * Return type of this directive.
      * @return The type of this directive.
      */
@@ -247,10 +257,18 @@
         try
         {
             if (!blockinput) {
+                preRender(context);
                 context.pushCurrentTemplateName(arg);
                 ((SimpleNode) t.getData()).render( context, writer );
             }
         }
+        catch( StopCommand stop )
+        {
+            if (!stop.isFor(this))
+            {
+                throw stop;
+            }
+        }
         /**
          * pass through application level runtime exceptions
          */
@@ -273,7 +291,10 @@
         finally
         {
             if (!blockinput)
+            {
                 context.popCurrentTemplateName();
+                postRender(context);
+            }
         }
 
         /*

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
 (original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
 Sat Feb 21 05:41:24 2009
@@ -104,6 +104,17 @@
     }
 
     /**
+     * Override to always return "macro".  We don't want to use
+     * the macro name here, since when writing VTL that uses the
+     * scope, we are within a #macro call.  The macro name will instead
+     * be used as the scope name when defining the body of a BlockMacro.
+     */
+    public String getScopeName()
+    {
+        return "macro";
+    }
+
+    /**
      * Velocimacros are always LINE
      * type directives.
      *
@@ -296,8 +307,17 @@
 
             try
             {
+                preRender(context);
                 return vmProxy.render(context, writer, node, body);
             }
+            catch (StopCommand stop)
+            {
+                if (!stop.isFor(this))
+                {
+                    throw stop;
+                }
+                return true;
+            }
             catch (RuntimeException e)
             {
                 /**
@@ -317,6 +337,10 @@
                   Log.formatFileString(node));
                 throw e;
             }
+            finally
+            {
+                postRender(context);
+            }
         }
         else if (strictRef)
         {

Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java?rev=746438&r1=746437&r2=746438&view=diff
==============================================================================
--- 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
 (original)
+++ 
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
 Sat Feb 21 05:41:24 2009
@@ -29,6 +29,7 @@
 import org.apache.velocity.exception.TemplateInitException;
 import org.apache.velocity.exception.VelocityException;
 import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.directive.StopCommand;
 import org.apache.velocity.runtime.parser.Parser;
 import org.apache.velocity.util.ClassUtils;
 import org.apache.velocity.util.introspection.Info;
@@ -212,18 +213,21 @@
     private Object handleInvocationException(Object o, InternalContextAdapter 
context, Throwable t)
     {
         /*
+         * We let StopCommands go up to the directive they are for/from
+         */
+        if (t instanceof StopCommand)
+        {
+            throw (StopCommand)t;
+        }
+
+        /*
          *  In the event that the invocation of the method
          *  itself throws an exception, we want to catch that
          *  wrap it, and throw.  We don't log here as we want to figure
          *  out which reference threw the exception, so do that
          *  above
          */
-
-        /*
-         *  let non-Exception Throwables go...
-         */
-
-        if (t instanceof Exception)
+        else if (t instanceof Exception)
         {
             try
             {
@@ -245,6 +249,10 @@
                     e, methodName, getTemplateName(), this.getLine(), 
this.getColumn());
             }
         }
+
+        /*
+         *  let non-Exception Throwables go...
+         */
         else
         {
             /*


Reply via email to