Skip to content

Commit

Permalink
Support custom function registration in Java API (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbali authored Nov 3, 2021
1 parent 000ae43 commit df26b65
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 3 deletions.
41 changes: 41 additions & 0 deletions docs/Functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,44 @@ Expects two arguments: a value and a list. Checks if list contains the value. Us
### Sum

Expects one number argument containing a list with numbers. Sums up the numbers and returns result. Usage: `sum(myList)`

## Custom functions

You can register custom implementations of `io.github.erdos.stencil.functions.Function` or the `stencil.functions/call-fn` multimethod.

Clojure example:

```clojure
(defmethod call-fn "first" [_ data]
(if (seq? data) (first data) data))
```

Java example:

```java
public class FirstFuncion implements Function {

@Override
public String getName() {
return "first";
}

@Override
public Object call(final Object... arguments) throws IllegalArgumentException {
if (arguments.length != 1) {
throw new IllegalArgumentException("Unexpected argument count");
}
final Object arg = arguments[0];
if (arg instanceof Iterable<?>) {
final Iterator<?> iterator = ((Iterable<?>) arg).iterator();
return iterator.hasNext() ? iterator.next() : null;
} else {
return null;
}
}
}

/* .... later you can register it in render stage .... */

API.render(preparedTemplate, fragments, data, Arrays.asList(new FirstFunction()));
```
15 changes: 13 additions & 2 deletions java-src/io/github/erdos/stencil/API.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package io.github.erdos.stencil;

import io.github.erdos.stencil.functions.Function;
import io.github.erdos.stencil.impl.NativeEvaluator;
import io.github.erdos.stencil.impl.NativeTemplateFactory;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;

public final class API {
Expand Down Expand Up @@ -46,10 +49,18 @@ public static PreparedFragment fragment(File fragmentFile) throws IOException {
}

public static EvaluatedDocument render(PreparedTemplate template, TemplateData data) {
return render(template, emptyMap(), data);
return render(template, emptyMap(), data, emptyList());
}

public static EvaluatedDocument render(PreparedTemplate template, Map<String, PreparedFragment> fragments, TemplateData data) {
return new NativeEvaluator().render(template, fragments, data);
return render(template, fragments, data, emptyList());
}

public static EvaluatedDocument render(PreparedTemplate template, Map<String, PreparedFragment> fragments, TemplateData data, Collection<Function> customFunctions) {
final NativeEvaluator evaluator = new NativeEvaluator();
if (customFunctions != null) {
evaluator.getFunctionEvaluator().registerFunctions(customFunctions.toArray(new Function[0]));
}
return evaluator.render(template, fragments, data);
}
}
56 changes: 56 additions & 0 deletions java-test/io/github/erdos/stencil/APITest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.github.erdos.stencil;

import io.github.erdos.stencil.exceptions.EvalException;
import io.github.erdos.stencil.functions.Function;
import org.junit.Assert;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class APITest {

private static class CustomFunction implements Function {
private int callCount = 0;
private Object lastResult = null;

@Override
public Object call(final Object... arguments) throws IllegalArgumentException {
callCount++;
lastResult = arguments.length > 0 ? arguments[0] : arguments;
return lastResult;
}

@Override
public String getName() {
return "customFunction";
}
}

@Test
public void testCustomFunction() throws IOException {
final CustomFunction fn = new CustomFunction();
try (final PreparedTemplate prepared =
API.prepare(new File("test-resources/test-custom-function.docx"))) {
final Map<String, Object> data = new HashMap<>();
data.put("input", "testInput");
API.render(prepared, Collections.emptyMap(), TemplateData.fromMap(data), Collections.singletonList(fn));
}
Assert.assertTrue("Custom function should have been called", fn.callCount > 0);
Assert.assertEquals("Custom function returned unexpected value", "testInput", fn.lastResult);
}

@Test(expected = EvalException.class)
public void testWithoutCustomFunction() throws IOException {
try (final PreparedTemplate prepared =
API.prepare(new File("test-resources/test-custom-function.docx"))) {
final Map<String, Object> data = new HashMap<>();
data.put("input", "testInput");
API.render(prepared, Collections.emptyMap(), TemplateData.fromMap(data));
Assert.fail("Should have thrown exception");
}
}
}
Binary file added test-resources/test-custom-function.docx
Binary file not shown.
16 changes: 15 additions & 1 deletion test/stencil/api_test.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
(ns stencil.api-test
(:import [io.github.erdos.stencil.exceptions EvalException])
(:require [clojure.test :refer [deftest testing is]]
[stencil.api :refer [prepare render! fragment cleanup!]]))
[stencil.api :refer [prepare render! fragment cleanup!]]
[stencil.functions :refer [call-fn]]))

(deftest test-prepare+render+cleanup
(let [template (prepare "./examples/Purchase Reminder/template.docx")
Expand Down Expand Up @@ -145,3 +146,16 @@
"footer" footer}
:output "/tmp/out-multipart.docx"
:overwrite? true)))

(deftest test-custom-function
(with-open [template (prepare "test-resources/test-custom-function.docx")]
(let [called (atom false)
f (java.io.File/createTempFile "stencil" ".docx")]
(try
(defmethod call-fn "customFunction"
[_ & args]
(reset! called true)
(first args))
(render! template {:input "data"} :output f :overwrite? true)
(is @called)
(finally (remove-method call-fn "customFunction"))))))

0 comments on commit df26b65

Please sign in to comment.