.get_optional_template(name[, options]) now implemented in the 2.3-gae
and 2.3 branches. Testing/feedback is welcome!

See commit:
https://github.com/apache/incubator-freemarker/commit/51c2476621809d8f4183f23e894be0106cabe810

You can find some examples in the tests:
https://github.com/apache/incubator-freemarker/blob/2.3-gae/src/test/java/freemarker/core/GetOptionalTemplateTest.java


Sunday, February 11, 2018, 10:02:30 PM, Daniel Dekany 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

Reply via email to