Repository: incubator-freemarker Updated Branches: refs/heads/2.3-gae 5f821f174 -> 8286a7bfc
Added ?absoulte_template_name. Necessary additions to the Environment and TemplateNameFormat. Some Manual cleanups related to `.caller_template_name`. Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/8286a7bf Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/8286a7bf Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/8286a7bf Branch: refs/heads/2.3-gae Commit: 8286a7bfcb402e34e67d75d50a5a2ee7c994275e Parents: 5f821f1 Author: ddekany <ddek...@apache.org> Authored: Sat Mar 10 20:56:45 2018 +0100 Committer: ddekany <ddek...@apache.org> Committed: Sat Mar 10 20:56:45 2018 +0100 ---------------------------------------------------------------------- .../freemarker/cache/TemplateNameFormat.java | 42 +++++++- src/main/java/freemarker/cache/_CacheAPI.java | 5 + src/main/java/freemarker/core/BuiltIn.java | 3 +- .../freemarker/core/BuiltInsForStringsMisc.java | 47 +++++++++ src/main/java/freemarker/core/Environment.java | 26 ++++- src/manual/en_US/book.xml | 104 +++++++++++++++++-- .../cache/TemplateNameFormatTest.java | 23 +++- .../core/AbsoluteTemplateNameBITest.java | 72 +++++++++++++ .../manual/AbsoluteTemplateNameBIExample.java | 31 ++++++ .../AbsoluteTemplateNameBIExample-foo.ftl | 19 ++++ .../AbsoluteTemplateNameBIExample-lib.ftl | 38 +++++++ .../dir/AbsoluteTemplateNameBIExample-foo.ftl | 19 ++++ .../dir/AbsoluteTemplateNameBIExample-main.ftl | 24 +++++ .../AbsoluteTemplateNameBIExample-main.ftl.out | 26 +++++ 14 files changed, 463 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/main/java/freemarker/cache/TemplateNameFormat.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateNameFormat.java b/src/main/java/freemarker/cache/TemplateNameFormat.java index 72126bf..e076f93 100644 --- a/src/main/java/freemarker/cache/TemplateNameFormat.java +++ b/src/main/java/freemarker/cache/TemplateNameFormat.java @@ -59,10 +59,10 @@ public abstract class TemplateNameFormat { * template names like {@code "classpath:foo.ftl"} interpreted as an absolute name with scheme {@code "classpath"} * and absolute path "foo.ftl". The scheme name before the {@code ":"} can't contain {@code "/"}, or else it's * treated as a malformed name. The scheme part can be separated either with {@code "://"} or just {@code ":"} from - * the path. Hence, {@code myschme:/x} is normalized to {@code myschme:x}, while {@code myschme:///x} is normalized - * to {@code myschme://x}, but {@code myschme://x} or {@code myschme:/x} aren't changed by normalization. It's up - * the {@link TemplateLoader} to which the normalized names are passed to decide which of these scheme separation - * conventions are valid (maybe both).</li> + * the path. Hence, {@code myscheme:/x} is normalized to {@code myscheme:x}, while {@code myscheme:///x} is + * normalized to {@code myscheme://x}, but {@code myscehme://x} or {@code myscheme:/x} aren't changed by + * normalization. It's up the {@link TemplateLoader} to which the normalized names are passed to decide which of + * these scheme separation conventions are valid (maybe both).</li> * * <li>{@code ":"} is not allowed in template names, except as the scheme separator (see previous point). * @@ -131,11 +131,21 @@ public abstract class TemplateNameFormat { * becomes to "foo.ftl". * * @param name - * The root based name. Not {@code null}. + * The root based name (a name that's either absolute or relative to the root). Not {@code null}. * * @return The normalized root based name. Not {@code null}. */ abstract String normalizeRootBasedName(String name) throws MalformedTemplateNameException; + + /** + * Converts a root based name to an absolute name, which is useful if you need to pass a name to something that + * doesn't necessary resolve relative paths relative to the root (like the {@code #include} directive). + * + * @param name + * The root based name (a name that's either absolute or relative to the root). Not {@code null}. + */ + // TODO [FM3] This is the kind of complication why normalized template names should just be absolute paths. + abstract String rootBasedNameToAbsoluteName(String name) throws MalformedTemplateNameException; private static final class Default020300 extends TemplateNameFormat { @Override @@ -200,6 +210,17 @@ public abstract class TemplateNameFormat { } return path; } + + @Override + String rootBasedNameToAbsoluteName(String name) throws MalformedTemplateNameException { + if (name.indexOf("://") > 0) { + return name; + } + if (!name.startsWith("/")) { + return "/" + name; + } + return name; + } @Override public String toString() { @@ -429,6 +450,17 @@ public abstract class TemplateNameFormat { return path; } + + @Override + String rootBasedNameToAbsoluteName(String name) throws MalformedTemplateNameException { + if (findSchemeSectionEnd(name) != 0) { + return name; + } + if (!name.startsWith("/")) { + return "/" + name; + } + return name; + } @Override public String toString() { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/main/java/freemarker/cache/_CacheAPI.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/_CacheAPI.java b/src/main/java/freemarker/cache/_CacheAPI.java index ead17de..ceedf9e 100644 --- a/src/main/java/freemarker/cache/_CacheAPI.java +++ b/src/main/java/freemarker/cache/_CacheAPI.java @@ -41,5 +41,10 @@ public final class _CacheAPI { throws MalformedTemplateNameException { return templateNameFormat.normalizeRootBasedName(name); } + + public static String rootBasedNameToAbsoluteName(TemplateNameFormat templateNameFormat, String rootBasedName) + throws MalformedTemplateNameException { + return templateNameFormat.rootBasedNameToAbsoluteName(rootBasedName); + } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/main/java/freemarker/core/BuiltIn.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/BuiltIn.java b/src/main/java/freemarker/core/BuiltIn.java index e830cb1..78b9e45 100644 --- a/src/main/java/freemarker/core/BuiltIn.java +++ b/src/main/java/freemarker/core/BuiltIn.java @@ -84,13 +84,14 @@ abstract class BuiltIn extends Expression implements Cloneable { static final Set<String> CAMEL_CASE_NAMES = new TreeSet<String>(); static final Set<String> SNAKE_CASE_NAMES = new TreeSet<String>(); - static final int NUMBER_OF_BIS = 264; + static final int NUMBER_OF_BIS = 266; static final HashMap<String, BuiltIn> BUILT_INS_BY_NAME = new HashMap(NUMBER_OF_BIS * 3 / 2 + 1, 1f); static { // Note that you must update NUMBER_OF_BIS if you add new items here! putBI("abs", new absBI()); + putBI("absolute_template_name", "absoluteTemplateName", new BuiltInsForStringsMisc.absolute_template_nameBI()); putBI("ancestors", new ancestorsBI()); putBI("api", new BuiltInsForMultipleTypes.apiBI()); putBI("boolean", new BuiltInsForStringsMisc.booleanBI()); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/main/java/freemarker/core/BuiltInsForStringsMisc.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/BuiltInsForStringsMisc.java b/src/main/java/freemarker/core/BuiltInsForStringsMisc.java index e4b18a2..e1bf88b 100644 --- a/src/main/java/freemarker/core/BuiltInsForStringsMisc.java +++ b/src/main/java/freemarker/core/BuiltInsForStringsMisc.java @@ -20,12 +20,17 @@ package freemarker.core; import java.io.StringReader; +import java.util.List; +import freemarker.template.MalformedTemplateNameException; import freemarker.template.SimpleNumber; import freemarker.template.Template; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateException; +import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; +import freemarker.template.TemplateScalarModel; class BuiltInsForStringsMisc { @@ -118,6 +123,48 @@ class BuiltInsForStringsMisc { } } } + + static class absolute_template_nameBI extends BuiltInForString { + @Override + TemplateModel calculateResult(String s, Environment env) throws TemplateException { + return new AbsoluteTemplateNameResult(s, env); + } + + private class AbsoluteTemplateNameResult implements TemplateScalarModel, TemplateMethodModelEx { + private final String pathToResolve; + private final Environment env; + + public AbsoluteTemplateNameResult(String pathToResolve, Environment env) { + this.pathToResolve = pathToResolve; + this.env = env; + } + + public Object exec(List args) throws TemplateModelException { + checkMethodArgCount(args, 1); + return resolvePath(getStringMethodArg(args, 0)); + } + + public String getAsString() throws TemplateModelException { + return resolvePath(getTemplate().getName()); + } + + /** + * @param basePath Maybe {@code null} + */ + private String resolvePath(String basePath) throws TemplateModelException { + try { + return env.rootBasedToAbsoluteTemplateName(env.toFullTemplateName(basePath, pathToResolve)); + } catch (MalformedTemplateNameException e) { + throw new _TemplateModelException(e, + "Can't resolve ", new _DelayedJQuote(pathToResolve), + "to absolute template name using base ", new _DelayedJQuote(basePath), + "; see cause exception"); + } + } + + } + + } // Can't be instantiated private BuiltInsForStringsMisc() { } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/main/java/freemarker/core/Environment.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java index 6c8e202..a6eb6eb 100644 --- a/src/main/java/freemarker/core/Environment.java +++ b/src/main/java/freemarker/core/Environment.java @@ -2739,9 +2739,12 @@ public final class Environment extends Configurable { /** * Resolves a reference to a template (like the one used in {@code #include} or {@code #import}), assuming a base - * name. This gives a full (that is, absolute), even if non-normalized template name, that could be used for - * {@link Configuration#getTemplate(String)}. This is mostly used when a + * name. This gives a root based, even if non-normalized and possibly non-absolute (but then relative to the root) + * template name, that could be used for {@link Configuration#getTemplate(String)}. This is mostly used when a * template refers to another template. + * <p> + * If you need to guarantee that the result is also an absolute path, then apply + * {@link #rootBasedToAbsoluteTemplateName(String)} on it. * * @param baseName * The name to which relative {@code targetName}-s are relative to. Maybe {@code null} (happens when @@ -2772,6 +2775,25 @@ public final class Environment extends Configurable { return _CacheAPI.toRootBasedName(configuration.getTemplateNameFormat(), baseName, targetName); } + /** + * Converts a root based name (a name that's either relative to the root, or is absolute), which are typically used + * by the API (such as for {@link Configuration#getTemplate(String)}), to an absolute name, which can be safely + * passed to {@code <#include path>} and such, as it won't be misinterpreted to be relative to the directory of the + * template. For example, {@code "foo/bar.ftl"} is converted to {@code "/foo/bar.ftl"}, while {@code "/foo/bar"} or + * {@code "foo://bar/baz"} remains as is, as they are already absolute names (see {@link TemplateNameFormat} for + * more about the format of names). + * + * <p> + * You only need this if the template name will be passed to {@code <#include name>}, {@code <#import name>}, + * {@code .get_optional_template(name)} or a similar construct in a template, otherwise using non-absolute root + * based names is fine. + * + * @since 2.3.28 + */ + public String rootBasedToAbsoluteTemplateName(String rootBasedName) throws MalformedTemplateNameException { + return _CacheAPI.rootBasedNameToAbsoluteName(configuration.getTemplateNameFormat(), rootBasedName); + } + String renderElementToString(TemplateElement te) throws IOException, TemplateException { Writer prevOut = out; try { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/manual/en_US/book.xml ---------------------------------------------------------------------- diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml index 564898a..804cb15 100644 --- a/src/manual/en_US/book.xml +++ b/src/manual/en_US/book.xml @@ -12450,6 +12450,11 @@ grant codeBase "file:/path/to/freemarker.jar" <listitem> <para><link + linkend="ref_builtin_absolute_template_name">absolute_template_name</link></para> + </listitem> + + <listitem> + <para><link linkend="ref_builtin_ancestors">ancestors</link></para> </listitem> @@ -17832,6 +17837,64 @@ Sorted by name.last: useful. If you need to use these in your normal page templates, you may revisit the data-model so you don't need to use these.</para> + <section xml:id="ref_builtin_absolute_template_name"> + <title>absolute_template_name</title> + + <indexterm> + <primary>absolute_template_name built-in</primary> + </indexterm> + + <para>Converts a template name to an absolute name, which can be + safely passed to <literal><#include + <replaceable>name</replaceable>></literal> or + <literal><#import <replaceable>name</replaceable> as + <replaceable>ns</replaceable>></literal> or + <literal>.get_optional_template(<replaceable>name</replaceable>)</literal> + and such in <emphasis>another</emphasis> template, as it won't be + misinterpreted to be relative to the directory of the template that + contains the <literal>include</literal>, <literal>import</literal>, + etc. For example, if you are in template + <literal>"dir/here.ftl"</literal>, then + <literal>"target.ftl"</literal> is converted to + <literal>"/dir/target.ftl"</literal> (note the initial + <literal>/</literal>). If now you pass this value to a template in + <literal>"other-dir/there.ftl"</literal>, where it's passed to the + <literal>include</literal> directive, then it won't be + misinterpreted as <literal>"other-dir/target.ftl"</literal>, like + <literal>"target.ftl"</literal> would have been.</para> + + <para>Optionally, you can specify a root based name (a name that's + either relative to the template root directory, or is absolute) that + will be used instead of the name of the current template, like + <literal><replaceable>pathToConver</replaceable>?absolute_template_name(<replaceable>otherTemplateName</replaceable>)</literal>.</para> + + <para>Example of an application (also uses <link + linkend="ref_specvar_caller_template_name"><literal>.caller_template_name</literal></link> + and <link + linkend="ref_specvar_get_optional_template"><literal>.get_optional_template</literal></link>):</para> + + <programlisting role="template"><#-- + <@smileyInclude name /> behaves like <#include name>, but prints a "(:" before the + template, or prints "):" instead if the template is missing. + + Note that just like with #include, if name is relative, it's resolved based on the + directory of the caller template, not of the template that defines this macro. As + .get_optional_template resolves relative names based on the current template, we + had to convert the name to an absolute name based on the caller template before + passing it to it. +--> +<#macro smileyInclude name> + <#local t = .get_optional_template( + name<emphasis>?absolute_template_name</emphasis>(.caller_template_name))> + <#if t.exists> + (: + <@t.include /> + <#else> + ): + </#if> +</#macro></programlisting> + </section> + <section xml:id="ref_buitin_api_and_has_api"> <title>api, has_api</title> @@ -23219,10 +23282,11 @@ There was no specific handler for node y linkend="ref.directive.macro">macro</link> or <link linkend="ref.directive.function">function</link> was called. It's mostly useful if you want to resolve paths relative to the caller - template. To serve that purpose better, if the caller template is - nameless, this will be an empty string (not a missing value). - Reading this variable will cause error if you aren't inside a macro - or function call. In particular, directives and + template (<link linkend="ref_builtin_absolute_template_name">see an + example here</link>). To serve that purpose better, if the caller + template is nameless, this will be an empty string (not a missing + value). Reading this variable will cause error if you aren't inside + a macro or function call. In particular, directives and <quote>methods</quote> implemented in Java will not influence the value of this variable; it's only for macros and functions implemented in templates. (<phrase @@ -23232,7 +23296,7 @@ There was no specific handler for node y object.</phrase>)</para> </listitem> - <listitem> + <listitem xml:id="ref_specvar_caller_template_name"> <para><indexterm> <primary>current_template_name</primary> </indexterm><literal>current_template_name</literal>: The name of @@ -27300,6 +27364,17 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting> </listitem> <listitem> + <para>Added new built-in, + <literal><replaceable>templateName</replaceable>?absolute_template_name</literal> + or + <literal><replaceable>templateName</replaceable>?absolute_template_name(<replaceable>baseName</replaceable>)</literal>, + which can be used to convert a relative template name to an + absolute template name. <link + linkend="ref_builtin_absolute_template_name">See more + here...</link></para> + </listitem> + + <listitem> <para>Bug fixed (<link xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-83">FREEMARKER-83</link>); this fix is only active when <link @@ -27336,7 +27411,24 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting> <listitem> <para><literal>DirectiveCallPlace</literal> now has a - <literal>Template getTemplate()</literal> method.</para> + <literal>Template getTemplate()</literal> method, so you can + query if from which template was your + <literal>TemplateDirectiveModel</literal> called. (This has + similar role as <literal>.caller_template_name</literal> for + macros/functions.)</para> + </listitem> + + <listitem> + <para>Added + <literal>Environment.rootBasedToAbsoluteTemplateName(String)</literal>, + which converts the root based names typically used for the + FreeMarker Java API-s (such as + <literal>Configuration.getTemplate(name)</literal>) to an + absolute path, which can be safely passed to + <literal><#include + <replaceable>path</replaceable>></literal> and such, as it + won't be misinterpreted to be relative to the directory of the + template.</para> </listitem> <listitem> http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/test/java/freemarker/cache/TemplateNameFormatTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/freemarker/cache/TemplateNameFormatTest.java b/src/test/java/freemarker/cache/TemplateNameFormatTest.java index 5cba04c..8441d97 100644 --- a/src/test/java/freemarker/cache/TemplateNameFormatTest.java +++ b/src/test/java/freemarker/cache/TemplateNameFormatTest.java @@ -223,7 +223,26 @@ public class TemplateNameFormatTest { } @Test - public void assertBackslashNotSpecialWith23() throws MalformedTemplateNameException, ParseException, IOException { + public void testRootBasedNameToAbsoluteName() throws MalformedTemplateNameException { + for (TemplateNameFormat tnf : new TemplateNameFormat[] { + TemplateNameFormat.DEFAULT_2_3_0, TemplateNameFormat.DEFAULT_2_4_0 }) { + assertEquals("/foo/bar", tnf.rootBasedNameToAbsoluteName("foo/bar")); + assertEquals("scheme://foo/bar", tnf.rootBasedNameToAbsoluteName("scheme://foo/bar")); + assertEquals("/foo/bar", tnf.rootBasedNameToAbsoluteName("/foo/bar")); + } + + assertEquals("a/b://c/d", TemplateNameFormat.DEFAULT_2_3_0.rootBasedNameToAbsoluteName("a/b://c/d")); + // Lenient handling of malformed rootBasedName: + assertEquals("/a/b://c/d", TemplateNameFormat.DEFAULT_2_4_0.rootBasedNameToAbsoluteName("a/b://c/d")); + + assertEquals("/b:/c/d", TemplateNameFormat.DEFAULT_2_3_0.rootBasedNameToAbsoluteName("b:/c/d")); + assertEquals("b:/c/d", TemplateNameFormat.DEFAULT_2_4_0.rootBasedNameToAbsoluteName("b:/c/d")); + assertEquals("/b:c/d", TemplateNameFormat.DEFAULT_2_3_0.rootBasedNameToAbsoluteName("b:c/d")); + assertEquals("b:c/d", TemplateNameFormat.DEFAULT_2_4_0.rootBasedNameToAbsoluteName("b:c/d")); + } + + @Test + public void testBackslashNotSpecialWith23() throws MalformedTemplateNameException, ParseException, IOException { Configuration cfg = new Configuration(Configuration.VERSION_2_3_22); MonitoredTemplateLoader tl = new MonitoredTemplateLoader(); @@ -273,7 +292,7 @@ public class TemplateNameFormatTest { } @Test - public void assertBackslashNotAllowedWith24() throws MalformedTemplateNameException, ParseException, IOException { + public void testBackslashNotAllowedWith24() throws MalformedTemplateNameException, ParseException, IOException { Configuration cfg = new Configuration(Configuration.VERSION_2_3_0); cfg.setTemplateNameFormat(TemplateNameFormat.DEFAULT_2_4_0); try { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/test/java/freemarker/core/AbsoluteTemplateNameBITest.java ---------------------------------------------------------------------- diff --git a/src/test/java/freemarker/core/AbsoluteTemplateNameBITest.java b/src/test/java/freemarker/core/AbsoluteTemplateNameBITest.java new file mode 100644 index 0000000..e4db1be --- /dev/null +++ b/src/test/java/freemarker/core/AbsoluteTemplateNameBITest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package freemarker.core; + +import java.io.IOException; + +import org.junit.Test; + +import freemarker.cache.StringTemplateLoader; +import freemarker.template.Configuration; +import freemarker.template.TemplateException; +import freemarker.test.TemplateTest; + +public class AbsoluteTemplateNameBITest extends TemplateTest { + + @Override + protected Configuration createConfiguration() throws Exception { + Configuration cfg = super.createConfiguration(); + cfg.setTemplateLoader(new StringTemplateLoader()); + return cfg; + } + + @Test + public void basicsTest() throws Exception { + assertOutput("${'a/b'?absolute_template_name}", "/a/b"); + assertOutput("${'a/b/'?absolute_template_name}", "/a/b/"); + assertOutput("${'foo://a/b'?absolute_template_name}", "foo://a/b"); + assertOutput("${'/a/b'?absolute_template_name}", "/a/b"); + + assertOutputOfDirPerF("${'a/b'?absolute_template_name}", "/dir/a/b"); + assertOutputOfDirPerF("${'a/b/'?absolute_template_name}", "/dir/a/b/"); + assertOutputOfDirPerF("${'foo://a/b'?absolute_template_name}", "foo://a/b"); + assertOutputOfDirPerF("${'/a/b'?absolute_template_name}", "/a/b"); + + for (String baseName : new String[] { "dir/f", "/dir/f", "dir/", "/dir/" }) { + assertOutput("${'a/b'?absolute_template_name('" + baseName + "')}", "/dir/a/b"); + assertOutput("${'a/b/'?absolute_template_name('" + baseName + "')}", "/dir/a/b/"); + assertOutput("${'foo://a/b'?absolute_template_name('" + baseName + "')}", "foo://a/b"); + assertOutput("${'/a/b'?absolute_template_name('" + baseName + "')}", "/a/b"); + } + + assertOutput("${'a/b'?absolute_template_name('schema://dir/f')}", "schema://dir/a/b"); + assertOutput("${'a/b/'?absolute_template_name('schema://dir/f')}", "schema://dir/a/b/"); + assertOutput("${'foo://a/b'?absolute_template_name('schema://dir/f')}", "foo://a/b"); + assertOutput("${'/a/b'?absolute_template_name('schema://dir/f')}", "schema://a/b"); + } + + private void assertOutputOfDirPerF(String ftl, String expectedOut) + throws IOException, TemplateException { + addTemplate("dir/f", ftl); + getConfiguration().removeTemplateFromCache("dir/f"); + assertOutputForNamed("dir/f", expectedOut); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/test/java/freemarker/manual/AbsoluteTemplateNameBIExample.java ---------------------------------------------------------------------- diff --git a/src/test/java/freemarker/manual/AbsoluteTemplateNameBIExample.java b/src/test/java/freemarker/manual/AbsoluteTemplateNameBIExample.java new file mode 100644 index 0000000..af8d686 --- /dev/null +++ b/src/test/java/freemarker/manual/AbsoluteTemplateNameBIExample.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package freemarker.manual; + +import org.junit.Test; + +public class AbsoluteTemplateNameBIExample extends ExamplesTest { + + @Test + public void test() throws Exception { + assertOutputForNamed("dir/AbsoluteTemplateNameBIExample-main.ftl"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/test/resources/freemarker/manual/AbsoluteTemplateNameBIExample-foo.ftl ---------------------------------------------------------------------- diff --git a/src/test/resources/freemarker/manual/AbsoluteTemplateNameBIExample-foo.ftl b/src/test/resources/freemarker/manual/AbsoluteTemplateNameBIExample-foo.ftl new file mode 100644 index 0000000..b588cb3 --- /dev/null +++ b/src/test/resources/freemarker/manual/AbsoluteTemplateNameBIExample-foo.ftl @@ -0,0 +1,19 @@ +<#-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +/foo http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/test/resources/freemarker/manual/AbsoluteTemplateNameBIExample-lib.ftl ---------------------------------------------------------------------- diff --git a/src/test/resources/freemarker/manual/AbsoluteTemplateNameBIExample-lib.ftl b/src/test/resources/freemarker/manual/AbsoluteTemplateNameBIExample-lib.ftl new file mode 100644 index 0000000..0db6c7d --- /dev/null +++ b/src/test/resources/freemarker/manual/AbsoluteTemplateNameBIExample-lib.ftl @@ -0,0 +1,38 @@ +<#-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<#-- + <@smileyInclude name /> behaves like <#include name>, but prints a "(:" before the + template, or prints "):" instead if the template is missing. + + Note that just like with #include, if name is relative, it's resolved based on the + directory of the caller template, not of the template that defines this macro. As + .get_optional_template resolves relative names based on the current template, we + had to convert the name to an absolute name based on the caller template before + passing it to it. +--> +<#macro smileyInclude name> + <#local t = .get_optional_template( + name?absolute_template_name(.caller_template_name))> + <#if t.exists> + (: + <@t.include /> + <#else> + ): + </#if> +</#macro> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-foo.ftl ---------------------------------------------------------------------- diff --git a/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-foo.ftl b/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-foo.ftl new file mode 100644 index 0000000..e68993c --- /dev/null +++ b/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-foo.ftl @@ -0,0 +1,19 @@ +<#-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +/dir/foo http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-main.ftl ---------------------------------------------------------------------- diff --git a/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-main.ftl b/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-main.ftl new file mode 100644 index 0000000..311bb9a --- /dev/null +++ b/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-main.ftl @@ -0,0 +1,24 @@ +<#-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<#import '/AbsoluteTemplateNameBIExample-lib.ftl' as lib> + +<@lib.smileyInclude 'AbsoluteTemplateNameBIExample-foo.ftl' /> +<@lib.smileyInclude '../AbsoluteTemplateNameBIExample-foo.ftl' /> +<@lib.smileyInclude '/AbsoluteTemplateNameBIExample-foo.ftl' /> +<@lib.smileyInclude 'AbsoluteTemplateNameBIExample-missing.ftl' /> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8286a7bf/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-main.ftl.out ---------------------------------------------------------------------- diff --git a/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-main.ftl.out b/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-main.ftl.out new file mode 100644 index 0000000..9e9f175 --- /dev/null +++ b/src/test/resources/freemarker/manual/dir/AbsoluteTemplateNameBIExample-main.ftl.out @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + (: +/dir/foo + (: +/foo + (: +/foo + ):