This is an automated email from the ASF dual-hosted git repository.
ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git
The following commit(s) were added to refs/heads/2.3-gae by this push:
new 22f0e13 When a macro uses .args, and has catch-all parameter, allow
positional macro arguments when the actual catch-all length is 0. Also, added
some tests for 0 argument calls.
22f0e13 is described below
commit 22f0e13d1ac79cfc5406a626dc7db6de8acea502
Author: ddekany <[email protected]>
AuthorDate: Sat Oct 26 00:05:54 2019 +0200
When a macro uses .args, and has catch-all parameter, allow positional
macro arguments when the actual catch-all length is 0. Also, added some tests
for 0 argument calls.
---
src/main/java/freemarker/core/Macro.java | 15 +++++++++----
.../freemarker/template/utility/Constants.java | 11 +++++++---
src/manual/en_US/book.xml | 3 ++-
.../freemarker/core/ArgsSpecialVariableTest.java | 25 ++++++++++++++++------
4 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/src/main/java/freemarker/core/Macro.java
b/src/main/java/freemarker/core/Macro.java
index b64e9e4..17c63f6 100644
--- a/src/main/java/freemarker/core/Macro.java
+++ b/src/main/java/freemarker/core/Macro.java
@@ -37,6 +37,7 @@ import freemarker.template.TemplateModelException;
import freemarker.template.TemplateModelIterator;
import freemarker.template.TemplateScalarModel;
import freemarker.template.TemplateSequenceModel;
+import freemarker.template.utility.Constants;
/**
* An element representing a macro or function declaration.
@@ -323,7 +324,8 @@ public final class Macro extends TemplateElement implements
TemplateModel {
if (argsSpecVarDraft != null) {
final String catchAllParamName = getMacro().catchAllParamName;
- final TemplateModel catchAllArgValue = catchAllParamName !=
null ? localVars.get(catchAllParamName) : null;
+ final TemplateModel catchAllArgValue = catchAllParamName !=
null
+ ? localVars.get(catchAllParamName) : null;
if (getMacro().isFunction()) {
int lengthWithCatchAlls = argsSpecVarDraft.length;
@@ -350,10 +352,15 @@ public final class Macro extends TemplateElement
implements TemplateModel {
TemplateHashModelEx2 catchAllHash;
if (catchAllParamName != null) {
if (catchAllArgValue instanceof TemplateSequenceModel)
{
- throw new _MiscTemplateException("The macro can
only by called with named arguments, " +
- "because it uses both .",
BuiltinVariable.ARGS, " and catch-all parameter.");
+ if (((TemplateSequenceModel)
catchAllArgValue).size() != 0) {
+ throw new _MiscTemplateException("The macro
can only by called with named arguments, " +
+ "because it uses both .",
BuiltinVariable.ARGS, " and a non-empty catch-all " +
+ "parameter.");
+ }
+ catchAllHash = Constants.EMPTY_HASH_EX2;
+ } else {
+ catchAllHash = (TemplateHashModelEx2)
catchAllArgValue;
}
- catchAllHash = (TemplateHashModelEx2) catchAllArgValue;
lengthWithCatchAlls += catchAllHash.size();
} else {
catchAllHash = null;
diff --git a/src/main/java/freemarker/template/utility/Constants.java
b/src/main/java/freemarker/template/utility/Constants.java
index 2162ef6..8392c01 100644
--- a/src/main/java/freemarker/template/utility/Constants.java
+++ b/src/main/java/freemarker/template/utility/Constants.java
@@ -95,9 +95,14 @@ public class Constants {
}
}
-
- public static final TemplateHashModelEx EMPTY_HASH = new EmptyHashModel();
-
+
+ /**
+ * @since 2.3.30
+ */
+ public static final TemplateHashModelEx2 EMPTY_HASH_EX2 = new
EmptyHashModel();
+
+ public static final TemplateHashModelEx EMPTY_HASH = EMPTY_HASH_EX2;
+
/**
* An empty hash. Since 2.3.27, it implements {@link
TemplateHashModelEx2}, before that it was only
* {@link TemplateHashModelEx}.
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 3b1432c..6c03186 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -24617,7 +24617,8 @@ There was no specific handler for node y
</listitem>
<listitem>
- <para>If a macro has a catch-all argument, and the macro uses
+ <para>If a macro has a catch-all parameter, and the actual
+ catch-all argument is not empty, and the macro uses
<literal>.args</literal> somewhere, it can only be called with
named arguments (like <literal><@m a=1 b=2 /></literal>),
and not with positional arguments (like <literal><@m 1 2
diff --git a/src/test/java/freemarker/core/ArgsSpecialVariableTest.java
b/src/test/java/freemarker/core/ArgsSpecialVariableTest.java
index 1064744..bc94cef 100644
--- a/src/test/java/freemarker/core/ArgsSpecialVariableTest.java
+++ b/src/test/java/freemarker/core/ArgsSpecialVariableTest.java
@@ -41,6 +41,12 @@ public class ArgsSpecialVariableTest extends TemplateTest {
}
@Test
+ public void macroZeroArgsTest() throws IOException, TemplateException {
+ assertOutput("<#macro m>${.args?size}</#macro><@m />", "0");
+ assertOutput("<#macro m others...>${.args?size}</#macro><@m />", "0");
+ }
+
+ @Test
public void macroWithDefaultsTest() throws IOException, TemplateException {
String macroDef = "<#macro m a b c=3><#list .args as k,
v>${k}=${v}<#sep>, </#list></#macro>";
String expectedOutput = "" +
@@ -80,8 +86,8 @@ public class ArgsSpecialVariableTest extends TemplateTest {
@Test
public void macroWithCatchAllTest() throws IOException, TemplateException {
- assertOutput("" +
- "<#macro m a b=2 others...><#list .args as k,
v>${k}=${v}<#sep>, </#list></#macro>" +
+ String macroDef = "<#macro m a b=2 others...><#list .args as k,
v>${k}=${v}<#sep>, </#list></#macro>";
+ assertOutput(macroDef +
"<@m a=11 b=22 c=33 d=44 />; " +
"<@m a=11 b=22 />; " +
"<@m a=11 />; " +
@@ -91,9 +97,9 @@ public class ArgsSpecialVariableTest extends TemplateTest {
"a=11, b=2; " +
"a=11, b=2, c=33");
- assertErrorContains("" +
- "<#macro m a b=2 others...><#list .args as k,
v>${k}=${v}<#sep>, </#list></#macro>" +
- "<@m 1, 2 />",
+ assertOutput(macroDef + "<@m 1, 2 />",
+ "a=1, b=2");
+ assertErrorContains(macroDef + "<@m 1, 2, 3 />",
".args", "catch-all");
}
@@ -106,6 +112,13 @@ public class ArgsSpecialVariableTest extends TemplateTest {
expectedOutput);
}
+
+ @Test
+ public void functionZeroArgsTest() throws IOException, TemplateException {
+ assertOutput("<#function f><#return .args?size></#function>${f()}",
"0");
+ assertOutput("<#function f others...><#return
.args?size></#function>${f()}", "0");
+ }
+
@Test
public void functionWithDefaultsTest() throws IOException,
TemplateException {
String functionDef = "<#function f a b c=3><#return .args?join(',
')></#function>";
@@ -150,7 +163,7 @@ public class ArgsSpecialVariableTest extends TemplateTest {
"11, 2; " +
"11, 2, 33");
}
-
+
@Test
public void usedInWrongContextTest() throws IOException, TemplateException
{
assertErrorContains("${.args}", "args", "macro", "function");