* 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:
parent
dffcf5aa2b
commit
a7b0920d33
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = [:]
|
||||||
|
|
Loading…
Reference in New Issue