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

org.beryx.hbs.Helpers.groovy Maven / Gradle / Ivy

/*
 * Copyright 2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.beryx.hbs

import com.github.jknack.handlebars.Context
import com.github.jknack.handlebars.Handlebars
import com.github.jknack.handlebars.Helper
import com.github.jknack.handlebars.Options
import groovy.transform.stc.ClosureParams
import groovy.transform.stc.FromAbstractTypeMethods
import groovy.util.logging.Slf4j
import org.apache.commons.lang3.LocaleUtils

@Slf4j
enum Helpers implements Helper {
    DEF ("def", { varName, options ->
        Context ctx = options.context
        def val = (options.params.size() > 0) ? options.prm(0) : options.fn()
        varName = from(varName)
        ctx.combine(varName, val)
        options.buffer()
    }),

    IFB ("ifb", { value, options ->
        Options.Buffer buffer = options.buffer()
        value = from(value)
        if(isNumber(value)) {
            value = asNumber(value)
        }
        buffer.append(asBoolean(value) ? options.fn() : options.inverse())
        buffer
    }),

    DEFAULT ("default", { value, options ->
        if(!(value instanceof Boolean) && Handlebars.Utils.isEmpty(value)) {
            value = options.prm(0)
        }
        Options.Buffer buffer = options.buffer()
        buffer.append(String.valueOf(from(value)))
        buffer
    }),

    LENGTH ("length", { list, options ->
        Options.Buffer buffer = options.buffer()
        buffer.append("${list.size()}")
        buffer
    }),

    COMPARE ("compare", { operand1, options ->
        Options.Buffer buffer = options.buffer()
        operand1 = from(operand1)
        def op = options.prm(0)
        def operand2 = options.prm(1)

        boolean asString = options.hash("asString", false)
        if(!asString && isNumber(operand1) && isNumber(operand2)) {
            operand1 = operand1 as double
            operand2 = operand2 as double
        } else {
            operand1 = operand1.toString()
            operand2 = operand2.toString()
        }
        int res = operand1.compareTo(operand2)

        def cmp = {
            switch (op) {
                case '==': return res == 0
                case '!=': return res != 0
                case '<': return res < 0
                case '<=': return res <= 0
                case '>': return res > 0
                case '>=': return res >= 0
            }
        }
        buffer.append(cmp() ? 'true' : 'false')
        buffer
    }),

    MATH ("math", { value, options ->
        Options.Buffer buffer = options.buffer()
        def op = options.prm(0)
        def operand1 = asNumber(from(value))
        def operand2 = asNumber(options.prm(1))

        def cmp = {
            switch (op) {
                case '+': return operand1 + operand2
                case '-': return operand1 - operand2
                case '*': return operand1 * operand2
                case '/': return operand1 / operand2
                case '%': return operand1 % operand2
                case '**': return Math.pow(operand1, operand2)
            }
        }
        int decimals = options.hash('decimals', -1)
        if(decimals < 0) {
            buffer.append(cmp().toString())
        } else {
            def format = "%.${decimals}f"
            String localeStr = options.hash("locale", Locale.getDefault().toString());
            Locale locale = LocaleUtils.toLocale(localeStr);
            buffer.append(String.format(locale, format, cmp() as double))
        }
        buffer
    }),

    NOT ("not", { value, options ->
        Options.Buffer buffer = options.buffer()
        value = from(value)
        buffer.append(Boolean.toString(!asBoolean(value)))
        buffer
    }),

    AND ("and", { operand1, options ->
        Options.Buffer buffer = options.buffer()
        boolean res = asBoolean(from(operand1))
        for(int i=0; res && (i < options.params.length); i++) {
            res = asBoolean(options.prm(i))
        }
        buffer.append(Boolean.toString(res))
        buffer
    }),

    OR ("or", { operand1, options ->
        Options.Buffer buffer = options.buffer()
        boolean res = asBoolean(from(operand1))
        for(int i=0; !res && (i < options.params.length); i++) {
            res = asBoolean(options.prm(i))
        }
        buffer.append(Boolean.toString(res))
        buffer
    }),

    AS_JAVA_ID("asJavaId", { text, options ->
        Options.Buffer buffer = options.buffer()
        text = from(text)
        if(!text) {
            buffer.append('_')
        } else {
            boolean useCamelCase = options.hash('camelCase', true)
            boolean useUnderscore = options.hash('underscore', false)
            boolean startNewPart = false
            boolean first = true
            StringBuilder sb = new StringBuilder()
            def chars = text.toString().trim().chars
            chars.each {ch ->
                if(Character.isJavaIdentifierPart(ch)) {
                    if((first && !Character.isJavaIdentifierStart(ch)) || (startNewPart && useUnderscore)) sb << '_'
                    sb << (first ? ch.toLowerCase() : (startNewPart ? (useCamelCase ? ch.toUpperCase() : ch.toLowerCase()) : ch))
                    startNewPart = false
                    first= false
                } else {
                    startNewPart = !first
                }
            }
            buffer.append(sb.toString())
        }
        buffer
    }),

    JAVA_COMMENT("javaComment", { String commentFile, Options options ->
        Options.Buffer buffer = options.buffer()

        String comment = null
        try {
            comment = options.handlebars.loader.sourceAt(commentFile).content()
        } catch (Exception e) {
            log.debug "Comment file $commentFile not found (${options.handlebars.loader.resolve(commentFile)})"
        }
        if(comment) {
            buffer.append('/*\n')
            comment.eachLine { line ->
                buffer.append(' * ').append(line).append('\n')
            }
            buffer.append(' */\n')
        }
        buffer
    })


    static {
        Options.metaClass.prm = { index -> from(delegate.params[index]) }
    }

    final String helperName
    private final Closure closure;

    Helpers(String helperName, @ClosureParams(value=FromAbstractTypeMethods, options="com.github.jknack.handlebars.Helper") Closure closure) {
        this.closure = closure
        this.helperName = helperName
    }

    @Override
    CharSequence apply(context, Options options) throws IOException {
        closure.call(context, options)
    }

    static void register(Handlebars handlebars) {
        Helpers.values().each { helper -> handlebars.registerHelper(helper.helperName, helper)}
    }

    private static from(param) {
        if(param instanceof Options.NativeBuffer) {
            param.writer.toString()
        } else {
            param
        }
    }

    private static boolean asBoolean(value) {
        if(value instanceof CharSequence) {
            if('true'.equalsIgnoreCase(value.toString())) return true
            if('false'.equalsIgnoreCase(value.toString())) return false
        }
        !Handlebars.Utils.isEmpty(value)
    }

    private static boolean isNumber(value) {
        if(value == null) return false
        if(value instanceof Number) return true
        try {
            Double.parseDouble(value.toString())
            return true
        } catch (e) {
            return false
        }
    }

    private static Number asNumber(value) {
        if(value == null) return null
        if(value instanceof Number) return value
        try {
            return new Long(value.toString())
        } catch (e) {
            return new Double(value.toString())
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy