summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/Makefile14
-rw-r--r--java/pablotron/luigi/Filter.java89
-rw-r--r--java/pablotron/luigi/FilterReference.java11
-rw-r--r--java/pablotron/luigi/LuigiError.java7
-rw-r--r--java/pablotron/luigi/Parser.java114
-rw-r--r--java/pablotron/luigi/Template.java37
-rw-r--r--java/pablotron/luigi/actions/Action.java12
-rw-r--r--java/pablotron/luigi/actions/FilterAction.java41
-rw-r--r--java/pablotron/luigi/actions/TextAction.java22
9 files changed, 347 insertions, 0 deletions
diff --git a/java/Makefile b/java/Makefile
new file mode 100644
index 0000000..15005fa
--- /dev/null
+++ b/java/Makefile
@@ -0,0 +1,14 @@
+SOURCES=$(shell find . -type f -name \*.java)
+CLASSES=$(shell find . -type f -name \*.class)
+OUT=luigi-template.jar
+
+all: $(SOURCES)
+ javac $(SOURCES)
+
+$(OUT): all
+ jar cvf $(OUT) $(CLASSES)
+
+jar: $(OUT)
+
+clean:
+ rm -v $(OUT) $(CLASSES)
diff --git a/java/pablotron/luigi/Filter.java b/java/pablotron/luigi/Filter.java
new file mode 100644
index 0000000..d89beab
--- /dev/null
+++ b/java/pablotron/luigi/Filter.java
@@ -0,0 +1,89 @@
+package pablotron.luigi;
+
+import java.util.Map;
+import java.util.HashMap;
+
+public final class Filter {
+ public interface Handler {
+ public String filter(String val, String args[], Map<String, String> row);
+ };
+
+ public static Map<String, Handler> FILTERS = new HashMap<String, Handler>() {{
+ put("null", new Handler() {
+ public String filter(String val, String args[], Map<String, String> row) {
+ return "";
+ }
+ });
+
+ put("s", new Handler() {
+ public String filter(String val, String args[], Map<String, String> row) {
+ int v = Integer.parseInt(val);
+ return (v == 1) ? "" : "s";
+ }
+ });
+
+ put("uc", new Handler() {
+ public String filter(String val, String args[], Map<String, String> row) {
+ return val.toUpperCase();
+ }
+ });
+
+ put("lc", new Handler() {
+ public String filter(String val, String args[], Map<String, String> row) {
+ return val.toLowerCase();
+ }
+ });
+
+ put("length", new Handler() {
+ public String filter(String val, String args[], Map<String, String> row) {
+ return Integer.toString(val.length());
+ }
+ });
+
+ put("trim", new Handler() {
+ public String filter(String val, String args[], Map<String, String> row) {
+ return val.trim();
+ }
+ });
+
+ put("h", new Handler() {
+ public String filter(String val, String args[], Map<String, String> row) {
+ StringBuilder r = new StringBuilder(val.length());
+
+ for (int i = 0, l = val.length(); i < l; i++) {
+ char c = val.charAt(i);
+
+ switch (c) {
+ case '&':
+ r.append("&amp;");
+ break;
+ case '<':
+ r.append("&lt;");
+ break;
+ case '>':
+ r.append("&gt;");
+ break;
+ case '\'':
+ r.append("&apos;");
+ break;
+ case '"':
+ r.append("&quot;");
+ break;
+ default:
+ r.append(c);
+ }
+ }
+
+ return r.toString();
+/*
+ * return val
+ * .replace("&", "&amp;")
+ * .replace("<", "&lt;")
+ * .replace(">", "&gt;")
+ * .replace("'", "&apos;")
+ * .replace("\"", "&quot;");
+ */
+ }
+ });
+ }};
+};
diff --git a/java/pablotron/luigi/FilterReference.java b/java/pablotron/luigi/FilterReference.java
new file mode 100644
index 0000000..d0f9d3d
--- /dev/null
+++ b/java/pablotron/luigi/FilterReference.java
@@ -0,0 +1,11 @@
+package pablotron.luigi;
+
+public final class FilterReference {
+ public final String name;
+ public final String[] args;
+
+ public FilterReference(final String name, final String args[]) {
+ this.name = name;
+ this.args = args;
+ }
+};
diff --git a/java/pablotron/luigi/LuigiError.java b/java/pablotron/luigi/LuigiError.java
new file mode 100644
index 0000000..4ff4c01
--- /dev/null
+++ b/java/pablotron/luigi/LuigiError.java
@@ -0,0 +1,7 @@
+package pablotron.luigi;
+
+public class LuigiError extends Exception {
+ public LuigiError(final String message) {
+ super(message);
+ }
+};
diff --git a/java/pablotron/luigi/Parser.java b/java/pablotron/luigi/Parser.java
new file mode 100644
index 0000000..0daef25
--- /dev/null
+++ b/java/pablotron/luigi/Parser.java
@@ -0,0 +1,114 @@
+package pablotron.luigi;
+
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+import pablotron.luigi.actions.Action;
+import pablotron.luigi.actions.FilterAction;
+import pablotron.luigi.actions.TextAction;
+import pablotron.luigi.FilterReference;
+import pablotron.luigi.LuigiError;
+
+public final class Parser {
+ private static final Pattern RE_ACTION = Pattern.compile(
+ // match opening brace
+ "%\\{" +
+
+ // match optional whitespace
+ "\\s*" +
+
+ // match key
+ // "(?<key>[^\\s\\|\\}]+)" +
+ "([^\\s\\|\\}]+)" +
+
+ // match filter(s)
+ // "(?<filters>(\\s*\\|(\\s*[^\\s\\|\\}]+)+)*)" +
+ "((\\s*\\|(\\s*[^\\s\\|\\}]+)+)*)" +
+
+ // match optional whitespace
+ "\\s*" +
+
+ // match closing brace
+ "\\}" +
+
+ // or match up all non-% chars or a single % char
+ // "| (?<text>[^%]* | %)",
+ "| ([^%]* | %)",
+
+ Pattern.COMMENTS
+ );
+
+ private static final Pattern RE_FILTER = Pattern.compile(
+ // match filter name
+ // "(?<name>\\S+)" +
+ "(\\S+)" +
+
+ // match filter arguments (optional)
+ // "(?<args>(\\s*\\S+)*)" +
+ "((\\s*\\S+)*)" +
+
+ // optional trailing whitespace
+ "\\s*",
+
+ Pattern.COMMENTS
+ );
+
+ private static final Pattern RE_DELIM_FILTERS = Pattern.compile(
+ "\\s*\\|\\s*"
+ );
+
+ private static final Pattern RE_DELIM_ARGS = Pattern.compile(
+ "\\s+"
+ );
+
+ public static Action[] parse_template(
+ String template
+ ) throws LuigiError {
+ ArrayList<Action> r = new ArrayList<Action>();
+
+ // match on text
+ final Matcher m = RE_ACTION.matcher(template);
+
+ while (m.find()) {
+ // String key = m.group("key");
+ String key = m.group(1);
+
+ if (key != null && key.length() > 0) {
+ // r.add(new FilterAction(key, parse_filters(m.group("filters"))));
+ r.add(new FilterAction(key, parse_filters(m.group(2))));
+ } else {
+ // r.add(new TextAction(m.group("text")));
+ r.add(new TextAction(m.group(5)));
+ }
+ }
+
+ // build array of results
+ return r.toArray(new Action[r.size()]);
+ }
+
+ public static FilterReference[] parse_filters(
+ String filters_str
+ ) throws LuigiError {
+ ArrayList<FilterReference> r = new ArrayList<FilterReference>();
+
+ // split string into individual filters and handle each one
+ for (String f: RE_DELIM_FILTERS.split(filters_str)) {
+ // trim filter string and skip empty filters
+ f = f.trim();
+ if (f.length() == 0)
+ continue;
+
+ // match on filter and check for error
+ Matcher m = RE_FILTER.matcher(f);
+ if (!m.find())
+ throw new LuigiError("invalid filter: " + f);
+
+ // append new filter reference to result
+ r.add(new FilterReference(m.group(1), RE_DELIM_ARGS.split(m.group(2))));
+ }
+
+ // return result
+ return r.toArray(new FilterReference[r.size()]);
+ }
+};
diff --git a/java/pablotron/luigi/Template.java b/java/pablotron/luigi/Template.java
new file mode 100644
index 0000000..2bf0bb7
--- /dev/null
+++ b/java/pablotron/luigi/Template.java
@@ -0,0 +1,37 @@
+package pablotron.luigi;
+
+import java.util.Map;
+import pablotron.luigi.Parser;
+import pablotron.luigi.Filter;
+import pablotron.luigi.LuigiError;
+import pablotron.luigi.actions.Action;
+
+public final class Template {
+ private static final String VERSION = "0.4.0";
+
+ private final String template;
+ private final Action actions[];
+ private final Map<String, Filter.Handler> filters;
+
+ public Template(
+ final String template,
+ final Map<String, Filter.Handler> filters
+ ) throws LuigiError {
+ this.template = template;
+ this.filters = filters;
+ this.actions = Parser.parse_template(template);
+ }
+
+ public Template(final String template) throws LuigiError {
+ this(template, Filter.FILTERS);
+ }
+
+ public String run(Map<String, String> args) throws LuigiError {
+ StringBuilder r = new StringBuilder();
+
+ for (Action a: this.actions)
+ r.append(a.run(this.filters, args));
+
+ return r.toString();
+ }
+};
diff --git a/java/pablotron/luigi/actions/Action.java b/java/pablotron/luigi/actions/Action.java
new file mode 100644
index 0000000..010622a
--- /dev/null
+++ b/java/pablotron/luigi/actions/Action.java
@@ -0,0 +1,12 @@
+package pablotron.luigi.actions;
+
+import java.util.Map;
+import pablotron.luigi.Filter;
+import pablotron.luigi.LuigiError;
+
+public interface Action {
+ public String run(
+ Map<String, Filter.Handler> filters,
+ Map<String, String> args
+ ) throws LuigiError;
+};
diff --git a/java/pablotron/luigi/actions/FilterAction.java b/java/pablotron/luigi/actions/FilterAction.java
new file mode 100644
index 0000000..b69923b
--- /dev/null
+++ b/java/pablotron/luigi/actions/FilterAction.java
@@ -0,0 +1,41 @@
+package pablotron.luigi.actions;
+
+import java.util.Map;
+import pablotron.luigi.actions.Action;
+import pablotron.luigi.FilterReference;
+import pablotron.luigi.Filter;
+import pablotron.luigi.LuigiError;
+
+public final class FilterAction implements Action {
+ private final String key;
+ private final FilterReference filters[];
+
+ public FilterAction(final String key, final FilterReference filters[]) {
+ this.key = key;
+ this.filters = filters;
+ }
+
+ public String run(
+ Map<String, Filter.Handler> filters,
+ Map<String, String> args
+ ) throws LuigiError {
+ // check for key
+ if (!args.containsKey(key))
+ throw new LuigiError("unknown key: " + key);
+
+ // reduce value to result
+ String r = args.get(key);
+ for (int i = 0, l = this.filters.length; i < l; i++) {
+ // get/check filter
+ Filter.Handler f = filters.get(this.filters[i].name);
+ if (f == null)
+ throw new LuigiError("unknown filter: " + this.filters[i].name);
+
+ // run filter
+ r = f.filter(r, this.filters[i].args, args);
+ }
+
+ // return result
+ return r;
+ }
+};
diff --git a/java/pablotron/luigi/actions/TextAction.java b/java/pablotron/luigi/actions/TextAction.java
new file mode 100644
index 0000000..3024f23
--- /dev/null
+++ b/java/pablotron/luigi/actions/TextAction.java
@@ -0,0 +1,22 @@
+package pablotron.luigi.actions;
+
+import java.util.Map;
+import pablotron.luigi.actions.Action;
+import pablotron.luigi.Filter;
+import pablotron.luigi.LuigiError;
+
+public final class TextAction implements Action {
+ private final String text;
+
+ public TextAction(final String text) {
+ this.text = text;
+ }
+
+ public String run(
+ Map<String, Filter.Handler> filters,
+ Map<String, String> args
+ ) throws LuigiError {
+ return this.text;
+ }
+};
+