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 ea7cd6e Added special rule to allow using the directive name in the
end-tag when ?with_args(...) was used in the start-tag, like
<@myMacro?with_args(args)>...</@myMacro>.
ea7cd6e is described below
commit ea7cd6ed00216cd2718a77ea3cd44e634e0ea8fd
Author: ddekany <[email protected]>
AuthorDate: Fri Nov 1 19:40:45 2019 +0100
Added special rule to allow using the directive name in the end-tag when
?with_args(...) was used in the start-tag, like
<@myMacro?with_args(args)>...</@myMacro>.
---
src/main/java/freemarker/core/MethodCall.java | 4 ++
src/main/javacc/FTL.jj | 13 +++-
src/manual/en_US/book.xml | 16 +++++
.../java/freemarker/core/EndTagSyntaxTest.java | 76 ++++++++++++++++++++++
4 files changed, 107 insertions(+), 2 deletions(-)
diff --git a/src/main/java/freemarker/core/MethodCall.java
b/src/main/java/freemarker/core/MethodCall.java
index 74e20a4..ab441aa 100644
--- a/src/main/java/freemarker/core/MethodCall.java
+++ b/src/main/java/freemarker/core/MethodCall.java
@@ -106,6 +106,10 @@ final class MethodCall extends Expression {
return 1 + arguments.items.size();
}
+ Expression getTarget() {
+ return target;
+ }
+
@Override
Object getParameterValue(int idx) {
if (idx == 0) {
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index 184c8a4..cb80218 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -3585,8 +3585,17 @@ TemplateElement UnifiedMacroTransform() :
start = <UNIFIED_CALL>
exp = Expression()
{
- if (exp instanceof Identifier || (exp instanceof Dot && ((Dot)
exp).onlyHasIdentifiers())) {
- startTagNameExp = exp;
+ // To allow <@foo.bar?withArgs(...)>...</@foo.bar>, but we also remove
superfluous (...):
+ Expression cleanedExp = exp;
+ if (cleanedExp instanceof MethodCall) {
+ Expression methodCallTarget = ((MethodCall)
cleanedExp).getTarget();
+ if (methodCallTarget instanceof BuiltInsForCallables.with_argsBI) {
+ cleanedExp = ((BuiltInsForCallables.with_argsBI)
methodCallTarget).target;
+ }
+ }
+
+ if (cleanedExp instanceof Identifier || (cleanedExp instanceof Dot &&
((Dot) cleanedExp).onlyHasIdentifiers())) {
+ startTagNameExp = cleanedExp;
} else {
startTagNameExp = null;
}
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index afe59d7..a99606f 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -19869,6 +19869,14 @@ Same as:
<programlisting role="output"> m2 does things with 1, 2, 3
Delegate to m1:
m1 does things with 1, 2, 3</programlisting>
+
+ <para>FreeMarker syntax allows using the name before the
+ <literal>?with_args(<replaceable>...</replaceable>)</literal> in the
+ end-tag, just as if the
+ <literal>?with_args(<replaceable>...</replaceable>)</literal> wasn't
+ there:</para>
+
+ <programlisting><@myMacro?with_args({'a':
1})>...</<emphasis>@myMacro</emphasis>></programlisting>
</section>
</section>
</chapter>
@@ -24273,6 +24281,14 @@ Or all above but with positional parameter passing
(<link
But
<literal><@a_hash.foo><replaceable>...</replaceable></@a_hash.foo></literal>
is OK.</para>
+
+ <para>There's also a special rule that says that if the
+ <literal><replaceable>user_def_dir_exp</replaceable></literal>
+ ends with <literal><link
+
linkend="ref_builtin_with_args">?with_args(<replaceable>...</replaceable>)</link></literal>,
+ then that's ignored when the end-tag is matched, so you can write
+ something like
+
<literal><@myMacro?with_args(args)><replaceable>...</replaceable></@myMacro></literal>.</para>
</section>
<section xml:id="ref_directive_userDefined_loopVar">
diff --git a/src/test/java/freemarker/core/EndTagSyntaxTest.java
b/src/test/java/freemarker/core/EndTagSyntaxTest.java
new file mode 100644
index 0000000..f4e7500
--- /dev/null
+++ b/src/test/java/freemarker/core/EndTagSyntaxTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.Before;
+import org.junit.Test;
+
+import freemarker.template.Configuration;
+import freemarker.template.TemplateException;
+import freemarker.test.TemplateTest;
+
+public class EndTagSyntaxTest extends TemplateTest {
+
+ @Override
+ protected Configuration createConfiguration() throws Exception {
+ return new Configuration(Configuration.VERSION_2_3_29);
+ }
+
+ @Before
+ public void setup() {
+ addTemplate("common.ftl",
+ "<#macro m a=1>${a}[<#nested />]</#macro>" +
+ "<#assign ns={'m':m}>");
+ getConfiguration().addAutoInclude("common.ftl");
+ }
+
+ @Test
+ public void testSimple() throws IOException, TemplateException {
+ assertOutput("<@m>nested</@>", "1[nested]");
+ assertOutput("<@m a=2>nested</@>", "2[nested]");
+
+ assertOutput("<@ns.m>nested</@ns.m>", "1[nested]");
+ assertOutput("<@ns.m a=2>nested</@ns.m>", "2[nested]");
+
+ assertOutput("<@m>nested</@m>", "1[nested]");
+ assertOutput("<@m a=2>nested</@m>", "2[nested]");
+
+ assertOutput("<@ns.m>nested</@ns.m>", "1[nested]");
+ assertOutput("<@ns.m a=2>nested</@ns.m>", "2[nested]");
+
+ assertErrorContains("<@ns.m a=2>nested</@m>", "</@ns.m>");
+ assertErrorContains("<@m a=2>nested</@n>", "</@m>");
+ }
+
+ @Test
+ public void testWithArgs() throws IOException, TemplateException {
+ assertOutput("<@m?withArgs({})>nested</@m>", "1[nested]");
+ assertOutput("<@m?withArgs({}) a=2>nested</@m>", "2[nested]");
+
+ assertOutput("<@ns.m?withArgs({})>nested</@ns.m>", "1[nested]");
+ assertOutput("<@ns.m?withArgs({}) a=2>nested</@ns.m>", "2[nested]");
+
+ assertErrorContains("<@ns.m?withArgs({})>nested</@m>", "</@ns.m>");
+ assertErrorContains("<@m?withArgs({})>nested</@n>", "</@m>");
+ }
+
+}