Saturday, February 17, 2018, 11:56:43 AM, Jacques Le Roux wrote:

> Hi,
>
> I must say it's much easier for me to understand Jacopo's solution.

That's not really a solution though, rather a work around that works
in some cases, but not in others. Jacopo basically says, as far as I
see, that we don't have to make FreeMarker even bigger only to address
such a rare use case.

> But I'm currently not a Freemarker heavy user, so maybe for those
> users an integrated syntax is better.
>
> When I think about it, I had once to use Freemarker heavily for a
> small CMS creation. And then indeed I think having
> .get_optional_template would have 
> been a plus. Because it's not a workaround, it's more flexible and allows 
> more.
>
> To be frank I was not aware of the special variables and the syntax
> is not easy, but all in all I think it's worth it.
>
> Jacques
>
>
> Le 16/02/2018 à 08:04, Daniel Dekany a écrit :
>> Some more opinions guys? Especially as we got one opinion against the
>> feature.
>>
>>
>> Tuesday, February 13, 2018, 9:59:41 AM, Daniel Dekany wrote:
>>
>>> Tuesday, February 13, 2018, 9:28:18 AM, Jacopo Cappellato wrote:
>>>
>>>> For less common use cases like this my preference is to defer the
>>>> implementation to the template developer rather than adding complexity to
>>>> the language.
>>>> If I understand the use case that originated this request, something
>>>> similar could be achieved with a simple trick like the following:
>>>> 1) the calling code would be:
>>>> <#include "possibly-missing-template.ftl" ignore_missing=true>
>>>> <#if !processed??>
>>>>          The template was not found or processed!
>>>> </#if>
>>>> 2) somewhere in possibly-missing-template.ftl (i.e. at the bottom of it) we
>>>> add an assign directive like:
>>>> <#assign processed=true>
>>>>
>>>> There are some cons to this approach (the most relevant one is that the
>>>> referenced template has to contain the #assign directive) but FM users
>>>> could live with this approach and in the meantime we could try to get their
>>>> feedback to better understand how much this requirement is desired to
>>>> justify a change to the codebase.
>>> The need for optional includes is something that was brought up for
>>> several times during the years. It's mostly needed for some custom
>>> fallback logic as far as I can tell. (While there's #include
>>> ignore_missing=true for a while, it doesn't let you to take some extra
>>> action depending on if the template is missing.)
>>>
>>> As of it's important enough to add a new feature of this weight (which
>>> low, as it's just yet another special variable, no new directive or
>>> syntax): It's a template language, and in that context
>>> including/importing other templates is probably an important enough
>>> topic to warrant some extras.
>>>
>>>> Jacopo
>>>>
>>>> On Sun, Feb 11, 2018 at 10:02 PM, Daniel Dekany <ddek...@apache.org> wrote:
>>>>
>>>>> See the RFE here:
>>>>> https://issues.apache.org/jira/browse/FREEMARKER-84
>>>>>
>>>>> As you see, the first consensus was introducing `.last_include_found`,
>>>>> but it has two problems:
>>>>>
>>>>> * Sometimes it happens that if, and only if the template exists then
>>>>>    you want to do (usually print) something *before* it. Problem is, by
>>>>>    the time you know that from `.last_include_found`, it's too late, as
>>>>>    the template was already processed.
>>>>>
>>>>> * Like many global state variables in general, this can lead to some
>>>>>    confusing edge cases and hard-to-follow code. Like, if `#include`
>>>>>    throws an exception, which is then handled by the user with
>>>>>    `#attempt`/`#recover`, then `.last_include_found` may or may not be
>>>>>    updated, as perhaps we haven't yet reached the point where it can be
>>>>>    told if the template exists. (Consider an expression evaluation
>>>>>    error in the `#include` parameter, or an I/O error due to which we
>>>>>    can't access the template directory). Also there are some public
>>>>>    `include` methods in the `Environment` API, but they can't set this
>>>>>    variable, as they return a `Template`, and the variable must be set
>>>>>    after the `Template` was processed, unless the template was missing.
>>>>>    (If you can't figure out why it must be done that way, that proves
>>>>>    again how tricky this is... think about includes inside includes.)
>>>>>
>>>>> So, I propose the solution below. Maybe somewhat difficult to grasp
>>>>> first, but it meant to be used rarely, and mostly by "experts"...
>>>>> Let's hope SO and examples in the Manual will help people though. (-;
>>>>>
>>>>> Introduce a new special variable (see
>>>>> https://freemarker.apache.org/docs/ref_specvar.html) called
>>>>> "get_optional_template", which is a TemplateMethodModelEx with these
>>>>> parameters:
>>>>>
>>>>> 1. template name (maybe a relative path, resolved as #include/#import
>>>>> does it) 2. A hash that can have the following keys: "parse",
>>>>> "encoding" (similarly to
>>>>> https://freemarker.apache.org/docs/ref_directive_include.
>>>>> html#ref.directive.include).
>>>>>
>>>>> Example method call (the `.` prefix is the special variable reference
>>>>> syntax):
>>>>>
>>>>>    <#assign t = .get_optional_template("foo.ftl", { 'encoding': 'utf-8' 
>>>>> })>
>>>>>
>>>>> The method returns a hash (`t` above) that contains the following keys:
>>>>>
>>>>> - "include": directive (or missing); `<@t.include />` has similar
>>>>>    effect as `<#include "foo.ftl">`
>>>>>
>>>>> - "import": method (or missing); returns a namespace. `<#assign f =
>>>>>    t.import()>` has similar effect as `<#import 'foo.ftl' as f>`
>>>>>
>>>>> - "exists": boolean; returns if the template was found.
>>>>>
>>>>> The method call loads the target template eagerly, i.e., it won't wait
>>>>> until `t.include`, `t.exist` etc. is actually used.
>>>>>
>>>>> Note that the hash is returned even if the template wasn't found (but
>>>>> then it won't contain "include" and "import", and "exists" will be
>>>>> `false`). If some other error occurs, like an I/O error other than a
>>>>> "template not found", or the template has invalid syntax, it will
>>>>> throw exception (just like #include).
>>>>>
>>>>> Use cases:
>>>>>
>>>>> - `#include` with fallback templates or fallback macro (note how we
>>>>>    can use the `exp!defaultExp` operator):
>>>>>
>>>>>    <@.get_optional_template('foo.ftl')
>>>>>        !.get_optional_template('bar.ftl').include
>>>>>        !defaultMacro  />
>>>>>
>>>>> - Doing something before `#include` if the template exists:
>>>>>
>>>>>      <#assign t = .get_optional_template('foo.ftl')>
>>>>>      <#if t.exists>
>>>>>        Do before existing template
>>>>>        <@t.include />
>>>>>      </#if>
>>>>>
>>>>> Opinions?
>>>>>
>>>>> --
>>>>> Thanks,
>>>>>   Daniel Dekany
>>>>>
>>>>>
>
>

-- 
Thanks,
 Daniel Dekany

Reply via email to