All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tools4j.groovytables.ClosureMethod.groovy Maven / Gradle / Ivy

package org.tools4j.groovytables
/**
 * User: ben
 * Date: 8/11/2016
 * Time: 6:42 AM
 */
class ClosureMethod implements Callable {
    final Closure closure

    ClosureMethod(final Closure closure) {
        this.closure = closure
    }

    interface ClosureCall{
        T call(Object[] coercedArgs)
    }

    static class ClosureCallUsingDelegateProperties implements ClosureCall{
        private final Closure closure
        private final List columnHeadings

        ClosureCallUsingDelegateProperties(Closure closure, final List columnHeadings) {
            this.columnHeadings = columnHeadings
            this.closure = closure
        }

        def call(Object[] coercedArgs) {
            final Object delegate = new Object()
            int i = 0
            columnHeadings.each { final String heading ->
                delegate.metaClass[heading] = coercedArgs[i++]
            }
            closure.setDelegate(delegate)
            closure.setResolveStrategy(Closure.DELEGATE_FIRST)
            closure.call()
        }
    }

    static class ClosureCallUsingClosureArguments implements ClosureCall {
        private final Closure closure

        ClosureCallUsingClosureArguments(final Closure closure) {
            this.closure = closure
        }

        T call(Object[] coercedArgs) {
            return closure.curry(coercedArgs).call()
        }
    }

    @Override
    ClosureCallPrecursor getCallPrecursor(final List columnHeadings, final Object... rawArgs) {
        if(columnHeadings == null || columnHeadings.size() == 0){
            return getCallPrecursor(rawArgs)
        }
        if(closure.getMaximumNumberOfParameters() > 1){
            throw new IllegalArgumentException("Cannot determine how to call closure.  You have specified column headings" +
                    " " + columnHeadings + " AND you have specified " + closure.getMaximumNumberOfParameters() + " closure parameters." +
                    " Please choose just one approach. i.e. specify column headings, and no closure parameters, or specify closure" +
                    " parameters and no column headings.")
        }
        return new ClosureCallPrecursor(Suitability.SUITABLE, rawArgs, rawArgs, new ClosureCallUsingDelegateProperties(closure, columnHeadings))
    }

    @Override
    ClosureCallPrecursor getCallPrecursor(final Object... rawArgs) {
        Logger.info("    Getting ClosureCallPrecursor with parameters ${closure.getParameterTypes()}")
        if(closure.getMaximumNumberOfParameters() <= 1){
            throw new IllegalArgumentException("Cannot call closure.  Please either specify column headings" +
                    " for each of your " + rawArgs.size() + " columns.  Or, declare " + rawArgs.size() + " arguments" +
                    " in your closure to accept the row values: " + rawArgs)

        } else if(closure.getMaximumNumberOfParameters() > 1 && closure.getMaximumNumberOfParameters() != rawArgs.length){
            throw new IllegalArgumentException("Mismatched number of args, closure has:$closure.maximumNumberOfParameters != table has:$rawArgs.length.  (Please note, use of varargs is not supported).")
        }

        Logger.info("        Correct number of args: $rawArgs.length")
        Suitability worstSuitabilityOfThisExecutable = Suitability.SUITABLE;
        final List coercedResults = new ArrayList<>(closure.getMaximumNumberOfParameters());
        for (int i = 0; i < closure.getParameterTypes().size(); i++) {
            final Class closureParamType = closure.getParameterTypes()[i];
            Object rawArg = rawArgs[i]
            final ValueCoercionResult coercionResult = ValueCoerser.coerceToType(rawArg, closureParamType);
            worstSuitabilityOfThisExecutable = worstSuitabilityOfThisExecutable.worseOf(coercionResult.getSuitability())
            Logger.info("        Coercion result for arg:${rawArg.getClass().simpleName}[$rawArg] to:$closureParamType.simpleName : $coercionResult")
            coercedResults.add(coercionResult);
            if (coercionResult.getSuitability() == Suitability.NOT_SUITABLE) {
                throw new IllegalArgumentException("Error processing row $rawArgs. Could not coerce argument '$rawArg' of class <${rawArg.getClass().simpleName}>" +
                        " to closure argument of type <$closureParamType.>")
            }
        }
        return new ClosureCallPrecursor(
                worstSuitabilityOfThisExecutable,
                rawArgs,
                coercedResults.collect{it.result}.toArray(),
                new ClosureCallUsingClosureArguments(closure)
        );
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy