I’d like to up-level this discussion a bit from the specific API suggestions, 
which are of course meant to be evocative examples.

The examples here are obviously useful; I can imagine use cases for all of 
them.  I’m a little concerned about adding them as “point” solutions, though, 
because I’d have concerns about whether they will work together.  Which makes 
me think that the withToString example might prefer to be an abstract class 
rather than a combinator, so that if users want to override various things, 
those will work together.

On Nov 27, 2023, at 12:00 PM, Tagir Valeev 
<[email protected]<mailto:[email protected]>> wrote:

Hello!

As we expect that people will create custom template processors, we can 
simplify their lives.

First, it could be common to add a finisher transformation to an existing 
processor. I think that for many purposes it would be enough to use STR 
processor as a starter, and then create a custom domain object from the 
resulting string. This could be simplified if we add a method 'andThen' to the 
Processor interface:


default <RR> Processor<RR, E> andThen(Function<R, RR> finisher) {
    Objects.requireNonNull(finisher);
    return st -> finisher.apply(process(st));
}

Second, I think that many processors may want to keep string parts intact but 
handle embedded expressions in a special way, effectively replacing the default 
'String.valueOf' behavior of the standard STR processor. We can provide a way 
doing this, encapsulating all the ceremony. Something like this:


static StringTemplate.Processor<String, RuntimeException> 
withToString(Function<Object, String> toStringFunction) {
    Objects.requireNonNull(toStringFunction);
    return st -> {
        StringBuilder sb = new StringBuilder();
        Iterator<String> fragIter = st.fragments().iterator();

        for (Object value : st.values()) {
            sb.append(fragIter.next());
            sb.append(toStringFunction.apply(value));
        }

        sb.append(fragIter.next());
        return sb.toString();
    };
}

withToString(String::valueOf) should be equivalent to the STR template (in 
functionality, not in performance)

Now, one can easily build interesting things like:


StringTemplate.Processor<Pattern, RuntimeException> REGEXP =
   withToString(obj -> Pattern.quote(obj.toString())).andThen(Pattern::compile);

What do you think?

With best regards,
Tagir Valeev

Reply via email to