From cc37dbafacc966e87ea2f2aed29b88b2b3c516ab Mon Sep 17 00:00:00 2001
From: Vasyl Khrystiuk
Date: Mon, 6 Nov 2023 02:14:55 +0200
Subject: [PATCH] [WIP] updating readme to reflect latest library state
---
README.md | 84 +++++++++----------
src/main/java/liqp/Examples.java | 4 +-
src/main/java/liqp/TemplateParser.java | 15 +++-
src/main/java/liqp/nodes/InsertionNode.java | 6 +-
src/test/java/liqp/InsertionTest.java | 14 ++--
src/test/java/liqp/ReadmeSamplesTest.java | 31 ++++++-
src/test/java/liqp/TemplateTest.java | 4 +-
src/test/java/liqp/nodes/BlockNodeTest.java | 2 +-
src/test/java/liqp/parser/ParseTest.java | 36 ++++++++
.../java/liqp/tags/IncludeRelativeTest.java | 6 +-
src/test/java/liqp/tags/IncludeTest.java | 3 +-
11 files changed, 137 insertions(+), 68 deletions(-)
diff --git a/README.md b/README.md
index dd897984..dd727aa1 100644
--- a/README.md
+++ b/README.md
@@ -77,7 +77,8 @@ In Ruby, you'd render a template like this:
With Liqp, the equivalent looks like this:
```java
-Template template = Template.parse("hi {{name}}");
+TemplateParser parser = new TemplateParser.Builder().build();
+Template template = parser.parse("hi {{name}}");
String rendered = template.render("name", "tobi");
System.out.println(rendered);
/*
@@ -99,8 +100,8 @@ The following examples are equivalent to the previous Liqp example:
#### Map example
```java
-Template template = Template.parse("hi {{name}}");
-Map map = new HashMap();
+Template template = new TemplateParser.Builder().build().parse("hi {{name}}");
+Map map = new HashMap<>();
map.put("name", "tobi");
String rendered = template.render(map);
System.out.println(rendered);
@@ -112,7 +113,7 @@ System.out.println(rendered);
#### JSON example
```java
-Template template = Template.parse("hi {{name}}");
+Template template = new TemplateParser.Builder().build().parse("hi {{name}}");
String rendered = template.render("{\"name\" : \"tobi\"}");
System.out.println(rendered);
/*
@@ -124,10 +125,10 @@ System.out.println(rendered);
```java
class MyParams implements Inspectable {
- public String name = "tobi";
+ public String name = "tobi";
};
-Template template = Template.parse("hi {{name}}");
-String rendered =template.render(new MyParams());
+Template template = TemplateParser.DEFAULT.parse("hi {{name}}");
+String rendered = template.render(new MyParams());
System.out.println(rendered);
/*
hi tobi
@@ -142,7 +143,7 @@ class MyLazy implements LiquidSupport {
return Collections.singletonMap("name", "tobi");
}
};
-Template template = Template.parse("hi {{name}}");
+Template template = TemplateParser.DEFAULT.parse("hi {{name}}");
String rendered = template.render(new MyLazy());
System.out.println(rendered);
/*
@@ -150,43 +151,38 @@ System.out.println(rendered);
*/
```
-#### Strict variables example
+#### Controlling library behavior
+The library has a set of keys to control the parsing/rendering process. All of them are set on `TemplateParser.Builder` class. Here they are:
+* `withFlavor(Flavor flavor)` - flavor of the liquid language. Flavor is nothing else than a predefined set of other settings. Here are supported flavors:
+ * `Flavor.JEKYLL` - flavor that defines all settings, so it tries to behave like jekyll's templates
+ * `Flavor.LIQUID` - the same for liquid's templates
+ * `Flavor.LIQP` (default) - developer of this library found some default behavior of two flavors above somehow weird in selected cases. So this flavor appears.
+* `withStripSingleLine(boolean stripSingleLine)`- if `true` then all blank lines left by outputless tags are removed. Default is `false`.
+* `withStripSpaceAroundTags(boolean stripSpacesAroundTags)` - if `true` then all whitespaces around tags are removed. Default is `false`.
+* `withObjectMapper(ObjectMapper mapper)` - if provided then this mapper is used for converting json strings to objects and internal object conversion. If not provided, then default mapper is used. Default one is good. Also, the default one is always accessible via TemplateContext instance:`context.getParser().getMapper();`
+* `withTag(Tag tag)` - register custom tag to be used in templates.
+* `withBlock(Block block)` - register custom block to be used in templates. The difference between tag and block is that block has open and closing tag and can contain other content like a text, tags and blocks.
+* `withFilter(Filter filter)` - register custom filter to be used in templates. See below for examples.
+* `withEvaluateInOutputTag(boolean evaluateInOutputTag)` - both `Flavor.JEKYLL` and `Flavor.LIQUID` are not allows to evaluate expressions in output tags, simply ignoring the expression and printing out very first token of the expression. Yes, this: `{{ 97 > 96 }}` will print `97`. This is known [bug/feature](https://github.com/Shopify/liquid/issues/1102) of those temlators. If you want to change this behavior and evaluate those expressions, set this flag to `true`. Also, the default flavor `Flavor.LIQP` has this flag set to `true` already.
+* `withStrictTypedExpressions(boolean strictTypedExpressions)` - ruby is strong-typed language. So comparing different types is not allowed there. This library tries to mimic ruby's type system in a way so all not explicit types (created or manipulated inside of templates) are converted with this schema: `nil` -> `null`; `boolean` -> `boolean`; `string` -> `java.lang.String`; any numbers -> `java.math.BigDecimal`, any datetime -> `java.time.ZonedDateTime`. If you want to change this behavior, and allow comparing in expressions in a less restricted way, set this flag to `true`, then the lax (javascript-like) approach for comparing in expressions will be used. Also, the default flavor `Flavor.LIQP` has this flag set to `true` already, others has it `false` by default.
+* `withLiquidStyleInclude(boolean liquidStyleInclude)` - if `true` then include tag will use [syntax from liquid](https://shopify.dev/docs/api/liquid/tags/include), otherwice [jekyll syntax](https://jekyllrb.com/docs/includes/) will be used. Default depends of flavor. `Flavor.LIQUID` and `Flavor.LIQP` has this flag set to `true` already. `Flavor.JEKYLL` has it `false`.
+* `withStrictVariables(boolean strictVariables)` - if set to `true` then all variables must be defined before usage, if some variable is not defined, the exception will be thrown. If `false` then all undefined variables will be treated as `null`. Default is `false`.
+* `withShowExceptionsFromInclude(boolean showExceptionsFromInclude)` - if set to `true` then all exceptions from included templates will be thrown. If `false` then all exceptions from included templates will be ignored. Default is `true`.
+* `withEvaluateMode(TemplateParser.EvaluateMode evaluateMode)` - there exists two rendering modes: `TemplateParser.EvaluateMode.LAZY` and `TemplateParser.EvaluateMode.EAGER`. By default, the `lazy` one is used. This should do the work in most cases.
+ * In `lazy` mode the template parameters are evaluating on demand and specific properties are read from there only if they are needed. Each filter/tag trying to do its work with its own parameter object, that can be literally anything.
+ * In `eager` the entire parameter object is converted into plain data tree structure that are made **only** from maps and lists, so tags/filters do know how to work with these kinds of objects. Special case - temporal objects, they are consumed as is.
+* `withRenderTransformer(RenderTransformer renderTransformer)` - even if most of elements (filters/tags/blocks) returns its results most cases as `String`, the task of combining all those strings into a final result is a task of `liqp.RenderTransformer` implementation. The default `liqp.RenderTransformerDefaultImpl` uses `StringBuilder` for that task, so template rendering is fast. Althought, you might have special needs or environment to render the results.
+* `withLocale(Locale locale)` - locale to be used for rendering. Default is `Locale.ENGLISH`. Used mostly for time rendering.
+* `withDefaultTimeZone(ZoneId defaultTimeZone)` - default time zone to be used for rendering. Default is `ZoneId.systemDefault()`. Used mostly for time rendering.
+* `withEnvironmentMapConfigurator(Consumer