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