Repository: PebbleTemplates/pebble
Pull request #387 (2018-08-17 03:34:31)

Make IF operator more tollerant to argument type

ebussieres: - [ ] Update documentation

Patch:
diff --git a/pebble-spring/pebble-spring-boot-2-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java b/pebble-spring/pebble-spring-boot-2-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java
index 2a655366..57ecbbc7 100644
--- a/pebble-spring/pebble-spring-boot-2-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java
+++ b/pebble-spring/pebble-spring-boot-2-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java
@@ -76,6 +76,7 @@ public class PebbleAutoConfiguration {
         builder.defaultLocale(this.properties.getDefaultLocale());
       }
       builder.strictVariables(this.properties.isStrictVariables());
+      builder.greedyMatchMethod(this.properties.isGreedyMatchMethod());
       return builder.build();
     }
   }
diff --git a/pebble-spring/pebble-spring-boot-2-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleProperties.java b/pebble-spring/pebble-spring-boot-2-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleProperties.java
index f2427019..53a421e9 100644
--- a/pebble-spring/pebble-spring-boot-2-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleProperties.java
+++ b/pebble-spring/pebble-spring-boot-2-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleProperties.java
@@ -12,6 +12,7 @@ public class PebbleProperties extends AbstractTemplateViewResolverProperties {
 
   private Locale defaultLocale;
   private boolean strictVariables;
+  private boolean greedyMatchMethod;
 
   public PebbleProperties() {
     super(DEFAULT_PREFIX, DEFAULT_SUFFIX);
@@ -33,4 +34,12 @@ public class PebbleProperties extends AbstractTemplateViewResolverProperties {
   public void setStrictVariables(boolean strictVariables) {
     this.strictVariables = strictVariables;
   }
+
+  public boolean isGreedyMatchMethod() {
+    return this.greedyMatchMethod;
+  }
+
+  public void setGreedyMatchMethod(boolean greedyMatchMethod) {
+    this.greedyMatchMethod = greedyMatchMethod;
+  }
 }
diff --git a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java
index bc8f714b..c3997769 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java
@@ -76,6 +76,7 @@ public class PebbleAutoConfiguration {
         builder.defaultLocale(this.properties.getDefaultLocale());
       }
       builder.strictVariables(this.properties.isStrictVariables());
+      builder.greedyMatchMethod(this.properties.isGreedyMatchMethod());
       return builder.build();
     }
   }
