* empty string binding values will be considered undefined

* convenience global functions any and allOf to we can easily evaluate many closures in one go
This commit is contained in:
Reinhard Pointner 2013-12-20 13:27:22 +00:00
parent dffcf5aa2b
commit a7b0920d33
2 changed files with 44 additions and 32 deletions

View File

@ -1,7 +1,5 @@
package net.sourceforge.filebot.format; package net.sourceforge.filebot.format;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.HashSet; import java.util.HashSet;
@ -13,59 +11,61 @@ import javax.script.Bindings;
import net.sourceforge.tuned.ExceptionUtilities; import net.sourceforge.tuned.ExceptionUtilities;
public class ExpressionBindings extends AbstractMap<String, Object> implements Bindings { public class ExpressionBindings extends AbstractMap<String, Object> implements Bindings {
protected final Object bindingBean; protected final Object bindingBean;
protected final Map<String, Method> bindings = new TreeMap<String, Method>(String.CASE_INSENSITIVE_ORDER); protected final Map<String, Method> bindings = new TreeMap<String, Method>(String.CASE_INSENSITIVE_ORDER);
protected final Method undefined; protected final Method undefined;
public ExpressionBindings(Object bindingBean) { public ExpressionBindings(Object bindingBean) {
this.bindingBean = bindingBean; this.bindingBean = bindingBean;
// get method bindings // get method bindings
for (Method method : bindingBean.getClass().getMethods()) { for (Method method : bindingBean.getClass().getMethods()) {
Define define = method.getAnnotation(Define.class); Define define = method.getAnnotation(Define.class);
if (define != null) { if (define != null) {
for (String name : define.value()) { for (String name : define.value()) {
Method existingBinding = bindings.put(name, method); Method existingBinding = bindings.put(name, method);
if (existingBinding != null) if (existingBinding != null)
throw new IllegalArgumentException(String.format("Illegal binding {%s} on %s", name, method.getName())); throw new IllegalArgumentException(String.format("Illegal binding {%s} on %s", name, method.getName()));
} }
} }
} }
// extract mapping that handles undefined bindings // extract mapping that handles undefined bindings
undefined = bindings.remove(Define.undefined); undefined = bindings.remove(Define.undefined);
} }
protected boolean isUndefined(Object value) {
if (value instanceof CharSequence) {
return ((CharSequence) value).length() <= 0;
}
return value == null;
}
public Object getBindingBean() { public Object getBindingBean() {
return bindingBean; return bindingBean;
} }
protected Object evaluate(final Method method) throws Exception { protected Object evaluate(final Method method) throws Exception {
Object value = method.invoke(bindingBean); Object value = method.invoke(bindingBean);
if (value != null) { if (!isUndefined(value)) {
return value; return value;
} }
// invoke fallback method // invoke fallback method
return undefined.invoke(bindingBean); return undefined.invoke(bindingBean);
} }
@Override @Override
public Object get(Object key) { public Object get(Object key) {
Method method = bindings.get(key); Method method = bindings.get(key);
if (method != null) { if (method != null) {
try { try {
return evaluate(method); return evaluate(method);
@ -73,61 +73,53 @@ public class ExpressionBindings extends AbstractMap<String, Object> implements B
throw new BindingException(key.toString(), ExceptionUtilities.getRootCauseMessage(e), e); throw new BindingException(key.toString(), ExceptionUtilities.getRootCauseMessage(e), e);
} }
} }
return null; return null;
} }
@Override @Override
public Object put(String key, Object value) { public Object put(String key, Object value) {
// bindings are immutable // bindings are immutable
return null; return null;
} }
@Override @Override
public Object remove(Object key) { public Object remove(Object key) {
// bindings are immutable // bindings are immutable
return null; return null;
} }
@Override @Override
public boolean containsKey(Object key) { public boolean containsKey(Object key) {
return bindings.containsKey(key); return bindings.containsKey(key);
} }
@Override @Override
public Set<String> keySet() { public Set<String> keySet() {
return bindings.keySet(); return bindings.keySet();
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return bindings.isEmpty(); return bindings.isEmpty();
} }
@Override @Override
public Set<Entry<String, Object>> entrySet() { public Set<Entry<String, Object>> entrySet() {
Set<Entry<String, Object>> entrySet = new HashSet<Entry<String, Object>>(); Set<Entry<String, Object>> entrySet = new HashSet<Entry<String, Object>>();
for (final String key : keySet()) { for (final String key : keySet()) {
entrySet.add(new Entry<String, Object>() { entrySet.add(new Entry<String, Object>() {
@Override @Override
public String getKey() { public String getKey() {
return key; return key;
} }
@Override @Override
public Object getValue() { public Object getValue() {
return get(key); return get(key);
} }
@Override @Override
public Object setValue(Object value) { public Object setValue(Object value) {
@ -135,8 +127,8 @@ public class ExpressionBindings extends AbstractMap<String, Object> implements B
} }
}); });
} }
return entrySet; return entrySet;
} }
} }

View File

@ -172,7 +172,7 @@ String.metaClass.ascii = { fallback = ' ' -> delegate.transliterate("Any-Latin;L
/** /**
* General helpers and utilities * General helpers and utilities
*/ */
def c(c) { def c(Closure c) {
try { try {
return c.call() return c.call()
} catch (Throwable e) { } catch (Throwable e) {
@ -180,6 +180,26 @@ def c(c) {
} }
} }
def any(Closure... closures) {
return closures.findResult{ c ->
try {
return c.call()
} catch (Throwable e) {
return null
}
}
}
def allOf(Closure... closures) {
return closures.toList().findResults{ c ->
try {
return c.call()
} catch (Throwable e) {
return null
}
}
}
def csv(path, delim = ';', keyIndex = 0, valueIndex = 1) { def csv(path, delim = ';', keyIndex = 0, valueIndex = 1) {
def f = path as File def f = path as File
def values = [:] def values = [:]