##### Coverage Report - org.webmacro.directive.ForeachDirective

Classes in this File | Line Coverage | Branch Coverage | Complexity
ForeachDirective |
51% | 36/70
26% | 10/38
| 7.5;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 |  |
     }