diff --git a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleProperties.java b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleProperties.java
index f2427019..53a421e9 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleProperties.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleProperties.java
@@ -12,6 +12,7 @@ public class PebbleProperties extends AbstractTemplateViewResolverProperties {
 
   private Locale defaultLocale;
   private boolean strictVariables;
+  private boolean greedyMatchMethod;
 
   public PebbleProperties() {
     super(DEFAULT_PREFIX, DEFAULT_SUFFIX);
@@ -33,4 +34,12 @@ public class PebbleProperties extends AbstractTemplateViewResolverProperties {
   public void setStrictVariables(boolean strictVariables) {
     this.strictVariables = strictVariables;
   }
+
+  public boolean isGreedyMatchMethod() {
+    return this.greedyMatchMethod;
+  }
+
+  public void setGreedyMatchMethod(boolean greedyMatchMethod) {
+    this.greedyMatchMethod = greedyMatchMethod;
+  }
 }
diff --git a/pebble/src/main/java/com/mitchellbosecke/pebble/node/IfNode.java b/pebble/src/main/java/com/mitchellbosecke/pebble/node/IfNode.java
index 581601c4..bfda5ef9 100644
--- a/pebble/src/main/java/com/mitchellbosecke/pebble/node/IfNode.java
+++ b/pebble/src/main/java/com/mitchellbosecke/pebble/node/IfNode.java
@@ -49,13 +49,26 @@ public class IfNode extends AbstractRenderableNode {
         Object result = conditionalExpression.evaluate(self, context);
 
         if (result != null) {
-          try {
+          if (result instanceof Boolean) {
             satisfied = (Boolean) result;
-          } catch (ClassCastException ex) {
-            throw new PebbleException(ex, "Expected a Boolean in \"if\" statement",
-                this.getLineNumber(),
-                self.getName());
           }
+          else if (result instanceof Number) {
+            Number number = (Number) result;
+            satisfied = number.intValue() != 0;
+          }
+          else if (result instanceof String) {
+            String str = (String) result;
+            satisfied = !str.isEmpty();
+          } else {
+            throw new PebbleException(
+                      null,
+                      String.format(
+                              "Unsupported value type %s. Expected Boolean, String, Number in \"if\" statement",
+                              result.getClass().getSimpleName()),
+                      this.getLineNumber(),
+                      self.getName());
+          }
+
         } else if (context.isStrictVariables()) {
           throw new PebbleException(null,
               "null value given to if statement and strict variables is set to true",


Test patch:
diff --git a/pebble/src/test/java/com/mitchellbosecke/pebble/CoreTagsTest.java b/pebble/src/test/java/com/mitchellbosecke/pebble/CoreTagsTest.java
index e8958f9c..7c5ae13b 100644
--- a/pebble/src/test/java/com/mitchellbosecke/pebble/CoreTagsTest.java
+++ b/pebble/src/test/java/com/mitchellbosecke/pebble/CoreTagsTest.java
@@ -84,22 +84,6 @@ public class CoreTagsTest {
     assertEquals("no", writer.toString());
   }
 
-  @Test(expected = PebbleException.class)
-  public void testExceptionWithIfStatement() throws PebbleException, IOException {
-    PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader())
-        .strictVariables(false).build();
-
-    String source = "{% if 'string' %}yes{% else %}no{% endif %}";
-    PebbleTemplate template = pebble.getTemplate(source);
-
-    Map<String, Object> context = new HashMap<>();
-    context.put("yes", true);
-
-    Writer writer = new StringWriter();
-    template.evaluate(writer, context);
-    assertEquals("no", writer.toString());
-  }
-
   /**
    * Issue #34
    */
diff --git a/pebble/src/test/java/com/mitchellbosecke/pebble/node/IfNodeTest.java b/pebble/src/test/java/com/mitchellbosecke/pebble/node/IfNodeTest.java
new file mode 100644
index 00000000..a6394102
--- /dev/null
+++ b/pebble/src/test/java/com/mitchellbosecke/pebble/node/IfNodeTest.java
@@ -0,0 +1,100 @@
+package com.mitchellbosecke.pebble.node;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import com.mitchellbosecke.pebble.PebbleEngine;
+import com.mitchellbosecke.pebble.error.PebbleException;
+import com.mitchellbosecke.pebble.loader.StringLoader;
+import com.mitchellbosecke.pebble.template.PebbleTemplate;
+
+public class IfNodeTest {
+
+  private static final String templateSource = "{% if value %}yes{% else %}no{% endif %}";
+
+  private String render(Object foobar) throws IOException {
+    return render(false, foobar);
+  }
+
+  private String render(boolean strict, Object value) throws IOException {
+    PebbleEngine pebble = new PebbleEngine.Builder()
+            .loader(new StringLoader())
+            .strictVariables(strict)
+            .build();
+
+    PebbleTemplate template = pebble.getTemplate(templateSource);
+    Map<String, Object> context = new HashMap<>();
+    context.put("value", value);
+
+    Writer writer = new StringWriter();
+    template.evaluate(writer, context);
+    return writer.toString();
+  }
+
+
+  @Test
+  public void testIfNull() throws IOException {
+    assertEquals("Null should be interpreted as FALSE",
+            "no", render(null));
+  }
+
+  @Test(expected=PebbleException.class)
+  public void testIfNullInStrictMode() throws IOException {
+    render(true, null);
+  }
+
+  @Test
+  public void testIfTrue() throws IOException {
+    assertEquals("Null should be interpreted as FALSE",
+            "yes", render(true));
+  }
+
+  @Test
+  public void testIfFalse() throws IOException {
+    assertEquals("Null should be interpreted as FALSE",
+            "no", render(false));
+  }
+
+  @Test
+  public void testIfNotZeroInteger() throws IOException {
+    assertEquals("Not zero integer should be interpreted as TRUE",
+            "yes", render(1));
+  }
+
+  @Test
+  public void testIfZeroInteger() throws IOException {
+    assertEquals("Zero integer should be interpreted as FALSE",
+            "no", render(0));
+  }
+
+  @Test
+  public void testIfNotZeroFloat() throws IOException {
+    assertEquals("Not zero float should be interpreted as TRUE",
+            "yes", render(1.1));
+  }
+
+  @Test
+  public void testIfZeroFloat() throws IOException {
+    assertEquals("Zero float should be interpreted as FALSE",
+            "no", render(0));
+  }
+
+  @Test
+  public void testIfNotEmptyString() throws IOException {
+    assertEquals("Not empty string should be interpreted as TRUE",
+            "yes", render("not empty string"));
+  }
+
+  @Test
+  public void testIfEmptyString() throws IOException {
+    assertEquals("Empty string should be interpreted as FALSE",
+            "no", render(""));
+  }
+}