StandardTemplateLanguage.java
package com.timtrense.template.lang.std;
import com.timtrense.template.PlaceholderDefinition;
import com.timtrense.template.TemplateLanguage;
import com.timtrense.template.TemplatePart;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.Getter;
import lombok.NonNull;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* The default implementation flavor for {@link TemplateLanguage}.
* <p>
* The {@link com.timtrense.template.Template template source text} would look something like:
* <code>
* <p>
* Hello, $(name, World)!
* It is $datetime(time, HH:mm, SOME_DEFAULT) o'clock.
* I like to drive a $enum(carType, MAJOR_BRAND).
* <p>
* Here is an escaped \$sequence() that will just
* be rendered as is (excluding the first '\' )
* </code>
* Basic values are enclosed using {@code ${variable, default} } notation.
* There are basic transformations that can be applied, like {@code $datetime }
* which converts an {@link java.time.temporal.TemporalAccessor} to text using a given format (or ISO-Zoned-Format if omitted).
* Notice that defaults may always be omitted.
* <p>
* Hint: You may either extend from this class or call {@link #placeholderDefinitions}.{@link Map#put(Object, Object) put(name, PlaceholderDefinition)}
* to add custom {@link PlaceholderDefinition placeholder types}
*
* @author Tim Trense
* @since 1.0
*/
public class StandardTemplateLanguage implements TemplateLanguage {
private static final Pattern PLACEHOLDER_WRAPPER = Pattern.compile("\\$([^(]*)\\(([^)]*)\\)");
private static final Map<String, PlaceholderDefinition> PLACEHOLDER_DEFINITIONS = Map.of(
"", new TextPlaceholderDefinition(','),
"datetime", new DateTimePlaceholderDefinition(','),
"enum", new EnumPlaceholderDefinition(','),
"list", new ListPlaceholderDefinition(',')
);
/**
* all known placeholders.
* The getter returns a mutable reference to the internal state to allow for easy "inline" extension of
* the standard language used in one's application.
* While this allows one to tamper with the language after creation, it lowers the learning curve for
* this library. If one prefers an immutable variant of a language, one may
* use {@link ImmutableStandardTemplateLanguage} .
*/
@Getter
@SuppressFBWarnings("EI_EXPOSE_REP")
private final @NonNull Map<String, PlaceholderDefinition> placeholderDefinitions;
/**
* @see StandardTemplateLanguage
*/
public StandardTemplateLanguage() {
placeholderDefinitions = new HashMap<>(PLACEHOLDER_DEFINITIONS);
}
protected StandardTemplateLanguage(@NonNull Map<@NonNull String, @NonNull PlaceholderDefinition> placeholderDefinitions) {
this.placeholderDefinitions = placeholderDefinitions;
}
@Override
public char getEscapeSequence() {
return '\\';
}
@Override
public Pattern getPlaceholderWrapperPattern() {
return PLACEHOLDER_WRAPPER;
}
@Override
public TemplatePart compilePlaceholder(Matcher placeholderMatcher) {
String placeholderName = placeholderMatcher.group(1);
PlaceholderDefinition nextPlaceholder = placeholderDefinitions.get(placeholderName);
if (nextPlaceholder == null) {
return null;
}
return nextPlaceholder.compile(placeholderMatcher.group(2));
}
}