ListPlaceholderDefinition.java

package com.timtrense.template.lang.std;

import com.timtrense.template.Context;
import com.timtrense.template.PlaceholderDefinition;
import com.timtrense.template.TemplatePart;
import lombok.NonNull;

import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * The default {@link PlaceholderDefinition} for a {@link ListPlaceholder}.
 * <p>
 * The placeholder needs to be written like
 * <pre>
 * variableName
 * (SEPARATOR WHITESPACE? defaultValue)?
 * (SEPARATOR WHITESPACE? delimiter)?
 * (SEPARATOR WHITESPACE? prefix)?
 * (SEPARATOR WHITESPACE? suffix)?
 * </pre>
 * where SEPARATOR may be a given {@link Character} and elements with an <b>?</b> are optional.
 * E.G. {@code myVariable,defaultValue} resolving to either the value of the {@link Context}-variable "myVariable" or
 * the given default value if that variable has a {@code null} value.
 * <p>
 * Since one may want to use SEPARATOR as a delimiter, one can specify the delimiter to be an empty string to
 * make this happen. E.g. {@code $(var,default,,[,])} will make for a separator being ',' due to the third argument
 * being left blank.
 *
 * @author Tim Trense
 * @since 1.1
 */
public class ListPlaceholderDefinition implements PlaceholderDefinition {

    private static final int GROUP_VARIABLE_NAME = 1;
    private static final int GROUP_DEFAULT_VALUE = 2;
    private static final int GROUP_DELIMITER = 3;
    private static final int GROUP_PREFIX = 4;
    private static final int GROUP_SUFFIX = 5;

    @NonNull
    private final Pattern pattern;

    private final String separator;

    /**
     * @param s separator, see {@link ListPlaceholderDefinition}
     */
    public ListPlaceholderDefinition(char s) {
        String requiredComponent = "([^" + s + "]+)";
        String maybeBlankComponent = "([^" + s + "]*)";
        String componentSeparator = s + "\\s*";
        pattern = Pattern.compile("(\\w[^" + s + "]*)"
                        + "(?:" + componentSeparator + requiredComponent + ")?" // defaultValue
                        + "(?:" + componentSeparator + maybeBlankComponent + ")?" // delimiter
                        + "(?:" + componentSeparator + requiredComponent + ")?" // prefix
                        + "(?:" + componentSeparator + requiredComponent + ")?", // suffix
                Pattern.CASE_INSENSITIVE);
        this.separator = String.valueOf(s);
    }

    @Override
    public TemplatePart compile(@NonNull String placeholderText) {
        Matcher matcher = pattern.matcher(placeholderText);
        if (!matcher.matches()) {
            return null;
        }
        String name = matcher.group(GROUP_VARIABLE_NAME);
        Object defaultValue = ListPlaceholder.DEFAULT_VALUE;
        String prefix = ListPlaceholder.DEFAULT_PREFIX;
        String suffix = ListPlaceholder.DEFAULT_SUFFIX;
        String delimiter = ListPlaceholder.DEFAULT_DELIMITER;
        if (matcher.groupCount() > GROUP_VARIABLE_NAME) {
            defaultValue = matcher.group(GROUP_DEFAULT_VALUE);
//            if (defaultValue == null) {
//                defaultValue = ListPlaceholder.DEFAULT_VALUE; // DEFAULT_VALUE==null
//            }
        }
        if (matcher.groupCount() > GROUP_DEFAULT_VALUE) {
            delimiter = Objects.requireNonNullElse(matcher.group(GROUP_DELIMITER), ListPlaceholder.DEFAULT_DELIMITER);
        }
        if (matcher.groupCount() > GROUP_DELIMITER) {
            prefix = Objects.requireNonNullElse(matcher.group(GROUP_PREFIX), ListPlaceholder.DEFAULT_PREFIX);
        }
        if (matcher.groupCount() > GROUP_PREFIX) {
            suffix = Objects.requireNonNullElse(matcher.group(GROUP_SUFFIX), ListPlaceholder.DEFAULT_SUFFIX);
        }

        if (delimiter.isEmpty()) {
            delimiter = separator;
        }

        return new ListPlaceholder(name, defaultValue, delimiter, prefix, suffix);
    }
}