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/02 12:13:05 UTC
[2/2] incubator-freemarker git commit: Forward ported
.getOptionalTemplate from 2.3-gae. Note that we don't have "encoding" and
"parse" options, as they aren't relevant in FM3.
Forward ported .getOptionalTemplate from 2.3-gae. Note that we don't have "encoding" and "parse" options, as they aren't relevant in FM3.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/99174103
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/99174103
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/99174103
Branch: refs/heads/3
Commit: 99174103a9a53e7d596deb3fa00aac2420aceefb
Parents: f9fa582
Author: ddekany <dd...@apache.org>
Authored: Fri Mar 2 13:11:30 2018 +0100
Committer: ddekany <dd...@apache.org>
Committed: Fri Mar 2 13:11:30 2018 +0100
----------------------------------------------------------------------
.../core/GetOptionalTemplateTest.java | 114 ++++++++++++++++++
.../freemarker/core/ASTExpBuiltInVariable.java | 5 +
.../core/GetOptionalTemplateFunction.java | 117 +++++++++++++++++++
3 files changed, 236 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99174103/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetOptionalTemplateTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetOptionalTemplateTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetOptionalTemplateTest.java
new file mode 100644
index 0000000..4149e02
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetOptionalTemplateTest.java
@@ -0,0 +1,114 @@
+package org.apache.freemarker.core;
+
+import org.apache.freemarker.core.templateresolver.TemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.test.TemplateTest;
+import org.junit.Test;
+
+public class GetOptionalTemplateTest extends TemplateTest {
+
+ private ByteArrayTemplateLoader byteArrayTemplateLoader = new ByteArrayTemplateLoader();
+
+ @Override
+ protected Configuration createDefaultConfiguration() throws Exception {
+ return new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateLoader(
+ new MultiTemplateLoader(new TemplateLoader[] {
+ new StringTemplateLoader(), byteArrayTemplateLoader
+ })).build();
+ }
+
+ @Test
+ public void testBasicsWhenTemplateExists() throws Exception {
+ addTemplate("inc.ftl", "<#assign x = (x!0) + 1>inc ${x}");
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('inc.ftl')>"
+ + "Exists: ${t.exists?c}; "
+ + "Include: <@t.include />, <@t.include />; "
+ + "Import: <#assign ns1 = t.import()><#assign ns2 = t.import()>${ns1.x}, ${ns2.x}; "
+ + "Aliased: <#assign x = 9 in ns1>${ns1.x}, ${ns2.x}, <#import 'inc.ftl' as ns3>${ns3.x}",
+ "Exists: true; "
+ + "Include: inc 1, inc 2; "
+ + "Import: 1, 1; "
+ + "Aliased: 9, 9, 9"
+ );
+ }
+
+ @Test
+ public void testBasicsWhenTemplateIsMissing() throws Exception {
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('missing.ftl')>"
+ + "Exists: ${t.exists?c}; "
+ + "Include: ${t.include???c}; "
+ + "Import: ${t.import???c}",
+ "Exists: false; "
+ + "Include: false; "
+ + "Import: false"
+ );
+ }
+
+ @Test
+ public void testRelativeAndAbsolutePath() throws Exception {
+ addTemplate("lib/inc.ftl", "included");
+
+ addTemplate("test1.ftl", "<@.getOptionalTemplate('lib/inc.ftl').include />");
+ assertOutputForNamed("test1.ftl", "included");
+
+ addTemplate("lib/test2.ftl", "<@.getOptionalTemplate('/lib/inc.ftl').include />");
+ assertOutputForNamed("lib/test2.ftl", "included");
+
+ addTemplate("lib/test3.ftl", "<@.getOptionalTemplate('inc.ftl').include />");
+ assertOutputForNamed("lib/test3.ftl", "included");
+
+ addTemplate("sub/test4.ftl", "<@.getOptionalTemplate('../lib/inc.ftl').include />");
+ assertOutputForNamed("sub/test4.ftl", "included");
+ }
+
+ @Test
+ public void testUseCase1() throws Exception {
+ addTemplate("lib/inc.ftl", "included");
+ assertOutput(""
+ + "<#macro test templateName{positional}>"
+ + "<#local t = .getOptionalTemplate(templateName)>"
+ + "<#if t.exists>"
+ + "before <@t.include /> after"
+ + "<#else>"
+ + "missing"
+ + "</#if>"
+ + "</#macro>"
+ + "<@test 'lib/inc.ftl' />; "
+ + "<@test 'inc.ftl' />",
+ "before included after; missing");
+ }
+
+ @Test
+ public void testUseCase2() throws Exception {
+ addTemplate("found.ftl", "found");
+ assertOutput(""
+ + "<@("
+ + ".getOptionalTemplate('missing1.ftl').include!"
+ + ".getOptionalTemplate('missing2.ftl').include!"
+ + ".getOptionalTemplate('found.ftl').include!"
+ + ".getOptionalTemplate('missing3.ftl').include"
+ + ") />",
+ "found");
+ assertOutput(""
+ + "<#macro fallback>fallback</#macro>"
+ + "<@("
+ + ".getOptionalTemplate('missing1.ftl').include!"
+ + ".getOptionalTemplate('missing2.ftl').include!"
+ + "fallback"
+ + ") />",
+ "fallback");
+ }
+
+ @Test
+ public void testWrongArguments() throws Exception {
+ assertErrorContains("<#assign t = .getOptionalTemplate()>", "argument");
+ assertErrorContains("<#assign t = .getOptionalTemplate('1', '2', '3')>", "arguments", "3");
+ assertErrorContains("<#assign t = .getOptionalTemplate(1)>", "1st argument", "string", "number");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99174103/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java
index 19b0b04..b9d2f12 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java
@@ -57,6 +57,7 @@ final class ASTExpBuiltInVariable extends ASTExpression {
static final String AUTO_ESC = "autoEsc";
static final String URL_ESCAPING_CHARSET = "urlEscapingCharset";
static final String NOW = "now";
+ static final String GET_OPTIONAL_TEMPLATE = "getOptionalTemplate";
static final Set<String> BUILT_IN_VARIABLE_NAMES = new _SortedArraySet<>(
// Must be sorted alphabetically!
@@ -64,6 +65,7 @@ final class ASTExpBuiltInVariable extends ASTExpression {
CURRENT_TEMPLATE_NAME,
DATA_MODEL,
ERROR,
+ GET_OPTIONAL_TEMPLATE,
GLOBALS,
INCOMPATIBLE_IMPROVEMENTS,
LANG,
@@ -194,6 +196,9 @@ final class ASTExpBuiltInVariable extends ASTExpression {
if (name == INCOMPATIBLE_IMPROVEMENTS) {
return new SimpleString(env.getConfiguration().getIncompatibleImprovements().toString());
}
+ if (name == GET_OPTIONAL_TEMPLATE) {
+ return GetOptionalTemplateFunction.INSTANCE;
+ }
throw new TemplateException(this,
"Invalid special variable: ", name);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99174103/freemarker-core/src/main/java/org/apache/freemarker/core/GetOptionalTemplateFunction.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/GetOptionalTemplateFunction.java b/freemarker-core/src/main/java/org/apache/freemarker/core/GetOptionalTemplateFunction.java
new file mode 100644
index 0000000..eb8b6da
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/GetOptionalTemplateFunction.java
@@ -0,0 +1,117 @@
+/*
+ * 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 org.apache.freemarker.core;
+
+import static org.apache.freemarker.core.util.CallableUtils.*;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
+
+/**
+ * Implements {@code .getOptionalTemplate(name, options)}.
+ */
+class GetOptionalTemplateFunction implements TemplateFunctionModel {
+
+ static final GetOptionalTemplateFunction INSTANCE = new GetOptionalTemplateFunction();
+
+ private static final String RESULT_INCLUDE = "include";
+ private static final String RESULT_IMPORT = "import";
+ private static final String RESULT_EXISTS = "exists";
+
+ private GetOptionalTemplateFunction() {
+ // No op.
+ }
+
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env) throws TemplateException {
+ final String absTemplateName;
+ try {
+ absTemplateName = env.toFullTemplateName(
+ env.getCurrentTemplate().getLookupName(),
+ getStringArgument(args, 0, this));
+ } catch (MalformedTemplateNameException e) {
+ throw new TemplateException("Failed to convert template path to full path; see cause exception.", e);
+ }
+
+ final Template template;
+ try {
+ template = env.getTemplateForInclusion(absTemplateName, true);
+ } catch (IOException e) {
+ throw new TemplateException(
+ "Error when trying to include template ", new _DelayedJQuote(absTemplateName));
+ }
+
+ NativeHashEx result = new NativeHashEx();
+ result.put(RESULT_EXISTS, template != null ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE);
+ // If the template is missing, result.include and such will be missing too, so that a default can be
+ // conveniently provided like in <@optTemp.include!myDefaultMacro />.
+ if (template != null) {
+ result.put(RESULT_INCLUDE, new TemplateDirectiveModel() {
+ @Override
+ public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env)
+ throws TemplateException, IOException {
+ env.include(template);
+ }
+
+ @Override
+ public boolean isNestedContentSupported() {
+ return false;
+ }
+
+ @Override
+ public ArgumentArrayLayout getDirectiveArgumentArrayLayout() {
+ return ArgumentArrayLayout.PARAMETERLESS;
+ }
+ });
+ result.put(RESULT_IMPORT, new TemplateFunctionModel() {
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
+ throws TemplateException {
+ try {
+ return env.importLib(template, null);
+ } catch (IOException e) {
+ throw new TemplateException(e, "Failed to import loaded template; see cause exception");
+ } catch (TemplateException e) {
+ throw new TemplateException(e, "Failed to import loaded template; see cause exception");
+ }
+ }
+
+ @Override
+ public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
+ return ArgumentArrayLayout.PARAMETERLESS;
+ }
+ });
+ }
+ return result;
+ }
+
+ @Override
+ public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
+ return ArgumentArrayLayout.SINGLE_POSITIONAL_PARAMETER;
+ }
+
+}