On Tue, Sep 3, 2024 at 9:35 PM Simon Hartley <[email protected]>
wrote:

> 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"
>

But this only matters if the render_once variable, when you call it as
directive on a given call place, is not always your
single TempalteDirectiveModel implementation. Given the function of that
directive, if that can happen, then all bets are off anyway.


> "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"
>

Same applies as above. This is not a problem for you.

On Tuesday 3 September 2024 at 19:04:46 BST, Daniel Dekany <
> [email protected]> 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 <[email protected]
> .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
>
>

-- 
Best regards,
Daniel Dekany

Reply via email to