package com.hubspot.jinjava.el.ext;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.google.common.base.Throwables;
/**
* Defines a function which will be called in the context of an interpreter instance. Supports named params with default values, as well as var args.
*
* @author jstehler
*
*/
public abstract class AbstractCallableMethod {
public static final Method EVAL_METHOD;
static {
try {
EVAL_METHOD = AbstractCallableMethod.class.getMethod("evaluate", Object[].class);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
private final String name;
private final LinkedHashMap<String, Object> argNamesWithDefaults;
public AbstractCallableMethod(String name, LinkedHashMap<String, Object> argNamesWithDefaults) {
this.name = name;
this.argNamesWithDefaults = argNamesWithDefaults;
}
public Object evaluate(Object... args) {
Map<String, Object> argMap = new LinkedHashMap<>(argNamesWithDefaults);
Map<String, Object> kwargMap = new LinkedHashMap<>();
List<Object> varArgs = new ArrayList<>();
int argPos = 0;
for (Map.Entry<String, Object> argEntry : argMap.entrySet()) {
if (argPos < args.length) {
Object arg = args[argPos++];
// once we hit the first named parameter, the rest must be named parameters...
if (arg instanceof NamedParameter) {
argPos--;
break;
}
argEntry.setValue(arg);
} else {
break;
}
}
// consumeth thyne named params
for (int i = argPos; i < args.length; i++) {
Object arg = args[i];
if (arg instanceof NamedParameter) {
NamedParameter param = (NamedParameter) arg;
if (argMap.containsKey(param.getName())) {
argMap.put(param.getName(), param.getValue());
} else {
kwargMap.put(param.getName(), param.getValue());
}
} else {
varArgs.add(arg);
}
}
return doEvaluate(argMap, kwargMap, varArgs);
}
public abstract Object doEvaluate(Map<String, Object> argMap, Map<String, Object> kwargMap, List<Object> varArgs);
public String getName() {
return name;
}
public List<String> getArguments() {
return new ArrayList<>(argNamesWithDefaults.keySet());
}
public Map<String, Object> getDefaults() {
return argNamesWithDefaults;
}
}