I've also discovered that DirectiveCallPlace.getOrCreateCustomData doesn't 
guarantee that it will be stable.

"the object will be usually created only once, even if multiple threads request 
the value when it's still null.
 It doesn't stand though when providerIdentity mismatches occur"

"if multiple directives that use the custom data feature use the same call 
place, the caching of the custom data can be inefficient, as they will keep 
overwriting each other's custom data"



On Tuesday 3 September 2024 at 19:04:46 BST, Daniel Dekany 
<daniel.dek...@gmail.com> wrote: 





DirectiveCallPlace doesn't make any promises regarding equality (even if in
the current implementation it happens to work), but you can instead use
DirectiveCallPlace.getOrCreateCustomData, which was exactly made for things
like what you try to do.

TemplateDirectiveModel doesn't currently support positionals. But that
feature actually can be implemented in 2.x too. (The 3 branch is not too
relevant, as it's questionable at best if it will ever get enough time, and
even then the point of it is breaking backward compatibility, so it's not
an answer for most current users.)

Yes, directives defined with macros can be called either as
fully positional, or as fully by-name. There's an ambiguity issue with it
otherwise. Like if you have <@m x y=2 />, then currently means that 1st
parameter is the value of x, and 2nd parameter is the boolean result of y
== 2. Because, in FreeMarker, unfortunately, you can write = instead == of
=.

On Tue, Sep 3, 2024 at 5:54 PM Simon Hartley <scrhart...@yahoo.co.uk.invalid>
wrote:

> 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());

>        }
>    }
>
> }
>


-- 
Best regards,
Daniel Dekany

Reply via email to