Skip to content

Commit

Permalink
Merge pull request #294 from kohlschuetter/ck/BigDecimals
Browse files Browse the repository at this point in the history
Fix number comparisons when applying filters, BigDecimal handling
  • Loading branch information
msangel authored Dec 27, 2023
2 parents 11aae24 + 0162dfb commit 445b09b
Show file tree
Hide file tree
Showing 12 changed files with 74 additions and 31 deletions.
10 changes: 5 additions & 5 deletions src/main/java/liqp/LValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,16 +279,16 @@ public BigDecimal asStrictNumber(Object number) {
if (number == null) {
return null;
}
if (number instanceof BigDecimal) {
return (BigDecimal) number;
if (number instanceof PlainBigDecimal) {
return (PlainBigDecimal) number;
}
return new BigDecimal(number.toString().trim());
return new PlainBigDecimal(number.toString().trim());
}

// mimic ruby's `BigDecimal.to_f` with standard java capabilities
// same time provide expected out for java.math.BigDecimal
public static String asFormattedNumber(BigDecimal bd) {
return bd.setScale(Math.max(1, bd.stripTrailingZeros().scale()), RoundingMode.UNNECESSARY).toPlainString();
public static BigDecimal asFormattedNumber(BigDecimal bd) {
return bd.setScale(Math.max(1, bd.stripTrailingZeros().scale()), RoundingMode.UNNECESSARY);
}

/**
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/liqp/PlainBigDecimal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package liqp;

import java.math.BigDecimal;

/**
* A {@link BigDecimal} with a {@link #toString()} method that is equivalent to calling
* {@link #toPlainString()}.
*
* @author Christian Kohlschütter
*/
public final class PlainBigDecimal extends BigDecimal {
private static final long serialVersionUID = 1L;

public PlainBigDecimal(String val) {
super(val);
}

@Override
public String toString() {
return toPlainString();
}
}
4 changes: 2 additions & 2 deletions src/main/java/liqp/filters/Abs.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package liqp.filters;

import java.math.BigDecimal;
import liqp.PlainBigDecimal;

public class Abs extends Filter {

Expand Down Expand Up @@ -29,7 +29,7 @@ public Object apply(Object value, Object... params) {
}

if (super.isNumber(value) || super.canBeDouble(value)) {
return asFormattedNumber(new BigDecimal(super.asNumber(value).toString()).abs());
return asFormattedNumber(new PlainBigDecimal(super.asNumber(value).toString()).abs());
}

return 0;
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/liqp/filters/Minus.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.math.BigDecimal;

import liqp.PlainBigDecimal;

public class Minus extends Filter {

/*
Expand All @@ -24,8 +26,8 @@ public Object apply(Object value, Object... params) {
return super.asNumber(value).longValue() - super.asNumber(rhsObj).longValue();
}

BigDecimal first = new BigDecimal(super.asNumber(value).toString());
BigDecimal second = new BigDecimal(super.asNumber(rhsObj).toString());
BigDecimal first = new PlainBigDecimal(super.asNumber(value).toString());
BigDecimal second = new PlainBigDecimal(super.asNumber(rhsObj).toString());
return asFormattedNumber(first.subtract(second));
}
}
5 changes: 3 additions & 2 deletions src/main/java/liqp/filters/Modulo.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.math.BigDecimal;

import liqp.PlainBigDecimal;
import liqp.TemplateContext;

public class Modulo extends Filter {
Expand All @@ -26,8 +27,8 @@ public Object apply(Object value, TemplateContext context, Object... params) {
return super.asNumber(value).longValue() % super.asNumber(rhsObj).longValue();
}

BigDecimal first = new BigDecimal(super.asNumber(value).toString());
BigDecimal second = new BigDecimal(super.asNumber(rhsObj).toString());
BigDecimal first = new PlainBigDecimal(super.asNumber(value).toString());
BigDecimal second = new PlainBigDecimal(super.asNumber(rhsObj).toString());
return asFormattedNumber(first.remainder(second));
}
}
6 changes: 4 additions & 2 deletions src/main/java/liqp/filters/Plus.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.math.BigDecimal;

import liqp.PlainBigDecimal;

public class Plus extends Filter {

/*
Expand All @@ -23,8 +25,8 @@ public Object apply(Object value, Object... params) {
if (super.canBeInteger(value) && super.canBeInteger(rhsObj)) {
return super.asNumber(value).longValue() + super.asNumber(rhsObj).longValue();
}
BigDecimal first = new BigDecimal(super.asNumber(value).toString());
BigDecimal second = new BigDecimal(super.asNumber(rhsObj).toString());
BigDecimal first = new PlainBigDecimal(super.asNumber(value).toString());
BigDecimal second = new PlainBigDecimal(super.asNumber(rhsObj).toString());
return asFormattedNumber(first.add(second));
}
}
5 changes: 3 additions & 2 deletions src/main/java/liqp/filters/Round.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package liqp.filters;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;

import liqp.PlainBigDecimal;

public class Round extends Filter {

@Override
Expand Down Expand Up @@ -32,6 +33,6 @@ public Object apply(Object value, Object... params) {
DecimalFormat formatter = new DecimalFormat(formatBuilder.toString());
formatter.setRoundingMode(RoundingMode.HALF_UP);

return new BigDecimal(formatter.format(number));
return new PlainBigDecimal(formatter.format(number));
}
}
6 changes: 4 additions & 2 deletions src/main/java/liqp/filters/Times.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.math.BigDecimal;

import liqp.PlainBigDecimal;

public class Times extends Filter {

/*
Expand All @@ -24,8 +26,8 @@ public Object apply(Object value, Object... params) {
return super.asNumber(value).longValue() * super.asNumber(rhsObj).longValue();
}

BigDecimal first = new BigDecimal(super.asNumber(value).toString());
BigDecimal second = new BigDecimal(super.asNumber(rhsObj).toString());
BigDecimal first = new PlainBigDecimal(super.asNumber(value).toString());
BigDecimal second = new PlainBigDecimal(super.asNumber(rhsObj).toString());
return first.multiply(second);
}
}
6 changes: 3 additions & 3 deletions src/main/java/liqp/nodes/ContainsNode.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package liqp.nodes;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import liqp.LValue;
import liqp.PlainBigDecimal;
import liqp.TemplateContext;
import liqp.parser.Inspectable;
import liqp.parser.LiquidSupport;
Expand Down Expand Up @@ -51,7 +51,7 @@ public Object render(TemplateContext context) {

private Object toSingleNumberType(Object needle) {
if (needle instanceof Number) {
needle = LValue.asFormattedNumber(new BigDecimal(needle.toString()));
needle = LValue.asFormattedNumber(new PlainBigDecimal(needle.toString()));
}
return needle;
}
Expand All @@ -60,7 +60,7 @@ private List<Object> toSingleNumberType(List<Object> asList) {
ArrayList<Object> res = new ArrayList<>(asList.size());
for(Object item: asList) {
if (item instanceof Number) {
res.add(LValue.asFormattedNumber(new BigDecimal(item.toString())));
res.add(LValue.asFormattedNumber(new PlainBigDecimal(item.toString())));
} else {
res.add(item);
}
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/liqp/nodes/OutputNode.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package liqp.nodes;

import liqp.PlainBigDecimal;
import liqp.TemplateContext;
import liqp.TemplateParser;
import liqp.exceptions.LiquidException;
Expand Down Expand Up @@ -51,12 +52,12 @@ public Object render(TemplateContext context) {
}
context.addError(new LiquidException("unexpected output: " + localUnparsed, unparsedline, unparsedPosition, null));
}

}

if (value instanceof BigDecimal) {
value = ((BigDecimal) value).toPlainString();
if (value instanceof BigDecimal && !(value instanceof PlainBigDecimal)) {
value = new PlainBigDecimal(value.toString());
}

return value;
}
}
16 changes: 10 additions & 6 deletions src/test/java/liqp/filters/TimesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import liqp.LValue;
import java.math.BigDecimal;

import org.antlr.v4.runtime.RecognitionException;
import org.junit.Test;

import liqp.LValue;
import liqp.PlainBigDecimal;
import liqp.Template;
import liqp.TemplateParser;

import java.math.BigDecimal;

public class TimesTest {

@Test
Expand Down Expand Up @@ -71,8 +72,11 @@ public void applyoriginaltest() {
assertThat(filter.apply(3L, 4L), is((Object)12L));
// assert_template_result "0", "{{ 'foo' | times:4 }}" // see: applyTest()
assertTrue(String.valueOf(filter.apply(2.1, 3L)).matches("6[.,]3"));
assertEquals("7.25", LValue.asFormattedNumber((BigDecimal) filter.apply(0.0725, 100)));
assertEquals("-7.25", LValue.asFormattedNumber((BigDecimal) filter.apply(-0.0725, 100)));
assertEquals("7.25", LValue.asFormattedNumber((BigDecimal) filter.apply(-0.0725, -100)));
assertEquals(new PlainBigDecimal("7.25"), LValue.asFormattedNumber((BigDecimal) filter.apply(
0.0725, 100)));
assertEquals(new PlainBigDecimal("-7.25"), LValue.asFormattedNumber((BigDecimal) filter.apply(
-0.0725, 100)));
assertEquals(new PlainBigDecimal("7.25"), LValue.asFormattedNumber((BigDecimal) filter.apply(
-0.0725, -100)));
}
}
12 changes: 10 additions & 2 deletions src/test/java/liqp/nodes/GtNodeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
import java.util.List;
import java.util.Map;

import liqp.exceptions.LiquidException;
import liqp.parser.Flavor;
import org.antlr.v4.runtime.RecognitionException;
import org.junit.Test;

import liqp.Template;
import liqp.TemplateParser;
import liqp.TemplateTest;
import liqp.exceptions.LiquidException;
import liqp.parser.Flavor;
import liqp.parser.Inspectable;

public class GtNodeTest {
Expand Down Expand Up @@ -126,4 +126,12 @@ public void testBug267StringVsNumber() {
assertTrue(e.getMessage().contains("not the same type"));
}
}

@Test
public void testFilterCompare() {
String result = new TemplateParser.Builder().withFlavor(Flavor.JEKYLL).build() //
.parse("{% assign score = 0 | plus: 1.0 %}{% if score > 0 %}true{% else %}false{% endif %}")
.render();
assertTrue(Boolean.parseBoolean(result));
}
}

0 comments on commit 445b09b

Please sign in to comment.