Skip to content

Commit

Permalink
Also defer evaluation when encountering a random value
Browse files Browse the repository at this point in the history
  • Loading branch information
Padraig Farrell committed Feb 19, 2019
1 parent 1032c62 commit 95471b6
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 10 deletions.
6 changes: 4 additions & 2 deletions src/main/java/com/hubspot/jinjava/el/ExpressionResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ public Object resolveExpression(String expression) {
interpreter.addError(TemplateError.fromException(new TemplateSyntaxException(expression.substring(e.getPosition() - EXPRESSION_START_TOKEN.length()),
"Error parsing '" + expression + "': " + errorMessage, interpreter.getLineNumber(), position, e)));
} catch (ELException e) {
if (e.getCause() != null && e.getCause() instanceof DeferredValueException) {
throw (DeferredValueException) e.getCause();
}
interpreter.addError(TemplateError.fromException(new TemplateSyntaxException(expression, e.getMessage(), interpreter.getLineNumber(), e)));
} catch (DisabledException e) {
interpreter.addError(new TemplateError(ErrorType.FATAL, ErrorReason.DISABLED, ErrorItem.FUNCTION, e.getMessage(), expression, interpreter.getLineNumber(), interpreter.getPosition(), e));
Expand All @@ -94,8 +97,7 @@ public Object resolveExpression(String expression) {
} catch (DeferredValueException e) {
// Re-throw so that it can be handled in JinjavaInterpreter
throw e;
}
catch (Exception e) {
} catch (Exception e) {
interpreter.addError(TemplateError.fromException(new InterpretException(
String.format("Error resolving expression [%s]: " + getRootCauseMessage(e), expression), e, interpreter.getLineNumber(), interpreter.getPosition())));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
* and instead echo its contents to the output.
*/
public class DeferredValueException extends InterpretException {
public DeferredValueException(String message) {
super("Encountered a deferred value: " + message);
}

public DeferredValueException(String variable, int lineNumber, int startPosition) {
super("Encountered a deferred value: \"" + variable + "\"", lineNumber, startPosition);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.hubspot.jinjava.interpret.TemplateError.ErrorType;
import com.hubspot.jinjava.interpret.errorcategory.BasicTemplateErrorCategory;
import com.hubspot.jinjava.random.ConstantZeroRandomNumberGenerator;
import com.hubspot.jinjava.random.DeferredRandomNumberGenerator;
import com.hubspot.jinjava.random.RandomNumberGeneratorStrategy;
import com.hubspot.jinjava.tree.Node;
import com.hubspot.jinjava.tree.TreeParser;
Expand Down Expand Up @@ -79,12 +80,18 @@ public JinjavaInterpreter(Jinjava application, Context context, JinjavaConfig re
this.config = renderConfig;
this.application = application;

if (config.getRandomNumberGeneratorStrategy() == RandomNumberGeneratorStrategy.THREAD_LOCAL) {
random = ThreadLocalRandom.current();
} else if (config.getRandomNumberGeneratorStrategy() == RandomNumberGeneratorStrategy.CONSTANT_ZERO) {
random = new ConstantZeroRandomNumberGenerator();
} else {
throw new IllegalStateException("No random number generator with strategy " + config.getRandomNumberGeneratorStrategy());
switch (config.getRandomNumberGeneratorStrategy()) {
case THREAD_LOCAL:
random = ThreadLocalRandom.current();
break;
case CONSTANT_ZERO:
random = new ConstantZeroRandomNumberGenerator();
break;
case DEFERRED:
random = new DeferredRandomNumberGenerator();
break;
default:
throw new IllegalStateException("No random number generator with strategy " + config.getRandomNumberGeneratorStrategy());
}

this.expressionResolver = new ExpressionResolver(this, application.getExpressionFactory());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package com.hubspot.jinjava.random;

import java.util.Random;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;

import com.hubspot.jinjava.interpret.DeferredValueException;

/**
* A random number generator that always returns 0. Useful for testing code when you want the output to be constant.
*/
public class DeferredRandomNumberGenerator extends Random {

private static final String EXCEPTION_MESSAGE = "Generating random number";

@Override
protected int next(int bits) {
throw new DeferredValueException(EXCEPTION_MESSAGE);
}

@Override
public int nextInt() {
throw new DeferredValueException(EXCEPTION_MESSAGE);
}

@Override
public int nextInt(int bound) {
throw new DeferredValueException(EXCEPTION_MESSAGE);
}

@Override
public long nextLong() {
throw new DeferredValueException(EXCEPTION_MESSAGE);
}

@Override
public boolean nextBoolean() {
throw new DeferredValueException(EXCEPTION_MESSAGE);
}

@Override
public float nextFloat() {
throw new DeferredValueException(EXCEPTION_MESSAGE);
}

@Override
public double nextDouble() {
throw new DeferredValueException(EXCEPTION_MESSAGE);
}

@Override
public synchronized double nextGaussian() {
throw new DeferredValueException(EXCEPTION_MESSAGE);
}

@Override
public void nextBytes(byte[] bytes) {
throw new UnsupportedOperationException();
}

@Override
public IntStream ints(long streamSize) {
throw new UnsupportedOperationException();
}

@Override
public IntStream ints() {
throw new UnsupportedOperationException();
}

@Override
public IntStream ints(long streamSize, int randomNumberOrigin, int randomNumberBound) {
throw new UnsupportedOperationException();
}

@Override
public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
throw new UnsupportedOperationException();
}

@Override
public LongStream longs(long streamSize) {
throw new UnsupportedOperationException();
}

@Override
public LongStream longs() {
throw new UnsupportedOperationException();
}

@Override
public LongStream longs(long streamSize, long randomNumberOrigin, long randomNumberBound) {
throw new UnsupportedOperationException();
}

@Override
public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
throw new UnsupportedOperationException();
}

@Override
public DoubleStream doubles(long streamSize) {
throw new UnsupportedOperationException();
}

@Override
public DoubleStream doubles() {
throw new UnsupportedOperationException();
}

@Override
public DoubleStream doubles(long streamSize, double randomNumberOrigin, double randomNumberBound) {
throw new UnsupportedOperationException();
}

@Override
public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

public enum RandomNumberGeneratorStrategy {
THREAD_LOCAL,
CONSTANT_ZERO
CONSTANT_ZERO,
DEFERRED
}
16 changes: 15 additions & 1 deletion src/test/java/com/hubspot/jinjava/interpret/DeferredTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.junit.Test;

import com.hubspot.jinjava.Jinjava;
import com.hubspot.jinjava.JinjavaConfig;
import com.hubspot.jinjava.random.RandomNumberGeneratorStrategy;

public class DeferredTest {

Expand All @@ -14,7 +16,12 @@ public class DeferredTest {
@Before
public void setup() {
Jinjava jinjava = new Jinjava();
interpreter = jinjava.newInterpreter();

Context context = new Context();
JinjavaConfig config = JinjavaConfig.newBuilder()
.withRandomNumberGeneratorStrategy(RandomNumberGeneratorStrategy.DEFERRED)
.build();
interpreter = new JinjavaInterpreter(jinjava, context, config);
interpreter.getContext().put("deferred", DeferredValue.instance());
interpreter.getContext().put("resolved", "resolvedValue");
}
Expand Down Expand Up @@ -92,4 +99,11 @@ public void itPreservesFunctions() {
assertThat(interpreter.getErrors()).isEmpty();
}

@Test
public void itPreservesRandomness() {
String output = interpreter.render("{{ [1,2,3]|shuffle }}");
assertThat(output).isEqualTo("{{ [1,2,3]|shuffle }}");
assertThat(interpreter.getErrors()).isEmpty();
}

}

0 comments on commit 95471b6

Please sign in to comment.