ok, so here's my current thought. since we've already changed this in
the last production release, i'm hesitant to just "change our mind"
and leave the VELOCITY-285 advocates hanging. so, here's two options
i think i'd be comfortable with:
1:
Index: ../src/java/org/apache/velocity/runtime/directive/Foreach.java
===================================================================
--- ../src/java/org/apache/velocity/runtime/directive/Foreach.java
(revision 701169)
+++ ../src/java/org/apache/velocity/runtime/directive/Foreach.java
(working copy)
@@ -247,6 +247,15 @@
}
/**
+ * Extension hook to allow VELOCITY-285 behavior by overriding
+ * and using context.localPut(key, value). See VELOCITY-630.
+ */
+ protected void put(InternalContextAdapter context, String key,
Object value)
+ {
+ context.put(key, value);
+ }
+
+ /**
* renders the #foreach() block
* @param context
* @param writer
@@ -325,11 +334,11 @@
while (!maxNbrLoopsExceeded && i.hasNext())
{
- // TODO: JDK 1.4+ -> Integer.valueOf()
- context.localPut(counterName , new Integer(counter));
- context.localPut(hasNextName,
Boolean.valueOf(i.hasNext()));
+ // TODO: JDK 1.5+ -> Integer.valueOf()
+ put(context, counterName , new Integer(counter));
+ put(context, hasNextName, Boolean.valueOf(i.hasNext()));
Object value = i.next();
- context.localPut(elementKey, value);
+ put(context, elementKey, value);
or 2:
Index: ../src/java/org/apache/velocity/runtime/directive/Foreach.java
===================================================================
--- ../src/java/org/apache/velocity/runtime/directive/Foreach.java
(revision 701169)
+++ ../src/java/org/apache/velocity/runtime/directive/Foreach.java
(working copy)
@@ -177,6 +177,11 @@
private boolean skipInvalidIterator;
/**
+ * Whether or not [EMAIL PROTECTED] #put} uses context.put or
context.localPut
+ */
+ private boolean strictPassByName;
+
+ /**
* The reference name used to access each
* of the elements in the list object. It
* is the $item in the following:
@@ -217,6 +222,7 @@
}
skipInvalidIterator =
rsvc.getBoolean(RuntimeConstants.SKIP_INVALID_ITERATOR,
true);
+ strictPassByName =
rsvc.getBoolean(RuntimeConstants.STRICT_FOREACH_PASS_BY_NAME, true);
/*
* this is really the only thing we can do here as everything
@@ -247,6 +253,22 @@
}
/**
+ * Controls whether loop vars are set locally or generally. See
VELOCITY-630
+ * and VELOCITY-285.
+ */
+ protected void put(InternalContextAdapter context, String key,
Object value)
+ {
+ if (strictPassByName)
+ {
+ context.put(key, value);
+ }
+ else
+ {
+ context.localPut(key, value);
+ }
+ }
+
+ /**
* renders the #foreach() block
* @param context
* @param writer
@@ -325,11 +347,11 @@
while (!maxNbrLoopsExceeded && i.hasNext())
{
- // TODO: JDK 1.4+ -> Integer.valueOf()
- context.localPut(counterName , new Integer(counter));
- context.localPut(hasNextName,
Boolean.valueOf(i.hasNext()));
+ // TODO: JDK 1.5+ -> Integer.valueOf()
+ put(context, counterName , new Integer(counter));
+ put(context, hasNextName, Boolean.valueOf(i.hasNext()));
Object value = i.next();
- context.localPut(elementKey, value);
+ put(context, elementKey, value);
On Tue, Oct 14, 2008 at 9:40 PM, Nathan Bubna <[EMAIL PROTECTED]>
wrote:
hmm. i suppose that makes sense... of course, i'm too tired to think
straight right now. let me re-examine this tomorrow.
On Tue, Oct 14, 2008 at 6:39 PM, Byron Foster <[EMAIL PROTECTED]> wrote:
So I looked into this some more and here is the deal. This bug was
introduced with VELOCITY-285. The solution to 285 was to make the
#foreach
index variable forced to local scope, which introduced bug
VELOCITY-630.
However, I assert that 285 was never a bug!
Given the following VTL:
#macro(dig $x)
x1: $x
#foreach($i in $x)
x2 $x
#dig($i)
#end
#end
#dig([[1,2],[3,4]])
The premiss of 285 is that reference $x at x1: and x2: should
render with
the same value. However, in a pass by name world this is not
true. On at
least the second recursion level to #dig the reference $x is
essentially an
alias for $i. Since $i changes value between x1 and x2, rendering
$x will
change.
I agree with the sentiment that this is surprising, but it is
working as it
should.
On Oct 14, 2008, at 1:58 , Byron Foster wrote:
Actually I don't think it's all that odd, the error case is
somewhat
general (it came up in my own usage of Velocity to generate HTML
lists). Any
pass by name reference to the #foreach iteration variable will
fail, it
doesn't need to be in a string literal, for example:
#macro(test $x)#foreach($i in [1, 2])$x#end#end
#test($i)
Maybe a different disscussion, but somewhat related to how
#foreach is
implemented with local scope. The macro localscope setting
(velocimacro.context.localscope) has the same behavior as above
for the #set
directive. However, I'm not sure what Velocity's intended
behavior is with
scoping rules and pass by name.
---------------------------------------------------------------------
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]