diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/Makefile | 14 | ||||
| -rw-r--r-- | java/pablotron/luigi/Filter.java | 89 | ||||
| -rw-r--r-- | java/pablotron/luigi/FilterReference.java | 11 | ||||
| -rw-r--r-- | java/pablotron/luigi/LuigiError.java | 7 | ||||
| -rw-r--r-- | java/pablotron/luigi/Parser.java | 114 | ||||
| -rw-r--r-- | java/pablotron/luigi/Template.java | 37 | ||||
| -rw-r--r-- | java/pablotron/luigi/actions/Action.java | 12 | ||||
| -rw-r--r-- | java/pablotron/luigi/actions/FilterAction.java | 41 | ||||
| -rw-r--r-- | java/pablotron/luigi/actions/TextAction.java | 22 | 
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("&"); +              break; +            case '<': +              r.append("<"); +              break; +            case '>': +              r.append(">"); +              break; +            case '\'': +              r.append("'"); +              break; +            case '"': +              r.append("""); +              break; +            default: +              r.append(c); +          } +        } + +        return r.toString(); +/*  + *         return val + *           .replace("&", "&") + *           .replace("<", "<") + *           .replace(">", ">") + *           .replace("'", "'") + *           .replace("\"", """); + */  +      } +    }); +  }}; +}; 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; +  } +}; + | 
