Skip to content

Commit

Permalink
#362: Bugfix loop.length and loop.revindex not of type Number (#363)
Browse files Browse the repository at this point in the history
  • Loading branch information
ebussieres authored Jun 30, 2018
1 parent 820a6c5 commit 1fc456e
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 69 deletions.
79 changes: 10 additions & 69 deletions src/main/java/com/mitchellbosecke/pebble/node/ForNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@
******************************************************************************/
package com.mitchellbosecke.pebble.node;

import com.mitchellbosecke.pebble.error.PebbleException;
import com.mitchellbosecke.pebble.extension.NodeVisitor;
import com.mitchellbosecke.pebble.node.expression.Expression;
import com.mitchellbosecke.pebble.node.fornode.LazyLength;
import com.mitchellbosecke.pebble.node.fornode.LazyRevIndex;
import com.mitchellbosecke.pebble.template.EvaluationContext;
import com.mitchellbosecke.pebble.template.PebbleTemplateImpl;
import com.mitchellbosecke.pebble.template.ScopeChain;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.mitchellbosecke.pebble.error.PebbleException;
import com.mitchellbosecke.pebble.extension.NodeVisitor;
import com.mitchellbosecke.pebble.node.expression.Expression;
import com.mitchellbosecke.pebble.template.EvaluationContext;
import com.mitchellbosecke.pebble.template.PebbleTemplateImpl;
import com.mitchellbosecke.pebble.template.ScopeChain;

/**
* Represents a "for" loop within the template.
*
Expand All @@ -39,18 +39,6 @@ public class ForNode extends AbstractRenderableNode {

private final BodyNode elseBody;

class Control extends Object {

protected int value = -1;

public Control(int value) {
this.value = value;
}

public Control() {
}
}

public ForNode(int lineNumber, String variableName, Expression<?> iterableExpression, BodyNode body,
BodyNode elseBody) {
super(lineNumber);
Expand Down Expand Up @@ -83,16 +71,7 @@ public void render(PebbleTemplateImpl self, Writer writer, EvaluationContext con
ScopeChain scopeChain = context.getScopeChain();
scopeChain.pushScope();

final Control length = new Control() {

@Override
public String toString() {
if (this.value == -1) {
this.value = getIteratorSize(iterableEvaluation);
}
return String.valueOf(value);
}
};
LazyLength length = new LazyLength(iterableEvaluation);

int index = 0;

Expand All @@ -118,15 +97,7 @@ public String toString() {
loop.put("first", false);
}

Control revindex = new Control(index) {

@Override
public String toString() {
return String.valueOf(Integer.valueOf(length.toString()) - this.value - 1);
}
};

loop.put("revindex", revindex);
loop.put("revindex", new LazyRevIndex(index, length));
loop.put("index", index++);
scopeChain.put("loop", loop);
scopeChain.put(this.variableName, iterator.next());
Expand Down Expand Up @@ -187,36 +158,6 @@ private Iterable<Object> toIterable(final Object obj) {
return result;
}

private int getIteratorSize(Object iterable) {
if (iterable == null) {
return 0;
}
if (iterable instanceof Collection) {
return ((Collection<?>) iterable).size();
} else if (iterable instanceof Map) {
return ((Map<?, ?>) iterable).size();
} else if (iterable.getClass().isArray()) {
return Array.getLength(iterable);
} else if (iterable instanceof Enumeration) {
Enumeration<?> enumeration = (Enumeration<?>) iterable;
int size = 0;
while (enumeration.hasMoreElements()) {
size++;
enumeration.nextElement();
}
return size;
}

// assumed to be of type Iterator
Iterator<?> it = ((Iterable<?>) iterable).iterator();
int size = 0;
while (it.hasNext()) {
size++;
it.next();
}
return size;
}

/**
* Adapts an array to an Iterable
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.mitchellbosecke.pebble.node.fornode;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

public class LazyLength extends Number {

private final Object iterableEvaluation;
private int value = -1;

public LazyLength(Object iterableEvaluation) {
this.iterableEvaluation = iterableEvaluation;
}

@Override
public int intValue() {
return getValue();
}

@Override
public long longValue() {
return (long) getValue();
}

@Override
public float floatValue() {
return (float) getValue();
}

@Override
public double doubleValue() {
return (double) getValue();
}

@Override
public String toString() {
return String.valueOf(getValue());
}

private int getValue() {
if (this.value == -1) {
this.value = getIteratorSize(iterableEvaluation);
}
return value;
}

private int getIteratorSize(Object iterable) {
if (iterable == null) {
return 0;
}
if (iterable instanceof Collection) {
return ((Collection<?>) iterable).size();
} else if (iterable instanceof Map) {
return ((Map<?, ?>) iterable).size();
} else if (iterable.getClass().isArray()) {
return Array.getLength(iterable);
} else if (iterable instanceof Enumeration) {
Enumeration<?> enumeration = (Enumeration<?>) iterable;
int size = 0;
while (enumeration.hasMoreElements()) {
size++;
enumeration.nextElement();
}
return size;
}

// assumed to be of type Iterator
Iterator<?> it = ((Iterable<?>) iterable).iterator();
int size = 0;
while (it.hasNext()) {
size++;
it.next();
}
return size;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.mitchellbosecke.pebble.node.fornode;

public class LazyRevIndex extends Number {
private final int value;
private final LazyLength lazyLength;

public LazyRevIndex(int value, LazyLength lazyLength) {
this.value = value;
this.lazyLength = lazyLength;
}

@Override
public int intValue() {
return getValue();
}

@Override
public long longValue() {
return (long) getValue();
}

@Override
public float floatValue() {
return (float) getValue();
}

@Override
public double doubleValue() {
return (double) getValue();
}

@Override
public String toString() {
return String.valueOf(getValue());
}

private int getValue() {
return lazyLength.intValue() - this.value - 1;
}
}
60 changes: 60 additions & 0 deletions src/test/java/com/mitchellbosecke/pebble/ForTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.mitchellbosecke.pebble;

import static org.junit.Assert.assertEquals;

import com.mitchellbosecke.pebble.loader.StringLoader;
import com.mitchellbosecke.pebble.template.PebbleTemplate;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;

public class ForTest {
@Test
public void testForLengthWithOperation() throws IOException {
PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader()).strictVariables(false).build();

String source = "{% for user in users %}{% if loop.index < ( loop.length - 1) %}{{user.username}}{% endif %}{% endfor %}";
PebbleTemplate template = pebble.getTemplate(source);
Map<String, Object> context = new HashMap<>();
List<User> users = new ArrayList<>();
users.add(new User("Alex"));
users.add(new User("Bob"));
users.add(new User("John"));
context.put("users", users);

Writer writer = new StringWriter();
template.evaluate(writer, context);
assertEquals("AlexBob", writer.toString());
}

@Test
public void testForRevIndexWithOperation() throws IOException {
PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader()).strictVariables(false).build();

String source = "{% for user in users %}{% if (loop.revindex - 1) >= 0 %}{{user.username}}{% endif %}{% endfor %}";
PebbleTemplate template = pebble.getTemplate(source);
Map<String, Object> context = new HashMap<>();
List<User> users = new ArrayList<>();
users.add(new User("Alex"));
users.add(new User("Bob"));
users.add(new User("John"));
context.put("users", users);

Writer writer = new StringWriter();
template.evaluate(writer, context);
assertEquals("AlexBob", writer.toString());
}

public static class User {
public final String username;

public User(String username) {
this.username = username;
}
}
}

0 comments on commit 1fc456e

Please sign in to comment.