You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2018/03/10 20:02:43 UTC

[1/2] incubator-freemarker git commit: Added ?absoulte_template_name. Necessary additions to the Environment and TemplateNameFormat. Some Manual cleanups related to `.caller_template_name`.

Repository: incubator-freemarker
Updated Branches:
  refs/heads/2.3 6442fd765 -> 5bfa9ac42


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
Commit: 8286a7bfcb402e34e67d75d50a5a2ee7c994275e
Parents: 5f821f1
Author: ddekany <dd...@apache.org>
Authored: Sat Mar 10 20:56:45 2018 +0100
Committer: ddekany <dd...@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>&lt;#include
+          <replaceable>name</replaceable>&gt;</literal> or
+          <literal>&lt;#import <replaceable>name</replaceable> as
+          <replaceable>ns</replaceable>&gt;</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">&lt;#--
+  &lt;@smileyInclude name /&gt; behaves like &lt;#include name&gt;, 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.
+--&gt;
+&lt;#macro smileyInclude name&gt;
+  &lt;#local t = .get_optional_template(
+      name<emphasis>?absolute_template_name</emphasis>(.caller_template_name))&gt;
+  &lt;#if t.exists&gt;
+    (:
+    &lt;@t.include /&gt;
+  &lt;#else&gt;
+    ):
+  &lt;/#if&gt;
+&lt;/#macro&gt;</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>&lt;#include
+              <replaceable>path</replaceable>&gt;</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
+    ):



[2/2] incubator-freemarker git commit: Merge remote-tracking branch 'origin/2.3-gae' into 2.3

Posted by dd...@apache.org.
Merge remote-tracking branch 'origin/2.3-gae' into 2.3


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/5bfa9ac4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/5bfa9ac4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/5bfa9ac4

Branch: refs/heads/2.3
Commit: 5bfa9ac426bbf0a03c2cd5009c03e76640a27bd6
Parents: 6442fd7 8286a7b
Author: ddekany <dd...@apache.org>
Authored: Sat Mar 10 21:01:58 2018 +0100
Committer: ddekany <dd...@apache.org>
Committed: Sat Mar 10 21:01:58 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(-)
----------------------------------------------------------------------