Coverage Report - org.webmacro.directive.ForeachDirective
 
Classes in this File Line Coverage Branch Coverage Complexity
ForeachDirective
51%
36/70
26%
10/38
7.5
 
 1  
 /*
 2  
  * Copyright (C) 1998-2000 Semiotek Inc.  All Rights Reserved.
 3  
  *
 4  
  * Redistribution and use in source and binary forms, with or without
 5  
  * modification, are permitted under the terms of either of the following
 6  
  * Open Source licenses:
 7  
  *
 8  
  * The GNU General Public License, version 2, or any later version, as
 9  
  * published by the Free Software Foundation
 10  
  * (http://www.fsf.org/copyleft/gpl.html);
 11  
  *
 12  
  *  or
 13  
  *
 14  
  * The Semiotek Public License (http://webmacro.org/LICENSE.)
 15  
  *
 16  
  * This software is provided "as is", with NO WARRANTY, not even the
 17  
  * implied warranties of fitness to purpose, or merchantability. You
 18  
  * assume all risks and liabilities associated with its use.
 19  
  *
 20  
  * See www.webmacro.org for more information on the WebMacro project.
 21  
  */
 22  
 
 23  
 package org.webmacro.directive;
 24  
 
 25  
 import java.io.IOException;
 26  
 import java.util.Iterator;
 27  
 
 28  
 import org.webmacro.Context;
 29  
 import org.webmacro.FastWriter;
 30  
 import org.webmacro.Macro;
 31  
 import org.webmacro.PropertyException;
 32  
 import org.webmacro.TemplateVisitor;
 33  
 import org.webmacro.engine.Block;
 34  
 import org.webmacro.engine.BuildContext;
 35  
 import org.webmacro.engine.BuildException;
 36  
 import org.webmacro.engine.Expression;
 37  
 import org.webmacro.engine.UndefinedMacro;
 38  
 import org.webmacro.engine.Variable;
 39  
 
 40  
 /**
 41  
  * Implements iteration through a list or an array with
 42  
  * various options.
 43  
  */
 44  142
 public class ForeachDirective extends Directive
 45  
 {
 46  
 
 47  
     private static final int FOREACH_TARGET = 1;
 48  
     private static final int FOREACH_IN_K = 2;
 49  
     private static final int FOREACH_LIST = 3;
 50  
     private static final int FOREACH_BODY = 4;
 51  
     private static final int FOREACH_INDEXING_K = 5;
 52  
     private static final int FOREACH_INDEX = 6;
 53  
     private static final int FOREACH_LIMIT_K = 7;
 54  
     private static final int FOREACH_LIMIT = 8;
 55  
     private static final int FOREACH_FROM_K = 9;
 56  
     private static final int FOREACH_FROM = 10;
 57  
 
 58  2
     private static final UndefinedMacro UNDEF = UndefinedMacro.getInstance();
 59  
 
 60  
     private Variable target, index;
 61  
     private Object list, indexFromExpr, limitExpr;
 62  
     private Macro body;
 63  
 
 64  
     // Syntax:
 65  
     // #foreach list-var in list-expr
 66  
     //   [ limit n ] [ indexing $i [ from m ] ]
 67  
     // { block }
 68  
 
 69  
     private static final ArgDescriptor[]
 70  2
             myArgs = new ArgDescriptor[]{
 71  
                 new LValueArg(FOREACH_TARGET),
 72  
                 new KeywordArg(FOREACH_IN_K, "in"),
 73  
                 new RValueArg(FOREACH_LIST),
 74  
                 new OptionChoice(2),
 75  
                 new OptionalGroup(3),
 76  
                 new KeywordArg(FOREACH_INDEXING_K, "indexing"),
 77  
                 new LValueArg(FOREACH_INDEX),
 78  
                 new OptionalGroup(2),
 79  
                 new KeywordArg(FOREACH_FROM_K, "from"),
 80  
                 new RValueArg(FOREACH_FROM),
 81  
                 new OptionalGroup(2),
 82  
                 new KeywordArg(FOREACH_LIMIT_K, "limit"),
 83  
                 new RValueArg(FOREACH_LIMIT),
 84  
                 new BlockArg(FOREACH_BODY)
 85  
             };
 86  
 
 87  
     private static final DirectiveDescriptor
 88  2
             myDescr = new DirectiveDescriptor("foreach", null, myArgs, null);
 89  
 
 90  
     public static DirectiveDescriptor getDescriptor ()
 91  
     {
 92  6
         return myDescr;
 93  
     }
 94  
 
 95  
     public Object build (DirectiveBuilder builder,
 96  
                          BuildContext bc)
 97  
             throws BuildException
 98  
     {
 99  
         try
 100  
         {
 101  142
             target = (Variable) builder.getArg(FOREACH_TARGET, bc);
 102  142
             index = (Variable) builder.getArg(FOREACH_INDEX, bc);
 103  
         }
 104  0
         catch (ClassCastException e)
 105  
         {
 106  0
             throw new NotVariableBuildException(myDescr.name, e);
 107  142
         }
 108  142
         list = builder.getArg(FOREACH_LIST, bc);
 109  142
         body = (Block) builder.getArg(FOREACH_BODY, bc);
 110  142
         indexFromExpr = builder.getArg(FOREACH_FROM, bc);
 111  142
         limitExpr = builder.getArg(FOREACH_LIMIT, bc);
 112  142
         return this;
 113  
     }
 114  
 
 115  
     public void write (FastWriter out, Context context)
 116  
             throws PropertyException, IOException
 117  
     {
 118  
 
 119  
         Object l, limit, from;
 120  2168
         int loopLimit = -1, loopStart = 1, loopIndex = 0;
 121  
 
 122  2168
         l = list;
 123  4336
         while (l instanceof Macro && l != UNDEF)
 124  2168
             l = ((Macro) l).evaluate(context);
 125  
 
 126  2168
         if (limitExpr != null)
 127  
         {
 128  0
             limit = limitExpr;
 129  0
             while (limit instanceof Macro && limit != UNDEF)
 130  0
                 limit = ((Macro) limit).evaluate(context);
 131  0
             if (Expression.isNumber(limit))
 132  0
                 loopLimit = (int) Expression.numberValue(limit);
 133  
             else
 134  
             {
 135  0
                 String warning = "#foreach: Cannot evaluate limit";
 136  0
                 writeWarning(warning, context, out);
 137  
             }
 138  
         }
 139  
 
 140  2168
         if (index != null && indexFromExpr != null)
 141  
         {
 142  0
             from = indexFromExpr;
 143  0
             while (from instanceof Macro && from != UNDEF)
 144  0
                 from = ((Macro) from).evaluate(context);
 145  0
             if (Expression.isNumber(from))
 146  0
                 loopStart = (int) Expression.numberValue(from);
 147  
             else
 148  
             {
 149  0
                 String warning = "#foreach: Cannot evaluate loop start";
 150  0
                 writeWarning(warning, context, out);
 151  
             }
 152  
         }
 153  
 
 154  
         Iterator iter;
 155  
         try
 156  
         {
 157  2168
             iter = context.getBroker()._propertyOperators.getIterator(l);
 158  
         }
 159  4
         catch (Exception e)
 160  
         {
 161  4
             String warning = "#foreach: ";
 162  4
             if (list instanceof Variable)
 163  4
                 warning += "$" + ((Variable) list).getVariableName();
 164  
             else
 165  0
                 warning += list;
 166  
 
 167  4
             warning += ": " + e.getMessage();
 168  4
             writeWarning(warning, context, out);
 169  0
             return;
 170  2164
         }
 171  
         while (iter.hasNext()
 172  21980
                 && ((loopLimit == -1)
 173  
                 || (loopLimit > loopIndex)))
 174  
         {
 175  
             try
 176  
             {
 177  19818
                 target.setValue(context, iter.next());
 178  19816
                 if (index != null)
 179  0
                     index.setValue(context, new Integer(loopIndex + loopStart));
 180  
             }
 181  0
             catch (PropertyException e)
 182  
             {
 183  0
                 String errorText = "#foreach: Unable to set list index";
 184  0
                 writeWarning(errorText, context, out);
 185  
             }
 186  2
             catch (Exception e)
 187  
             {
 188  2
                 throw new PropertyException("Unable to iterate list", e);
 189  19816
             }
 190  19816
             body.write(out, context);
 191  19816
             ++loopIndex;
 192  
         }
 193  2162
     }
 194  
 
 195  
     public void accept (TemplateVisitor v)
 196  
     {
 197  0
         v.beginDirective(myDescr.name);
 198  0
         v.visitDirectiveArg("ForeachTarget", target);
 199  0
         v.visitDirectiveArg("ForeachList", list);
 200  0
         if (index != null)
 201  0
             v.visitDirectiveArg("ForeachIndex", index);
 202  0
         if (indexFromExpr != null)
 203  0
             v.visitDirectiveArg("ForeachFrom", indexFromExpr);
 204  0
         if (limitExpr != null)
 205  0
             v.visitDirectiveArg("ForeachLimit", limitExpr);
 206  0
         v.visitDirectiveArg("ForeachBlock", body);
 207  0
         v.endDirective();
 208  0
     }
 209  
 
 210  
 }