Heya,

I was hoping you could verify a couple of things for me.
Please let me know if you would prefer that I make either of these be Stack 
Overflow questions.


1. Is it valid to rely on identity / reference-equality with 
env.getCurrentDirectiveCallPlace() ?
   Is the result stable so that I can store per-Environment data while taking 
advantage of this?
   For reference, below I've included the source for my render_once directive 
to clarify.
   
   
2. I was wondering about the possibility of invoking TemplateDirectiveModel's 
with positional parameters.
   I found https://issues.apache.org/jira/browse/FREEMARKER-63, so does that 
mean I must wait for V3?
   Also am I correct that this implementation makes each parameter be strictly 
either positional or named?
   This seems a shame, since I like the flexibility of being able to choose, 
and some teams will prefer brevity while others explicitness:
   <@my_directive "my arg" /> or <@my_directive param="my arg" />


Many thanks and best regards,
Simon Hartley



//    <#macro require_jQuery>
//        <@render_once>
//            <script 
src="https://code.jquery.com/jquery-3.7.1.min.js";></script><#t>
//        </@render_once>
//    </#macro>
//    <@require_jQuery />  <#-- Renders something -->
//    <@require_jQuery />  <#-- Nothing to render -->
//
// Inspiration: https://templ.guide/syntax-and-usage/render-once/
//
// If you #include a use of this directive multiple times then each will reset 
whether it has rendered.
// If we wanted to work around this, then this directive could be enhanced to 
accept an optional key,
// perhaps using object-equality, rather than reference-equality, e.g. a string 
scalar.
public class RenderOnceDirective implements TemplateDirectiveModel {

    private static final CustomAttribute IDENTITY_BASED_STATE = new 
CustomAttribute(SCOPE_ENVIRONMENT) {
        @Override
        protected Set<?> create() {
            return Collections.newSetFromMap(new IdentityHashMap<>());
        }
    };

    @Override
    public void execute(Environment env, Map params, TemplateModel[] loopVars, 
TemplateDirectiveBody body)
            throws TemplateException, IOException {
        if (!params.isEmpty()) {
            throw new TemplateModelException("This directive doesn't allow 
parameters.");
        }
        if (loopVars.length != 0) {
            throw new TemplateModelException("This directive doesn't support 
loop variables.");
        }
        if (body == null) {
            throw new TemplateModelException("missing body");
        }

        @SuppressWarnings("unchecked")
        Set<Object> alreadyRun = (Set<Object>) IDENTITY_BASED_STATE.get(env);
        Object key = env.getCurrentDirectiveCallPlace();
        boolean firstTime = alreadyRun.add(key);
        if (firstTime) {
            body.render(env.getOut());
        }
    }

}

Reply via email to