freemarker-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ddek...@apache.org
Subject [freemarker] branch 2.3-gae updated: Renamed ?spread_args to ?with_args
Date Fri, 01 Nov 2019 17:06:28 GMT
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 bcde758  Renamed ?spread_args to ?with_args
bcde758 is described below

commit bcde758d4a00b3a2e2de2deb4d7e6b56cfbaada7
Author: ddekany <ddekany@apache.org>
AuthorDate: Fri Nov 1 18:06:18 2019 +0100

    Renamed ?spread_args to ?with_args
---
 src/main/java/freemarker/core/BuiltIn.java         |   6 +-
 .../java/freemarker/core/BuiltInsForCallables.java |  42 +--
 src/main/java/freemarker/core/Environment.java     |  34 +-
 src/main/java/freemarker/core/Macro.java           |  29 +-
 src/manual/en_US/book.xml                          | 383 ++++++++++-----------
 ...gsBuiltInTest.java => WithArgsBuiltInTest.java} | 260 +++++++-------
 ...readArgsExamples.java => WithArgsExamples.java} |   4 +-
 ...hArgsExamples-usingWithArgsSpecialVariable.ftl} |   2 +-
 ...sExamples-usingWithArgsSpecialVariable.ftl.out} |   0
 9 files changed, 380 insertions(+), 380 deletions(-)

diff --git a/src/main/java/freemarker/core/BuiltIn.java b/src/main/java/freemarker/core/BuiltIn.java
index f1be894..da9ffc6 100644
--- a/src/main/java/freemarker/core/BuiltIn.java
+++ b/src/main/java/freemarker/core/BuiltIn.java
@@ -87,8 +87,8 @@ abstract class BuiltIn extends Expression implements Cloneable {
     static final int NUMBER_OF_BIS = 287;
     static final HashMap<String, BuiltIn> BUILT_INS_BY_NAME = new HashMap(NUMBER_OF_BIS * 3 / 2 + 1, 1f);
 
-    static final String BI_NAME_SNAKE_CASE_SPREAD_ARGS = "spread_args";
-    static final String BI_NAME_CAMEL_CASE_SPREAD_ARGS = "spreadArgs";
+    static final String BI_NAME_SNAKE_CASE_WITH_ARGS = "with_args";
+    static final String BI_NAME_CAMEL_CASE_WITH_ARGS = "withArgs";
 
     static {
         // Note that you must update NUMBER_OF_BIS if you add new items here!
@@ -278,7 +278,6 @@ abstract class BuiltIn extends Expression implements Cloneable {
         putBI("sort_by", "sortBy", new sort_byBI());
         putBI("sort", new sortBI());
         putBI("split", new BuiltInsForStringsBasic.split_BI());
-        putBI(BI_NAME_SNAKE_CASE_SPREAD_ARGS, BI_NAME_CAMEL_CASE_SPREAD_ARGS, new BuiltInsForCallables.spread_argsBI());
         putBI("switch", new BuiltInsWithLazyConditionals.switch_BI());
         putBI("starts_with", "startsWith", new BuiltInsForStringsBasic.starts_withBI());
         putBI("string", new BuiltInsForMultipleTypes.stringBI());
@@ -301,6 +300,7 @@ abstract class BuiltIn extends Expression implements Cloneable {
         putBI("url_path", "urlPath", new BuiltInsForStringsEncoding.urlPathBI());
         putBI("values", new BuiltInsForHashes.valuesBI());
         putBI("web_safe", "webSafe", BUILT_INS_BY_NAME.get("html"));  // deprecated; use ?html instead
+        putBI(BI_NAME_SNAKE_CASE_WITH_ARGS, BI_NAME_CAMEL_CASE_WITH_ARGS, new BuiltInsForCallables.with_argsBI());
         putBI("word_list", "wordList", new BuiltInsForStringsBasic.word_listBI());
         putBI("xhtml", new BuiltInsForStringsEncoding.xhtmlBI());
         putBI("xml", new BuiltInsForStringsEncoding.xmlBI());
diff --git a/src/main/java/freemarker/core/BuiltInsForCallables.java b/src/main/java/freemarker/core/BuiltInsForCallables.java
index 477f103..acc4245 100644
--- a/src/main/java/freemarker/core/BuiltInsForCallables.java
+++ b/src/main/java/freemarker/core/BuiltInsForCallables.java
@@ -40,7 +40,7 @@ import freemarker.template.utility.TemplateModelUtils;
 
 class BuiltInsForCallables {
 
-    static class spread_argsBI extends BuiltIn {
+    static class with_argsBI extends BuiltIn {
 
         TemplateModel _eval(Environment env) throws TemplateException {
             TemplateModel model = target.eval(env);
@@ -71,20 +71,20 @@ class BuiltInsForCallables {
                 checkMethodArgCount(args.size(), 1);
                 TemplateModel argTM = (TemplateModel) args.get(0);
 
-                Macro.SpreadArgs spreadArgs;
+                Macro.WithArgs withArgs;
                 if (argTM instanceof TemplateSequenceModel) {
-                    spreadArgs = new Macro.SpreadArgs((TemplateSequenceModel) argTM);
+                    withArgs = new Macro.WithArgs((TemplateSequenceModel) argTM);
                 } else if (argTM instanceof TemplateHashModelEx) {
                     if (macroOrFunction.isFunction()) {
                         throw new _TemplateModelException("When applied on a function, ?",  key,
                                 " can't have a hash argument. Use a sequence argument.");
                     }
-                    spreadArgs = new Macro.SpreadArgs((TemplateHashModelEx) argTM);
+                    withArgs = new Macro.WithArgs((TemplateHashModelEx) argTM);
                 } else {
                     throw _MessageUtil.newMethodArgMustBeExtendedHashOrSequnceException("?" + key, 0, argTM);
                 }
 
-                return new Macro(macroOrFunction, spreadArgs);
+                return new Macro(macroOrFunction, withArgs);
             }
 
         }
@@ -102,16 +102,16 @@ class BuiltInsForCallables {
                 TemplateModel argTM = (TemplateModel) args.get(0);
 
                 if (argTM instanceof TemplateSequenceModel) {
-                    final TemplateSequenceModel spreadArgs = (TemplateSequenceModel) argTM;
+                    final TemplateSequenceModel withArgs = (TemplateSequenceModel) argTM;
                     if (method instanceof TemplateMethodModelEx) {
                         return new TemplateMethodModelEx() {
                             public Object exec(List origArgs) throws TemplateModelException {
-                                int spreadArgsSize = spreadArgs.size();
+                                int withArgsSize = withArgs.size();
                                 List<TemplateModel> newArgs = new ArrayList<TemplateModel>(
-                                        spreadArgsSize + origArgs.size());
+                                        withArgsSize + origArgs.size());
 
-                                for (int i = 0; i < spreadArgsSize; i++) {
-                                    newArgs.add(spreadArgs.get(i));
+                                for (int i = 0; i < withArgsSize; i++) {
+                                    newArgs.add(withArgs.get(i));
                                 }
 
                                 newArgs.addAll(origArgs);
@@ -122,12 +122,12 @@ class BuiltInsForCallables {
                     } else {
                         return new TemplateMethodModel() {
                             public Object exec(List origArgs) throws TemplateModelException {
-                                int spreadArgsSize = spreadArgs.size();
+                                int withArgsSize = withArgs.size();
                                 List<String> newArgs = new ArrayList<String>(
-                                        spreadArgsSize + origArgs.size());
+                                        withArgsSize + origArgs.size());
 
-                                for (int i = 0; i < spreadArgsSize; i++) {
-                                    TemplateModel argVal = spreadArgs.get(i);
+                                for (int i = 0; i < withArgsSize; i++) {
+                                    TemplateModel argVal = withArgs.get(i);
                                     newArgs.add(argValueToString(argVal));
                                 }
 
@@ -182,18 +182,18 @@ class BuiltInsForCallables {
                 TemplateModel argTM = (TemplateModel) args.get(0);
 
                 if (argTM instanceof TemplateHashModelEx) {
-                    final TemplateHashModelEx spreadArgs = (TemplateHashModelEx) argTM;
+                    final TemplateHashModelEx withArgs = (TemplateHashModelEx) argTM;
                     return new TemplateDirectiveModel() {
                         public void execute(Environment env, Map origArgs, TemplateModel[] loopVars,
                                 TemplateDirectiveBody body) throws TemplateException, IOException {
-                            int spreadArgsSize = spreadArgs.size();
+                            int withArgsSize = withArgs.size();
                             Map<String, TemplateModel> newArgs = new LinkedHashMap<String, TemplateModel>(
-                                    (spreadArgsSize + origArgs.size()) * 4 / 3, 1f);
+                                    (withArgsSize + origArgs.size()) * 4 / 3, 1f);
 
-                            TemplateHashModelEx2.KeyValuePairIterator spreadArgsIter =
-                                    TemplateModelUtils.getKeyValuePairIterator(spreadArgs);
-                            while (spreadArgsIter.hasNext()) {
-                                TemplateHashModelEx2.KeyValuePair spreadArgKVP = spreadArgsIter.next();
+                            TemplateHashModelEx2.KeyValuePairIterator withArgsIter =
+                                    TemplateModelUtils.getKeyValuePairIterator(withArgs);
+                            while (withArgsIter.hasNext()) {
+                                TemplateHashModelEx2.KeyValuePair spreadArgKVP = withArgsIter.next();
 
                                 TemplateModel argNameTM = spreadArgKVP.getKey();
                                 if (!(argNameTM instanceof TemplateScalarModel)) {
diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index 7338895..8ca29b1 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -903,16 +903,16 @@ public final class Environment extends Configurable {
         SimpleSequence positionalCatchAllParamValue = null;
         int nextPositionalArgToAssignIdx = 0;
 
-        // Used for ?spread_args(...):
-        Macro.SpreadArgs spreadArgs = macro.getSpreadArgs();
-        if (spreadArgs != null) {
-            TemplateHashModelEx byNameSpreadArgs = spreadArgs.getByName();
-            TemplateSequenceModel byPositionSpreadArgs = spreadArgs.getByPosition();
-
-            if (byNameSpreadArgs != null) {
-                new HashMap<String, TemplateModel>(byNameSpreadArgs.size() * 4 / 3, 1f);
+        // Used for ?with_args(...):
+        Macro.WithArgs withArgs = macro.getWithArgs();
+        if (withArgs != null) {
+            TemplateHashModelEx byNameWithArgs = withArgs.getByName();
+            TemplateSequenceModel byPositionWithArgs = withArgs.getByPosition();
+
+            if (byNameWithArgs != null) {
+                new HashMap<String, TemplateModel>(byNameWithArgs.size() * 4 / 3, 1f);
                 TemplateHashModelEx2.KeyValuePairIterator namedParamValueOverridesIter =
-                        TemplateModelUtils.getKeyValuePairIterator(byNameSpreadArgs);
+                        TemplateModelUtils.getKeyValuePairIterator(byNameWithArgs);
                 while (namedParamValueOverridesIter.hasNext()) {
                     TemplateHashModelEx2.KeyValuePair defaultArgHashKVP = namedParamValueOverridesIter.next();
 
@@ -943,14 +943,14 @@ public final class Environment extends Configurable {
                         throw newUndeclaredParamNameException(macro, argName);
                     }
                 }
-            } else if (byPositionSpreadArgs != null) {
+            } else if (byPositionWithArgs != null) {
                 String[] argNames = macro.getArgumentNamesInternal();
-                final int argsCnt = byPositionSpreadArgs.size();
+                final int argsCnt = byPositionWithArgs.size();
                 if (argNames.length < argsCnt && catchAllParamName == null) {
                     throw newTooManyArgumentsException(macro, argNames, argsCnt);
                 }
                 for (int i = 0; i < argsCnt; i++) {
-                    TemplateModel argValue = byPositionSpreadArgs.get(i);
+                    TemplateModel argValue = byPositionWithArgs.get(i);
                     try {
                         if (nextPositionalArgToAssignIdx < argNames.length) {
                             String argName = argNames[nextPositionalArgToAssignIdx++];
@@ -970,7 +970,7 @@ public final class Environment extends Configurable {
 
         if (namedArgs != null) {
             if (catchAllParamName != null && namedCatchAllParamValue == null && positionalCatchAllParamValue == null) {
-                if (namedArgs.isEmpty() && spreadArgs != null && spreadArgs.getByPosition() != null) {
+                if (namedArgs.isEmpty() && withArgs != null && withArgs.getByPosition() != null) {
                     positionalCatchAllParamValue = initPositionalCatchAllParameter(macroCtx, catchAllParamName);
                 } else {
                     namedCatchAllParamValue = initNamedCatchAllParameter(macroCtx, catchAllParamName);
@@ -998,7 +998,7 @@ public final class Environment extends Configurable {
             }
         } else if (positionalArgs != null) {
             if (catchAllParamName != null && positionalCatchAllParamValue == null && namedCatchAllParamValue == null) {
-                if (positionalArgs.isEmpty() && spreadArgs != null && spreadArgs.getByName() != null) {
+                if (positionalArgs.isEmpty() && withArgs != null && withArgs.getByName() != null) {
                     namedCatchAllParamValue = initNamedCatchAllParameter(macroCtx, catchAllParamName);
                 } else {
                     positionalCatchAllParamValue = initPositionalCatchAllParameter(macroCtx, catchAllParamName);
@@ -1007,12 +1007,12 @@ public final class Environment extends Configurable {
 
             String[] argNames = macro.getArgumentNamesInternal();
             final int argsCnt = positionalArgs.size();
-            final int argsWithSpreadArgsCnt = argsCnt + nextPositionalArgToAssignIdx;
-            if (argNames.length < argsWithSpreadArgsCnt && positionalCatchAllParamValue == null) {
+            final int argsWithWithArgsCnt = argsCnt + nextPositionalArgToAssignIdx;
+            if (argNames.length < argsWithWithArgsCnt && positionalCatchAllParamValue == null) {
                 if (namedCatchAllParamValue != null) {
                     throw newBothNamedAndPositionalCatchAllParamsException(macro);
                 } else {
-                    throw newTooManyArgumentsException(macro, argNames, argsWithSpreadArgsCnt);
+                    throw newTooManyArgumentsException(macro, argNames, argsWithWithArgsCnt);
                 }
             }
             for (int srcPosArgIdx = 0; srcPosArgIdx < argsCnt; srcPosArgIdx++) {
diff --git a/src/main/java/freemarker/core/Macro.java b/src/main/java/freemarker/core/Macro.java
index 17c63f6..d1a81d0 100644
--- a/src/main/java/freemarker/core/Macro.java
+++ b/src/main/java/freemarker/core/Macro.java
@@ -58,7 +58,7 @@ public final class Macro extends TemplateElement implements TemplateModel {
     private final String name;
     private final String[] paramNames;
     private final Map<String, Expression> paramNamesWithDefault;
-    private final SpreadArgs spreadArgs;
+    private final WithArgs withArgs;
     private boolean requireArgsSpecialVariable;
     private final String catchAllParamName;
     private final boolean function;
@@ -78,7 +78,7 @@ public final class Macro extends TemplateElement implements TemplateModel {
         this.paramNamesWithDefault = paramNamesWithDefault;
         this.paramNames = paramNamesWithDefault.keySet().toArray(new String[0]);
         this.catchAllParamName = catchAllParamName;
-        this.spreadArgs = null;
+        this.withArgs = null;
         this.requireArgsSpecialVariable = requireArgsSpecialVariable;
         this.function = function;
         this.setChildren(children);
@@ -87,20 +87,20 @@ public final class Macro extends TemplateElement implements TemplateModel {
     }
 
     /**
-     * Copy-constructor with replacing {@link #spreadArgs} (with the quirk that the parent of the
+     * Copy-constructor with replacing {@link #withArgs} (with the quirk that the parent of the
      * child AST elements will stay the copied macro).
      *
-     * @param spreadArgs Usually {@code null}; used by {@link BuiltInsForCallables.spread_argsBI} to
+     * @param withArgs Usually {@code null}; used by {@link BuiltInsForCallables.with_argsBI} to
      *      set arbitrary default value to parameters. Note that the defaults aren't
      *      {@link Expression}-s, but {@link TemplateModel}-s.
      */
-    Macro(Macro that, SpreadArgs spreadArgs) {
+    Macro(Macro that, WithArgs withArgs) {
         // Attention! Keep this constructor in sync with the other constructor!
         this.name = that.name;
         this.paramNamesWithDefault = that.paramNamesWithDefault;
         this.paramNames = that.paramNames;
         this.catchAllParamName = that.catchAllParamName;
-        this.spreadArgs = spreadArgs; // Using the argument value here
+        this.withArgs = withArgs; // Using the argument value here
         this.requireArgsSpecialVariable = that.requireArgsSpecialVariable;
         this.function = that.function;
         this.namespaceLookupKey = that.namespaceLookupKey;
@@ -132,8 +132,9 @@ public final class Macro extends TemplateElement implements TemplateModel {
         return name;
     }
 
-    public SpreadArgs getSpreadArgs() {
-        return spreadArgs;
+    /** The arguments added via {@code ?with_args}; maybe {@code null}. */
+    public WithArgs getWithArgs() {
+        return withArgs;
     }
 
     public Object getNamespaceLookupKey() {
@@ -151,12 +152,12 @@ public final class Macro extends TemplateElement implements TemplateModel {
         StringBuilder sb = new StringBuilder();
         if (canonical) sb.append('<');
         sb.append(getNodeTypeSymbol());
-        if (spreadArgs != null) {
+        if (withArgs != null) {
             // As such a node won't be part of a template, this is probably never needed.
             sb.append('?')
                     .append(getTemplate().getActualNamingConvention() == Configuration.CAMEL_CASE_NAMING_CONVENTION
-                            ? BuiltIn.BI_NAME_CAMEL_CASE_SPREAD_ARGS
-                            : BuiltIn.BI_NAME_SNAKE_CASE_SPREAD_ARGS)
+                            ? BuiltIn.BI_NAME_CAMEL_CASE_WITH_ARGS
+                            : BuiltIn.BI_NAME_SNAKE_CASE_WITH_ARGS)
                     .append("(...)");
         }
         sb.append(' ');
@@ -476,16 +477,16 @@ public final class Macro extends TemplateElement implements TemplateModel {
         return true;
     }
 
-    static final class SpreadArgs {
+    static final class WithArgs {
         private final TemplateHashModelEx byName;
         private final TemplateSequenceModel byPosition;
 
-        SpreadArgs(TemplateHashModelEx byName) {
+        WithArgs(TemplateHashModelEx byName) {
             this.byName = byName;
             this.byPosition = null;
         }
 
-        SpreadArgs(TemplateSequenceModel byPosition) {
+        WithArgs(TemplateSequenceModel byPosition) {
             this.byName = null;
             this.byPosition = byPosition;
         }
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index f712b44..afe59d7 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -13060,11 +13060,6 @@ grant codeBase "file:/path/to/freemarker.jar"
           </listitem>
 
           <listitem>
-            <para><link
-            linkend="ref_builtin_spread_args">spread_args</link></para>
-          </listitem>
-
-          <listitem>
             <para><link linkend="ref_builtin_rtf">rtf</link></para>
           </listitem>
 
@@ -13183,6 +13178,11 @@ grant codeBase "file:/path/to/freemarker.jar"
 
           <listitem>
             <para><link
+            linkend="ref_builtin_with_args">with_args</link></para>
+          </listitem>
+
+          <listitem>
+            <para><link
             linkend="ref_builtin_word_list">word_list</link></para>
           </listitem>
 
@@ -19132,189 +19132,6 @@ Filer for positives:
           a <literal>long</literal>.</para>
         </section>
 
-        <section xml:id="ref_builtin_spread_args">
-          <title>spread_args</title>
-
-          <note>
-            <para>This built-in is available since 2.3.30</para>
-          </note>
-
-          <para>The goal of this built-in is to add parameters
-          <emphasis>dynamically</emphasis> to the call of a directive (like a
-          macro), function or method. Dynamically means that parameters are
-          added based on a hash value (like <literal>{'a': 1, 'b': 2, 'c':
-          3}</literal> or a Java <literal>Map</literal>), or a sequence value
-          (like <literal>[1, 2, 3]</literal> or a Java
-          <literal>List</literal>), whose the actual content is might only
-          known at the moment when the call happens.</para>
-
-          <para>For example, we have this macro <literal>m</literal>:</para>
-
-          <programlisting role="template">&lt;#macro m a b c&gt;a=${a}, b=${b}, c=${c}&lt;/#macro&gt;</programlisting>
-
-          <para>Normally you call it like:</para>
-
-          <programlisting role="template">&lt;@m a=1 b=2 c=3 /&gt;</programlisting>
-
-          <para>Below call does the same, assuming <literal>dynArgs</literal>
-          is the hash <literal>{'a': 1, 'b': 2, 'c': 3}</literal>:</para>
-
-          <programlisting role="template">&lt;@m?spread_args(dynArgs) /&gt;</programlisting>
-
-          <programlisting role="output">a=1, b=1, c=1</programlisting>
-
-          <para>Below call also does the same, but combines dynamic arguments
-          from <literal>dynArgsAB</literal>, assumed to be <literal>{'a': 1,
-          'b': 2}</literal>, and argument <literal>c</literal> specified
-          directly:</para>
-
-          <programlisting role="template">&lt;@m?spread_args(dynArgsAB) c=3 /&gt;</programlisting>
-
-          <programlisting role="output">a=1, b=1, c=1</programlisting>
-
-          <para>To understand why this works, you need to realize that macros,
-          custom directives, functions, and methods in FreeMarker are just
-          values, just like numbers, strings, etc. <literal>&lt;#macro m
-          <replaceable>...</replaceable>&gt;</literal> just creates a value
-          that's a macro (as opposed to a number, or string, etc.), and then
-          assigns it to variable <literal>m</literal>. Thus,
-          <literal>m</literal> in itself is a valid expression, which
-          evaluates to the macro (but it doesn't <emphasis>call</emphasis> the
-          macro). <literal>&lt;@m <replaceable>...</replaceable>
-          /&gt;</literal> evaluates the expression <literal>m</literal> (and
-          you can use arbitrarily complex expressions there too, like
-          <literal>m?spread_args(<replaceable>...</replaceable>)</literal>),
-          and then <emphasis>calls</emphasis> the resulting macro.
-          <literal>m?spread_args(<replaceable>dynArgs</replaceable>)</literal>
-          returns a macro that's very similar to the original macro (that's
-          stored in <literal>m</literal>), but its arguments default to the
-          values specified in
-          <literal><replaceable>dynArgs</replaceable></literal>. So the result
-          of <literal>m?spread_args({'b': 22, 'c': 33})</literal> is similar
-          to a modified macro that was created as <literal>&lt;#macro
-          <replaceable>unspefiedName</replaceable> a b=22 c=33&gt;</literal>.
-          With an example:</para>
-
-          <programlisting role="template">&lt;#assign mWithDefs = m?spread_args({'b': 22, 'c': 33})&gt;
-&lt;@myWithDefs a=1 c='overridden'/&gt;</programlisting>
-
-          <programlisting role="output">a=1, b=22, c=overridden</programlisting>
-
-          <para>Above we have created a new macro based on the value of
-          <literal>m</literal>, stored it in variable
-          <literal>mWithDefs</literal>, and then later we called it with
-          <literal>&lt;@myWithDefs <replaceable>...</replaceable>
-          /&gt;</literal>.</para>
-
-          <para><literal>spread_args</literal> can also be applied on
-          functions (crated with <literal>&lt;#function
-          <replaceable>...</replaceable>&gt;</literal>) and Java methods
-          (usually get from the data-model, like
-          <literal>myObject.myMethod</literal>). But because functions and
-          methods can only be called with positional arguments (like
-          <literal>f(1, 2, 3)</literal>, and <emphasis>not</emphasis> as
-          <literal>f(a=1, b=2, c=3)</literal>), the argument to
-          <literal>spread_args</literal> must be a sequence instead of a hash.
-          Other than that, the same tricks work as with macros:</para>
-
-          <programlisting role="template">&lt;#function f(a, b, c)&gt;&lt;#return "a=${a}, b=${b}, c=${c}"&gt;&lt;/#function&gt;
-&lt;#assign dynArgs=[1, 2, 3]&gt;
-
-${f(1, 2, 3)}
-Same as:
-${f?spread_args(dynArgs)()}
-or as:
-${f?spread_args([1, 2])(3)}
-or as:
-${f?spread_args([1])(2, 3)}
-
-&lt;#assign fWithOneAsFirstArg = f?spread_args([1])&gt;
-${fWithOneAsFirstArg(2, 3)} &lt;#-- same as f(1, 2, 3) --&gt;</programlisting>
-
-          <para>Note the double application of
-          <literal>(<replaceable>...</replaceable>)</literal> above, like in
-          <literal>f?spread_args(<replaceable>dynArgs</replaceable>)()</literal>.
-          That's because
-          <literal>f?spread_args(<replaceable>dynArgs</replaceable>)</literal>
-          just returns a new function (which is just a value), but doesn't
-          call it. So if you want to call that new function immediately (as
-          opposed to assigning it to a variable for example), you need the
-          second <literal>()</literal>.</para>
-
-          <para>Because macro calls support both named and positional
-          arguments, the <literal>spread_args</literal> argument can be a
-          sequence for macros as well (though using a hash is usually a better
-          practice):</para>
-
-          <programlisting role="template">&lt;#macro m a b c&gt;a=${a}, b=${b}, c=${c}&lt;/#macro&gt;
-
-&lt;#-- Called with named parameters: --&gt;
-&lt;@m a=1 b=2 c=3 /&gt;
-Same as:
-&lt;#-- Called with positional parameters: --&gt;
-&lt;@m 1 2 3 /&gt;
-Same as:
-&lt;@m?spread_args([1, 2, 3]) /&gt;
-Same as:
-&lt;#-- Sequence spread_args with positional c parameter: --&gt;
-&lt;@m?spread_args([1, 2]) 3 /&gt;
-Same as:
-&lt;#-- Sequence spread_args with named c parameter: --&gt;
-&lt;@m?spread_args([1, 2]) c=3 /&gt;</programlisting>
-
-          <para>To summarize, depending on the type of the value
-          <literal>spread_args</literal> is applied on, the type of argument
-          to <literal>spread_args</literal> can be:</para>
-
-          <itemizedlist>
-            <listitem>
-              <para>Function or method: sequence. Note that WRONG
-              <literal>f?spread_args(1, 2)</literal> is WRONG, the correct
-              form is <literal>f?spread_args([1, 2])</literal>.</para>
-            </listitem>
-
-            <listitem>
-              <para>Macro: hash or sequence</para>
-            </listitem>
-
-            <listitem>
-              <para>Directive (user defined): hash</para>
-            </listitem>
-          </itemizedlist>
-
-          <para>The return type of <literal>spread_args</literal> is the same
-          as the type of value it was applied on, like if it's applied on a
-          method (like
-          <literal>myObj.myMethod?spread_args(dynArgs)</literal>), then it
-          returns a method.</para>
-
-          <para>Note that it's not possible to apply
-          <literal>spread_args</literal> on built-in directives, like
-          <literal>&lt;#if <replaceable>...</replaceable>&gt;</literal>,
-          <literal>&lt;#list <replaceable>...</replaceable>&gt;</literal>,
-          etc., because they aren't available as values.</para>
-
-          <para>This built-in is often used together with the <link
-          linkend="specvar.args"><literal>.args</literal> special
-          variable</link>. For example:</para>
-
-          <programlisting role="template">&lt;#macro m1 a b c&gt;
-  m1 does things with ${a}, ${b}, ${c}
-&lt;/#macro&gt;
-
-&lt;#macro m2 a b c&gt;
-  m2 does things with ${a}, ${b}, ${c}
-  Delegate to m1:
-  &lt;@m1?spread_args(.args) /&gt;
-&lt;/#macro&gt;
-
-&lt;@m2 a=1 b=2 c=3 /&gt;</programlisting>
-
-          <programlisting role="output">  m2 does things with 1, 2, 3
-  Delegate to m1:
-  m1 does things with 1, 2, 3</programlisting>
-        </section>
-
         <section xml:id="ref_builtin_eval">
           <title>eval</title>
 
@@ -19871,6 +19688,188 @@ Again:
             chained together.</para>
           </simplesect>
         </section>
+
+        <section xml:id="ref_builtin_with_args">
+          <title>with_args</title>
+
+          <note>
+            <para>This built-in is available since 2.3.30</para>
+          </note>
+
+          <para>The goal of this built-in is to add parameters
+          <emphasis>dynamically</emphasis> to the call of a directive (like a
+          macro), function or method. Dynamically means that parameters are
+          added based on a hash value (like <literal>{'a': 1, 'b': 2, 'c':
+          3}</literal> or a Java <literal>Map</literal>), or a sequence value
+          (like <literal>[1, 2, 3]</literal> or a Java
+          <literal>List</literal>), whose actual content is might only known
+          at the moment when the call happens.</para>
+
+          <para>For example, we have this macro <literal>m</literal>:</para>
+
+          <programlisting role="template">&lt;#macro m a b c&gt;a=${a}, b=${b}, c=${c}&lt;/#macro&gt;</programlisting>
+
+          <para>Normally you call it like:</para>
+
+          <programlisting role="template">&lt;@m a=1 b=2 c=3 /&gt;</programlisting>
+
+          <para>Below call does the same, assuming <literal>dynArgs</literal>
+          is the hash <literal>{'a': 1, 'b': 2, 'c': 3}</literal>:</para>
+
+          <programlisting role="template">&lt;@m?with_args(dynArgs) /&gt;</programlisting>
+
+          <programlisting role="output">a=1, b=1, c=1</programlisting>
+
+          <para>Below call also does the same, but combines dynamic arguments
+          from <literal>dynArgsAB</literal>, assumed to be <literal>{'a': 1,
+          'b': 2}</literal>, and argument <literal>c</literal> specified
+          directly:</para>
+
+          <programlisting role="template">&lt;@m?with_args(dynArgsAB) c=3 /&gt;</programlisting>
+
+          <programlisting role="output">a=1, b=1, c=1</programlisting>
+
+          <para>To understand why this works, you need to realize that macros,
+          custom directives, functions, and methods in FreeMarker are just
+          values, just like numbers, strings, etc. <literal>&lt;#macro m
+          <replaceable>...</replaceable>&gt;</literal> just creates a value
+          that's a macro (as opposed to a number, or string, etc.), and then
+          assigns it to variable <literal>m</literal>. Thus,
+          <literal>m</literal> in itself is a valid expression, which
+          evaluates to the macro (but it doesn't <emphasis>call</emphasis> the
+          macro). <literal>&lt;@m <replaceable>...</replaceable>
+          /&gt;</literal> evaluates the expression <literal>m</literal> (and
+          you can use arbitrarily complex expressions there too, like
+          <literal>m?with_args(<replaceable>...</replaceable>)</literal>), and
+          then <emphasis>calls</emphasis> the resulting macro.
+          <literal>m?with_args(<replaceable>dynArgs</replaceable>)</literal>
+          returns a macro that's very similar to the original macro (that's
+          stored in <literal>m</literal>), but its arguments
+          <emphasis>default</emphasis> to the values specified in
+          <literal><replaceable>dynArgs</replaceable></literal>. So the result
+          of <literal>m?with_args({'b': 22, 'c': 33})</literal> is similar to
+          a modified macro that was created as <literal>&lt;#macro
+          <replaceable>unspefiedName</replaceable> a b=22 c=33&gt;</literal>.
+          With an example:</para>
+
+          <programlisting role="template">&lt;#assign mWithDefs = m?with_args({'b': 22, 'c': 33})&gt;
+&lt;@myWithDefs a=1 c='overridden'/&gt;</programlisting>
+
+          <programlisting role="output">a=1, b=22, c=overridden</programlisting>
+
+          <para>Above we have created a new macro based on the value of
+          <literal>m</literal>, stored it in variable
+          <literal>mWithDefs</literal>, and then later we called it with
+          <literal>&lt;@myWithDefs <replaceable>...</replaceable>
+          /&gt;</literal>.</para>
+
+          <para><literal>with_args</literal> can also be applied on functions
+          (crated with <literal>&lt;#function
+          <replaceable>...</replaceable>&gt;</literal>) and Java methods
+          (usually get from the data-model, like
+          <literal>myObject.myMethod</literal>). But because functions and
+          methods can only be called with positional arguments (like
+          <literal>f(1, 2, 3)</literal>, and <emphasis>not</emphasis> as
+          <literal>f(a=1, b=2, c=3)</literal>), the argument to
+          <literal>with_args</literal> must be a sequence instead of a hash.
+          Other than that, the same tricks work as with macros:</para>
+
+          <programlisting role="template">&lt;#function f(a, b, c)&gt;&lt;#return "a=${a}, b=${b}, c=${c}"&gt;&lt;/#function&gt;
+&lt;#assign dynArgs=[1, 2, 3]&gt;
+
+${f(1, 2, 3)}
+Same as:
+${f?with_args(dynArgs)()}
+or as:
+${f?with_args([1, 2])(3)}
+or as:
+${f?with_args([1])(2, 3)}
+
+&lt;#assign fWithOneAsFirstArg = f?with_args([1])&gt;
+${fWithOneAsFirstArg(2, 3)} &lt;#-- same as f(1, 2, 3) --&gt;</programlisting>
+
+          <para>Note the double application of
+          <literal>(<replaceable>...</replaceable>)</literal> above, like in
+          <literal>f?with_args(<replaceable>dynArgs</replaceable>)()</literal>.
+          That's because
+          <literal>f?with_args(<replaceable>dynArgs</replaceable>)</literal>
+          just returns a new function (which is just a value), but doesn't
+          call it. So if you want to call that new function immediately (as
+          opposed to assigning it to a variable for example), you need the
+          second <literal>()</literal>.</para>
+
+          <para>Because macro calls support both named and positional
+          arguments, the <literal>with_args</literal> argument can be a
+          sequence for macros as well (though using a hash is usually a better
+          practice):</para>
+
+          <programlisting role="template">&lt;#macro m a b c&gt;a=${a}, b=${b}, c=${c}&lt;/#macro&gt;
+
+&lt;#-- Called with named parameters: --&gt;
+&lt;@m a=1 b=2 c=3 /&gt;
+Same as:
+&lt;#-- Called with positional parameters: --&gt;
+&lt;@m 1 2 3 /&gt;
+Same as:
+&lt;@m?with_args([1, 2, 3]) /&gt;
+Same as:
+&lt;#-- Sequence with_args with positional c parameter: --&gt;
+&lt;@m?with_args([1, 2]) 3 /&gt;
+Same as:
+&lt;#-- Sequence with_args with named c parameter: --&gt;
+&lt;@m?with_args([1, 2]) c=3 /&gt;</programlisting>
+
+          <para>To summarize, depending on the type of the value
+          <literal>with_args</literal> is applied on, the type of argument to
+          <literal>with_args</literal> can be:</para>
+
+          <itemizedlist>
+            <listitem>
+              <para>Function or method: sequence. Note that WRONG
+              <literal>f?with_args(1, 2)</literal> is WRONG, the correct form
+              is <literal>f?with_args([1, 2])</literal>.</para>
+            </listitem>
+
+            <listitem>
+              <para>Macro: hash or sequence</para>
+            </listitem>
+
+            <listitem>
+              <para>Directive (user defined): hash</para>
+            </listitem>
+          </itemizedlist>
+
+          <para>The return type of <literal>with_args</literal> is the same as
+          the type of value it was applied on, like if it's applied on a
+          method (like <literal>myObj.myMethod?with_args(dynArgs)</literal>),
+          then it returns a method.</para>
+
+          <para>Note that it's not possible to apply
+          <literal>with_args</literal> on built-in directives, like
+          <literal>&lt;#if <replaceable>...</replaceable>&gt;</literal>,
+          <literal>&lt;#list <replaceable>...</replaceable>&gt;</literal>,
+          etc., because they aren't available as values.</para>
+
+          <para>This built-in is often used together with the <link
+          linkend="specvar.args"><literal>.args</literal> special
+          variable</link>. For example:</para>
+
+          <programlisting role="template">&lt;#macro m1 a b c&gt;
+  m1 does things with ${a}, ${b}, ${c}
+&lt;/#macro&gt;
+
+&lt;#macro m2 a b c&gt;
+  m2 does things with ${a}, ${b}, ${c}
+  Delegate to m1:
+  &lt;@m1?with_args(.args) /&gt;
+&lt;/#macro&gt;
+
+&lt;@m2 a=1 b=2 c=3 /&gt;</programlisting>
+
+          <programlisting role="output">  m2 does things with 1, 2, 3
+  Delegate to m1:
+  m1 does things with 1, 2, 3</programlisting>
+        </section>
       </section>
     </chapter>
 
@@ -24694,7 +24693,7 @@ There was no specific handler for node y
           directives, it returns all arguments of the current invocation of
           the macro or function. This allows processing all the arguments in
           an uniform way (like pass them to the <link
-          linkend="ref_builtin_spread_args"><literal>spread_args</literal>
+          linkend="ref_builtin_with_args"><literal>with_args</literal>
           built-in</link>). Further details:</para>
 
           <itemizedlist>
@@ -28972,11 +28971,11 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               <para><link
               xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-107">FREEMARKER-107</link>:
               Added
-              <literal>?<replaceable>spread_args</replaceable>(dynamicArguments)</literal>
+              <literal>?<replaceable>with_args</replaceable>(dynamicArguments)</literal>
               to add parameters dynamically to directive (like macro),
               function and method calls. Actually, this built-in returns
               directive or macro or function that has different parameter
-              defaults. <link linkend="ref_builtin_spread_args">See more
+              defaults. <link linkend="ref_builtin_with_args">See more
               here...</link></para>
             </listitem>
 
@@ -28989,7 +28988,7 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               which contains all the arguments. This is useful for operations
               that act on all the arguments uniformly, like for example to
               pass the arguments to <link
-              linkend="ref_builtin_spread_args"><literal>?spread_args(<replaceable>...</replaceable>)</literal></link>.</para>
+              linkend="ref_builtin_with_args"><literal>?with_args(<replaceable>...</replaceable>)</literal></link>.</para>
             </listitem>
 
             <listitem>
diff --git a/src/test/java/freemarker/core/SpreadArgsBuiltInTest.java b/src/test/java/freemarker/core/WithArgsBuiltInTest.java
similarity index 51%
rename from src/test/java/freemarker/core/SpreadArgsBuiltInTest.java
rename to src/test/java/freemarker/core/WithArgsBuiltInTest.java
index 1ecc81c..3712509 100644
--- a/src/test/java/freemarker/core/SpreadArgsBuiltInTest.java
+++ b/src/test/java/freemarker/core/WithArgsBuiltInTest.java
@@ -40,7 +40,7 @@ import freemarker.template.TemplateModel;
 import freemarker.template.TemplateModelException;
 import freemarker.test.TemplateTest;
 
-public class SpreadArgsBuiltInTest extends TemplateTest {
+public class WithArgsBuiltInTest extends TemplateTest {
 
     private static final String PRINT_O = "o=<#if o?isSequence>[${o?join(', ')}]" +
             "<#else>{<#list o as k,v>${k}=${v!'null'}<#sep>, </#list>}" +
@@ -86,140 +86,140 @@ public class SpreadArgsBuiltInTest extends TemplateTest {
     }
 
     @Test
-    public void testMacroWithNamedSpreadArgs() throws Exception {
+    public void testMacroWithNamedWithArgs() throws Exception {
         assertOutput("<@m b=2 a=1 />", "a=1; b=2; c=d3");
-        assertOutput("<@m?spreadArgs({'b': 2, 'a': 1}) />", "a=1; b=2; c=d3");
-        assertOutput("<@m?spreadArgs({'b': 2, 'a': 1}) a=11 />", "a=11; b=2; c=d3");
-        assertOutput("<@m?spreadArgs({'b': 2, 'a': 1}) a=11 b=22 />", "a=11; b=22; c=d3");
-        assertOutput("<@m?spreadArgs({'b': 2, 'c': 3}) a=1 />", "a=1; b=2; c=3");
-        assertOutput("<@m?spreadArgs({}) b=2 c=3 a=1 />", "a=1; b=2; c=3");
+        assertOutput("<@m?withArgs({'b': 2, 'a': 1}) />", "a=1; b=2; c=d3");
+        assertOutput("<@m?withArgs({'b': 2, 'a': 1}) a=11 />", "a=11; b=2; c=d3");
+        assertOutput("<@m?withArgs({'b': 2, 'a': 1}) a=11 b=22 />", "a=11; b=22; c=d3");
+        assertOutput("<@m?withArgs({'b': 2, 'c': 3}) a=1 />", "a=1; b=2; c=3");
+        assertOutput("<@m?withArgs({}) b=2 c=3 a=1 />", "a=1; b=2; c=3");
 
         assertOutput("<@mCA a=1 b=2 />", "a=1; b=2; o={}");
-        assertOutput("<@mCA?spreadArgs({'a': 1, 'b': 2}) />", "a=1; b=2; o={}");
-        assertOutput("<@mCA?spreadArgs({'a': 1}) b=2 />", "a=1; b=2; o={}");
-        assertOutput("<@mCA?spreadArgs({}) a=1 b=2 />", "a=1; b=2; o={}");
-        assertOutput("<@mCA?spreadArgs({'a': 1, 'b': 2, 'c': 3}) />", "a=1; b=2; o={c=3}");
-        assertOutput("<@mCA?spreadArgs({'a': 1, 'b': 2}) c=3 />", "a=1; b=2; o={c=3}");
-        assertOutput("<@mCA?spreadArgs({'a': 1}) b=2 c=3 />", "a=1; b=2; o={c=3}");
-        assertOutput("<@mCA?spreadArgs({}) a=1 b=2 c=3 />", "a=1; b=2; o={c=3}");
+        assertOutput("<@mCA?withArgs({'a': 1, 'b': 2}) />", "a=1; b=2; o={}");
+        assertOutput("<@mCA?withArgs({'a': 1}) b=2 />", "a=1; b=2; o={}");
+        assertOutput("<@mCA?withArgs({}) a=1 b=2 />", "a=1; b=2; o={}");
+        assertOutput("<@mCA?withArgs({'a': 1, 'b': 2, 'c': 3}) />", "a=1; b=2; o={c=3}");
+        assertOutput("<@mCA?withArgs({'a': 1, 'b': 2}) c=3 />", "a=1; b=2; o={c=3}");
+        assertOutput("<@mCA?withArgs({'a': 1}) b=2 c=3 />", "a=1; b=2; o={c=3}");
+        assertOutput("<@mCA?withArgs({}) a=1 b=2 c=3 />", "a=1; b=2; o={c=3}");
         assertOutput("<@mCA a=1 b=2 c=3 />", "a=1; b=2; o={c=3}");
         assertOutput("<@mCA a=1 b=2 c=3 d=4 />", "a=1; b=2; o={c=3, d=4}");
-        assertOutput("<@mCA?spreadArgs({'a': 1, 'b': 2, 'c': 3, 'd': 4}) />", "a=1; b=2; o={c=3, d=4}");
-        assertOutput("<@mCA?spreadArgs({'a': 1, 'b': 2, 'c': 3, 'd': 4}) b=22 />", "a=1; b=22; o={c=3, d=4}");
-        assertOutput("<@mCA?spreadArgs({'a': 1, 'b': 2, 'c': 3, 'd': 4}) b=22 e=5 />", "a=1; b=22; o={c=3, d=4, e=5}");
-        assertOutput("<@mCA?spreadArgs({'a': 1, 'b': 2, 'c': 3, 'd': 4}) 11 22 />", "a=11; b=22; o={c=3, d=4}");
-        assertOutput("<@mCA?spreadArgs({'a': 1, 'b': 2}) 11 22 33 />", "a=11; b=22; o=[33]");
-        assertErrorContains("<@mCA?spreadArgs({'a': 1, 'b': 2, 'c': 3}) 11 22 33 />",
+        assertOutput("<@mCA?withArgs({'a': 1, 'b': 2, 'c': 3, 'd': 4}) />", "a=1; b=2; o={c=3, d=4}");
+        assertOutput("<@mCA?withArgs({'a': 1, 'b': 2, 'c': 3, 'd': 4}) b=22 />", "a=1; b=22; o={c=3, d=4}");
+        assertOutput("<@mCA?withArgs({'a': 1, 'b': 2, 'c': 3, 'd': 4}) b=22 e=5 />", "a=1; b=22; o={c=3, d=4, e=5}");
+        assertOutput("<@mCA?withArgs({'a': 1, 'b': 2, 'c': 3, 'd': 4}) 11 22 />", "a=11; b=22; o={c=3, d=4}");
+        assertOutput("<@mCA?withArgs({'a': 1, 'b': 2}) 11 22 33 />", "a=11; b=22; o=[33]");
+        assertErrorContains("<@mCA?withArgs({'a': 1, 'b': 2, 'c': 3}) 11 22 33 />",
                 "both named and positional", "catch-all");
 
-        assertOutput("<@mCAO?spreadArgs({'a': 1, 'b': 2}) />", "o={a=1, b=2}");
-        assertOutput("<@mCAO?spreadArgs({'a': 1}) b=2 />", "o={a=1, b=2}");
-        assertOutput("<@mCAO?spreadArgs({}) a=1 b=2 />", "o={a=1, b=2}");
+        assertOutput("<@mCAO?withArgs({'a': 1, 'b': 2}) />", "o={a=1, b=2}");
+        assertOutput("<@mCAO?withArgs({'a': 1}) b=2 />", "o={a=1, b=2}");
+        assertOutput("<@mCAO?withArgs({}) a=1 b=2 />", "o={a=1, b=2}");
         assertOutput("<@mCAO a=1 b=2 />", "o={a=1, b=2}");
 
         assertOutput("<@mCAO />", "o=[]");
-        assertOutput("<@mCAO?spreadArgs({}) />", "o={}");
+        assertOutput("<@mCAO?withArgs({}) />", "o={}");
 
         assertOutput("<@m b=2 a=1 c=null />", "a=1; b=2; c=d3");
         Map<String, Integer> cNull = new HashMap<String, Integer>();
         cNull.put("c", null);
         addToDataModel("cNull", cNull);
-        assertOutput("<@m?spreadArgs(cNull) b=2 a=1 />", "a=1; b=2; c=d3");
+        assertOutput("<@m?withArgs(cNull) b=2 a=1 />", "a=1; b=2; c=d3");
     }
 
     @Test
-    public void testNullsWithMacroWithNamedSpreadArgs() throws Exception {
-        // Null-s in ?spreadArgs should behave similarly as if they were given directly as argument.
+    public void testNullsWithMacroWithNamedWithArgs() throws Exception {
+        // Null-s in ?withArgs should behave similarly as if they were given directly as argument.
         assertOutput("<@mCAO a=null b=null />", "o={a=null, b=null}");
         Map<String, Integer> aNullBNull = new LinkedHashMap<String, Integer>();
         aNullBNull.put("a", null);
         aNullBNull.put("b", null);
         addToDataModel("aNullBNull", aNullBNull);
-        assertOutput("<@mCAO?spreadArgs(aNullBNull) />", "o={a=null, b=null}");
+        assertOutput("<@mCAO?withArgs(aNullBNull) />", "o={a=null, b=null}");
 
-        assertOutput("<@m?spreadArgs({'a': 11, 'b': 22, 'c': 33}) a=111 b=222 c=null />", "a=111; b=222; c=d3");
-        assertErrorContains("<@m?spreadArgs({'a': 11, 'b': 22, 'c': 33}) a=111 b=null c=333 />", "required", "\"b\"");
-        assertOutput("<@mCAO?spreadArgs({'a': 1, 'b': 2}) a=null b=22 c=33 />", "o={a=null, b=22, c=33}");
+        assertOutput("<@m?withArgs({'a': 11, 'b': 22, 'c': 33}) a=111 b=222 c=null />", "a=111; b=222; c=d3");
+        assertErrorContains("<@m?withArgs({'a': 11, 'b': 22, 'c': 33}) a=111 b=null c=333 />", "required", "\"b\"");
+        assertOutput("<@mCAO?withArgs({'a': 1, 'b': 2}) a=null b=22 c=33 />", "o={a=null, b=22, c=33}");
     }
 
     @Test
-    public void testMacroWithPositionalSpreadArgs() throws Exception {
+    public void testMacroWithPositionalWithArgs() throws Exception {
         assertOutput("<@m 1 2 />", "a=1; b=2; c=d3");
-        assertOutput("<@m?spreadArgs([1, 2]) />", "a=1; b=2; c=d3");
-        assertOutput("<@m?spreadArgs([1]) 2 />", "a=1; b=2; c=d3");
-        assertOutput("<@m?spreadArgs([]) 1 2 />", "a=1; b=2; c=d3");
+        assertOutput("<@m?withArgs([1, 2]) />", "a=1; b=2; c=d3");
+        assertOutput("<@m?withArgs([1]) 2 />", "a=1; b=2; c=d3");
+        assertOutput("<@m?withArgs([]) 1 2 />", "a=1; b=2; c=d3");
         assertOutput("<@m 1 2 3 />", "a=1; b=2; c=3");
-        assertOutput("<@m?spreadArgs([1, 2, 3]) />", "a=1; b=2; c=3");
-        assertOutput("<@m?spreadArgs([1, 2]) c=3 />", "a=1; b=2; c=3");
-        assertOutput("<@m?spreadArgs([1, 2, 0]) c=3 />", "a=1; b=2; c=3");
-        assertOutput("<@m?spreadArgs([1, 0, 3]) b=2 />", "a=1; b=2; c=3");
+        assertOutput("<@m?withArgs([1, 2, 3]) />", "a=1; b=2; c=3");
+        assertOutput("<@m?withArgs([1, 2]) c=3 />", "a=1; b=2; c=3");
+        assertOutput("<@m?withArgs([1, 2, 0]) c=3 />", "a=1; b=2; c=3");
+        assertOutput("<@m?withArgs([1, 0, 3]) b=2 />", "a=1; b=2; c=3");
 
         assertOutput("<@mCA 1 2 />", "a=1; b=2; o=[]");
-        assertOutput("<@mCA?spreadArgs([1, 2]) />", "a=1; b=2; o=[]");
-        assertOutput("<@mCA?spreadArgs([1]) 2 />", "a=1; b=2; o=[]");
-        assertOutput("<@mCA?spreadArgs([]) 1 2 />", "a=1; b=2; o=[]");
+        assertOutput("<@mCA?withArgs([1, 2]) />", "a=1; b=2; o=[]");
+        assertOutput("<@mCA?withArgs([1]) 2 />", "a=1; b=2; o=[]");
+        assertOutput("<@mCA?withArgs([]) 1 2 />", "a=1; b=2; o=[]");
         assertOutput("<@mCA 1 2 3 />", "a=1; b=2; o=[3]");
-        assertOutput("<@mCA?spreadArgs([1, 2, 3]) />", "a=1; b=2; o=[3]");
-        assertOutput("<@mCA?spreadArgs([1]) 2, 3 />", "a=1; b=2; o=[3]");
-        assertOutput("<@mCA?spreadArgs([1, 2]) 3 />", "a=1; b=2; o=[3]");
-        assertOutput("<@mCA?spreadArgs([1]) b=2 c=3 />", "a=1; b=2; o={c=3}");
-        assertOutput("<@mCA?spreadArgs([]) a=1 b=2 c=3 />", "a=1; b=2; o={c=3}");
-        assertOutput("<@mCA?spreadArgs([1, 2]) c=3 />", "a=1; b=2; o={c=3}");
-        assertOutput("<@mCA?spreadArgs([1, 0]) b=2 c=3 />", "a=1; b=2; o={c=3}");
-        assertErrorContains("<@mCA?spreadArgs([1, 2, 3]) d=4 />",
+        assertOutput("<@mCA?withArgs([1, 2, 3]) />", "a=1; b=2; o=[3]");
+        assertOutput("<@mCA?withArgs([1]) 2, 3 />", "a=1; b=2; o=[3]");
+        assertOutput("<@mCA?withArgs([1, 2]) 3 />", "a=1; b=2; o=[3]");
+        assertOutput("<@mCA?withArgs([1]) b=2 c=3 />", "a=1; b=2; o={c=3}");
+        assertOutput("<@mCA?withArgs([]) a=1 b=2 c=3 />", "a=1; b=2; o={c=3}");
+        assertOutput("<@mCA?withArgs([1, 2]) c=3 />", "a=1; b=2; o={c=3}");
+        assertOutput("<@mCA?withArgs([1, 0]) b=2 c=3 />", "a=1; b=2; o={c=3}");
+        assertErrorContains("<@mCA?withArgs([1, 2, 3]) d=4 />",
                 "both named and positional", "catch-all");
 
-        assertOutput("<@mCAO?spreadArgs([1, 2]) />", "o=[1, 2]");
-        assertOutput("<@mCAO?spreadArgs([1]) 2 />", "o=[1, 2]");
+        assertOutput("<@mCAO?withArgs([1, 2]) />", "o=[1, 2]");
+        assertOutput("<@mCAO?withArgs([1]) 2 />", "o=[1, 2]");
         assertOutput("<@mCAO 1, 2 />", "o=[1, 2]");
 
-        assertOutput("<@mCAO?spreadArgs([]) />", "o=[]");
+        assertOutput("<@mCAO?withArgs([]) />", "o=[]");
     }
 
     @Test
-    public void testNullsWithMacroWithPositionalSpreadArgs() throws Exception {
-        // Null-s in ?spreadArgs should behave similarly as if they were given directly as argument.
+    public void testNullsWithMacroWithPositionalWithArgs() throws Exception {
+        // Null-s in ?withArgs should behave similarly as if they were given directly as argument.
         assertOutput("<@mCAO 1 null null 4 />", "o=[1, 4]"); // [FM3] Should be: 1, null, null, 4
         addToDataModel("args", Arrays.asList(1, null, null, 4));
-        assertOutput("<@mCAO?spreadArgs(args) />", "o=[1, 4]"); // [FM3] See above
-        assertOutput("<@mCAO?spreadArgs(args) null 5 6 />", "o=[1, 4, 5, 6]"); // [FM3] See above
+        assertOutput("<@mCAO?withArgs(args) />", "o=[1, 4]"); // [FM3] See above
+        assertOutput("<@mCAO?withArgs(args) null 5 6 />", "o=[1, 4, 5, 6]"); // [FM3] See above
     }
 
     @Test
     public void testFunction() throws Exception {
         assertOutput("${f(1, 2)}", "a=1; b=2; c=d3");
-        assertOutput("${f?spreadArgs([1, 2])()}", "a=1; b=2; c=d3");
-        assertOutput("${f?spreadArgs([1])(2)}", "a=1; b=2; c=d3");
-        assertOutput("${f?spreadArgs([])(1, 2)}", "a=1; b=2; c=d3");
+        assertOutput("${f?withArgs([1, 2])()}", "a=1; b=2; c=d3");
+        assertOutput("${f?withArgs([1])(2)}", "a=1; b=2; c=d3");
+        assertOutput("${f?withArgs([])(1, 2)}", "a=1; b=2; c=d3");
         assertOutput("${f(1, 2, 3)}", "a=1; b=2; c=3");
-        assertOutput("${f?spreadArgs([1, 2, 3])()}", "a=1; b=2; c=3");
+        assertOutput("${f?withArgs([1, 2, 3])()}", "a=1; b=2; c=3");
 
         assertOutput("${fCA(1, 2)}", "a=1; b=2; o=[]");
-        assertOutput("${fCA?spreadArgs([1, 2])()}", "a=1; b=2; o=[]");
-        assertOutput("${fCA?spreadArgs([1])(2)}", "a=1; b=2; o=[]");
-        assertOutput("${fCA?spreadArgs([])(1, 2)}", "a=1; b=2; o=[]");
+        assertOutput("${fCA?withArgs([1, 2])()}", "a=1; b=2; o=[]");
+        assertOutput("${fCA?withArgs([1])(2)}", "a=1; b=2; o=[]");
+        assertOutput("${fCA?withArgs([])(1, 2)}", "a=1; b=2; o=[]");
         assertOutput("${fCA(1, 2, 3)}", "a=1; b=2; o=[3]");
-        assertOutput("${fCA?spreadArgs([1, 2, 3])()}", "a=1; b=2; o=[3]");
-        assertOutput("${fCA?spreadArgs([1])(2, 3)}", "a=1; b=2; o=[3]");
-        assertOutput("${fCA?spreadArgs([1, 2])(3)}", "a=1; b=2; o=[3]");
-        assertOutput("${fCA?spreadArgs([])(1, 2, 3)}", "a=1; b=2; o=[3]");
+        assertOutput("${fCA?withArgs([1, 2, 3])()}", "a=1; b=2; o=[3]");
+        assertOutput("${fCA?withArgs([1])(2, 3)}", "a=1; b=2; o=[3]");
+        assertOutput("${fCA?withArgs([1, 2])(3)}", "a=1; b=2; o=[3]");
+        assertOutput("${fCA?withArgs([])(1, 2, 3)}", "a=1; b=2; o=[3]");
 
         assertOutput("${fCAO(1, 2)}", "o=[1, 2]");
-        assertOutput("${fCAO?spreadArgs([1, 2])()}", "o=[1, 2]");
-        assertOutput("${fCAO?spreadArgs([1])(2)}", "o=[1, 2]");
-        assertOutput("${fCAO?spreadArgs([])(1, 2)}", "o=[1, 2]");
+        assertOutput("${fCAO?withArgs([1, 2])()}", "o=[1, 2]");
+        assertOutput("${fCAO?withArgs([1])(2)}", "o=[1, 2]");
+        assertOutput("${fCAO?withArgs([])(1, 2)}", "o=[1, 2]");
 
-        assertErrorContains("${f?spreadArgs({'a': 1, 'b': 2})}",
-                "function", "hash", "sequence", "?spreadArgs");
+        assertErrorContains("${f?withArgs({'a': 1, 'b': 2})}",
+                "function", "hash", "sequence", "?withArgs");
     }
 
     @Test
     public void testNullsWithFunction() throws Exception {
-        // Null-s in ?spreadArgs should behave similarly as if they were given directly as argument.
+        // Null-s in ?withArgs should behave similarly as if they were given directly as argument.
         assertOutput("${fCAO(1, null, null, 4)}", "o=[1, 4]"); // [FM3] Should be: 1, null, null, 4
         addToDataModel("args", Arrays.asList(1, null, null, 4));
-        assertOutput("${fCAO?spreadArgs(args)()}", "o=[1, 4]"); // [FM3] See above
-        assertOutput("${fCAO?spreadArgs(args)(null, 5, 6)}", "o=[1, 4, 5, 6]"); // [FM3] See above
+        assertOutput("${fCAO?withArgs(args)()}", "o=[1, 4]"); // [FM3] See above
+        assertOutput("${fCAO?withArgs(args)(null, 5, 6)}", "o=[1, 4, 5, 6]"); // [FM3] See above
     }
 
     @Test
@@ -238,7 +238,7 @@ public class SpreadArgsBuiltInTest extends TemplateTest {
                 "<#import 'ns1.ftl' as ns1>" +
                 "<#assign v = 'NS0'>" +
                 "<@ns1.m 1; n>n=${n} v=${v}</@>; " +
-                "<#assign m2 = ns1.m?spreadArgs([2])>" +
+                "<#assign m2 = ns1.m?withArgs([2])>" +
                 "<@m2; n>n=${n} v=${v}</@>",
         "p=1 v=NS1 v=L {n=1 v=NS0} v=L; " +
                 "p=2 v=NS1 v=L {n=2 v=NS0} v=L");
@@ -250,49 +250,49 @@ public class SpreadArgsBuiltInTest extends TemplateTest {
 
         // No error:
         assertOutput(macroDef + "<@m 1 2 3 />", "1, 2, 3");
-        assertOutput(macroDef + "<@m?spread_args([1, 2, 3]) />", "1, 2, 3");
-        assertOutput(macroDef + "<@m?spread_args([1, 2]) 3 />", "1, 2, 3");
+        assertOutput(macroDef + "<@m?with_args([1, 2, 3]) />", "1, 2, 3");
+        assertOutput(macroDef + "<@m?with_args([1, 2]) 3 />", "1, 2, 3");
 
         // Too many args:
         assertErrorContains(macroDef + "<@m 1 2 3 4 />", "accepts 3", "got 4");
-        assertErrorContains(macroDef + "<@m?spread_args([1, 2, 3, 4]) />", "accepts 3", "got 4");
-        assertErrorContains(macroDef + "<@m?spread_args([1, 2, 3]) 5 />", "accepts 3", "got 4");
-        assertErrorContains(macroDef + "<@m?spread_args([1]) 2 3 4 />", "accepts 3", "got 4");
+        assertErrorContains(macroDef + "<@m?with_args([1, 2, 3, 4]) />", "accepts 3", "got 4");
+        assertErrorContains(macroDef + "<@m?with_args([1, 2, 3]) 5 />", "accepts 3", "got 4");
+        assertErrorContains(macroDef + "<@m?with_args([1]) 2 3 4 />", "accepts 3", "got 4");
 
         // Too few args:
         assertErrorContains(macroDef + "<@m 1 2 />", "\"c\"", "was not specified");
-        assertErrorContains(macroDef + "<@m?spread_args([1, 2]) />", "\"c\"", "was not specified");
-        assertErrorContains(macroDef + "<@m?spread_args([1]) 2 />", "\"c\"", "was not specified");
-        assertErrorContains(macroDef + "<@m?spread_args([]) 1 2 />", "\"c\"", "was not specified");
+        assertErrorContains(macroDef + "<@m?with_args([1, 2]) />", "\"c\"", "was not specified");
+        assertErrorContains(macroDef + "<@m?with_args([1]) 2 />", "\"c\"", "was not specified");
+        assertErrorContains(macroDef + "<@m?with_args([]) 1 2 />", "\"c\"", "was not specified");
     }
 
     @Test
     public void testDefaultsThenCatchAll() throws IOException, TemplateException {
         String macroDef = "<#macro m a=1 b=2 c=3 o...>a=${a} b=${b} c=${c} " + PRINT_O + "</#macro>";
 
-        assertOutput(macroDef + "<@m?spreadArgs([]) />", "a=1 b=2 c=3 o=[]");
-        assertOutput(macroDef + "<@m?spreadArgs([11]) />", "a=11 b=2 c=3 o=[]");
-        assertOutput(macroDef + "<@m?spreadArgs([11, 22]) />", "a=11 b=22 c=3 o=[]");
-        assertOutput(macroDef + "<@m?spreadArgs([11, 22, 33]) />", "a=11 b=22 c=33 o=[]");
-        assertOutput(macroDef + "<@m?spreadArgs([11, 22, 33, 44]) />", "a=11 b=22 c=33 o=[44]");
-        assertOutput(macroDef + "<@m?spreadArgs([11, 22, 33, 44, 55]) />", "a=11 b=22 c=33 o=[44, 55]");
-
-        assertOutput(macroDef + "<@m?spreadArgs([]) 11 />", "a=11 b=2 c=3 o=[]");
-        assertOutput(macroDef + "<@m?spreadArgs([11]) 22 />", "a=11 b=22 c=3 o=[]");
-        assertOutput(macroDef + "<@m?spreadArgs([11, 22]) 33 />", "a=11 b=22 c=33 o=[]");
-        assertOutput(macroDef + "<@m?spreadArgs([11, 22, 33]) 44 />", "a=11 b=22 c=33 o=[44]");
-        assertOutput(macroDef + "<@m?spreadArgs([11, 22, 33, 44]) 55 />", "a=11 b=22 c=33 o=[44, 55]");
-
-        assertOutput(macroDef + "<@m?spreadArgs({}) />", "a=1 b=2 c=3 o={}");
-        assertOutput(macroDef + "<@m?spreadArgs({'b':22}) />", "a=1 b=22 c=3 o={}");
-        assertOutput(macroDef + "<@m?spreadArgs({'b':22, 'c':33}) />", "a=1 b=22 c=33 o={}");
-        assertOutput(macroDef + "<@m?spreadArgs({'b':22, 'c':33, 'd':55}) />", "a=1 b=22 c=33 o={d=55}");
-        assertOutput(macroDef + "<@m?spreadArgs({'b':22, 'd':55, 'e':66}) />", "a=1 b=22 c=3 o={d=55, e=66}");
-
-        assertOutput(macroDef + "<@m?spreadArgs({}) b=22 />", "a=1 b=22 c=3 o={}");
-        assertOutput(macroDef + "<@m?spreadArgs({'b':22}) c=33 />", "a=1 b=22 c=33 o={}");
-        assertOutput(macroDef + "<@m?spreadArgs({'b':22, 'c':33}) d=55 />", "a=1 b=22 c=33 o={d=55}");
-        assertOutput(macroDef + "<@m?spreadArgs({'b':22, 'd':55}) e=66 />", "a=1 b=22 c=3 o={d=55, e=66}");
+        assertOutput(macroDef + "<@m?withArgs([]) />", "a=1 b=2 c=3 o=[]");
+        assertOutput(macroDef + "<@m?withArgs([11]) />", "a=11 b=2 c=3 o=[]");
+        assertOutput(macroDef + "<@m?withArgs([11, 22]) />", "a=11 b=22 c=3 o=[]");
+        assertOutput(macroDef + "<@m?withArgs([11, 22, 33]) />", "a=11 b=22 c=33 o=[]");
+        assertOutput(macroDef + "<@m?withArgs([11, 22, 33, 44]) />", "a=11 b=22 c=33 o=[44]");
+        assertOutput(macroDef + "<@m?withArgs([11, 22, 33, 44, 55]) />", "a=11 b=22 c=33 o=[44, 55]");
+
+        assertOutput(macroDef + "<@m?withArgs([]) 11 />", "a=11 b=2 c=3 o=[]");
+        assertOutput(macroDef + "<@m?withArgs([11]) 22 />", "a=11 b=22 c=3 o=[]");
+        assertOutput(macroDef + "<@m?withArgs([11, 22]) 33 />", "a=11 b=22 c=33 o=[]");
+        assertOutput(macroDef + "<@m?withArgs([11, 22, 33]) 44 />", "a=11 b=22 c=33 o=[44]");
+        assertOutput(macroDef + "<@m?withArgs([11, 22, 33, 44]) 55 />", "a=11 b=22 c=33 o=[44, 55]");
+
+        assertOutput(macroDef + "<@m?withArgs({}) />", "a=1 b=2 c=3 o={}");
+        assertOutput(macroDef + "<@m?withArgs({'b':22}) />", "a=1 b=22 c=3 o={}");
+        assertOutput(macroDef + "<@m?withArgs({'b':22, 'c':33}) />", "a=1 b=22 c=33 o={}");
+        assertOutput(macroDef + "<@m?withArgs({'b':22, 'c':33, 'd':55}) />", "a=1 b=22 c=33 o={d=55}");
+        assertOutput(macroDef + "<@m?withArgs({'b':22, 'd':55, 'e':66}) />", "a=1 b=22 c=3 o={d=55, e=66}");
+
+        assertOutput(macroDef + "<@m?withArgs({}) b=22 />", "a=1 b=22 c=3 o={}");
+        assertOutput(macroDef + "<@m?withArgs({'b':22}) c=33 />", "a=1 b=22 c=33 o={}");
+        assertOutput(macroDef + "<@m?withArgs({'b':22, 'c':33}) d=55 />", "a=1 b=22 c=33 o={d=55}");
+        assertOutput(macroDef + "<@m?withArgs({'b':22, 'd':55}) e=66 />", "a=1 b=22 c=3 o={d=55, e=66}");
     }
 
     @Test
@@ -300,26 +300,26 @@ public class SpreadArgsBuiltInTest extends TemplateTest {
         addToDataModel("obj", new MethodHolder());
 
         assertOutput("${obj.m3p(1, 2, 3)}", "1, 2, 3");
-        assertOutput("${obj.m3p?spreadArgs([1, 2, 3])()}", "1, 2, 3");
-        assertOutput("${obj.m3p?spreadArgs([1, 2])(3)}", "1, 2, 3");
-        assertOutput("${obj.m3p?spreadArgs([1])(2, 3)}", "1, 2, 3");
-        assertOutput("${obj.m3p?spreadArgs([])(1, 2, 3)}", "1, 2, 3");
+        assertOutput("${obj.m3p?withArgs([1, 2, 3])()}", "1, 2, 3");
+        assertOutput("${obj.m3p?withArgs([1, 2])(3)}", "1, 2, 3");
+        assertOutput("${obj.m3p?withArgs([1])(2, 3)}", "1, 2, 3");
+        assertOutput("${obj.m3p?withArgs([])(1, 2, 3)}", "1, 2, 3");
 
         assertOutput("${obj.m0p()}", "OK");
-        assertOutput("${obj.m0p?spreadArgs([])()}", "OK");
+        assertOutput("${obj.m0p?withArgs([])()}", "OK");
 
         assertOutput("${obj.mVA(1, 2, 3, 4)}", "1, 2, o=[3, 4]");
-        assertOutput("${obj.mVA?spreadArgs([1, 2, 3, 4])()}", "1, 2, o=[3, 4]");
-        assertOutput("${obj.mVA?spreadArgs([1, 2, 3])(4)}", "1, 2, o=[3, 4]");
-        assertOutput("${obj.mVA?spreadArgs([1, 2])(3, 4)}", "1, 2, o=[3, 4]");
-        assertOutput("${obj.mVA?spreadArgs([1])(2, 3, 4)}", "1, 2, o=[3, 4]");
-        assertOutput("${obj.mVA?spreadArgs([])(1, 2, 3, 4)}", "1, 2, o=[3, 4]");
+        assertOutput("${obj.mVA?withArgs([1, 2, 3, 4])()}", "1, 2, o=[3, 4]");
+        assertOutput("${obj.mVA?withArgs([1, 2, 3])(4)}", "1, 2, o=[3, 4]");
+        assertOutput("${obj.mVA?withArgs([1, 2])(3, 4)}", "1, 2, o=[3, 4]");
+        assertOutput("${obj.mVA?withArgs([1])(2, 3, 4)}", "1, 2, o=[3, 4]");
+        assertOutput("${obj.mVA?withArgs([])(1, 2, 3, 4)}", "1, 2, o=[3, 4]");
 
-        assertErrorContains("${obj.mVA?spreadArgs({})}", "hash", "sequence", "argument");
+        assertErrorContains("${obj.mVA?withArgs({})}", "hash", "sequence", "argument");
 
         assertOutput("${obj.mNullable(null, 2, null)}", "null, 2, null");
         addToDataModel("args", Arrays.asList(null, 2, null));
-        assertOutput("${obj.mNullable?spreadArgs(args)()}", "null, 2, null");
+        assertOutput("${obj.mNullable?withArgs(args)()}", "null, 2, null");
     }
 
     public static class MethodHolder {
@@ -355,9 +355,9 @@ public class SpreadArgsBuiltInTest extends TemplateTest {
         addToDataModel("legacyMethod", new LegacyMethodModel());
         getConfiguration().setNumberFormat("0.00");
         assertOutput("${legacyMethod(1, '2')}", "[1.00, 2]");
-        assertOutput("${legacyMethod?spreadArgs([1, '2'])()}", "[1.00, 2]");
-        assertOutput("${legacyMethod?spreadArgs([1])('2')}", "[1.00, 2]");
-        assertOutput("${legacyMethod?spreadArgs([])(1, '2')}", "[1.00, 2]");
+        assertOutput("${legacyMethod?withArgs([1, '2'])()}", "[1.00, 2]");
+        assertOutput("${legacyMethod?withArgs([1])('2')}", "[1.00, 2]");
+        assertOutput("${legacyMethod?withArgs([])(1, '2')}", "[1.00, 2]");
     }
 
     private static class LegacyMethodModel implements TemplateMethodModel {
@@ -377,18 +377,18 @@ public class SpreadArgsBuiltInTest extends TemplateTest {
 
         assertOutput("<@directive a=1 b=2 c=3; u, v>${u} ${v}</@>",
                 "{a=1, b=2, c=3}{11 22}");
-        assertOutput("<@directive?spreadArgs({'a': 1, 'b': 2, 'c': 3}); u, v>${u} ${v}</@>",
+        assertOutput("<@directive?withArgs({'a': 1, 'b': 2, 'c': 3}); u, v>${u} ${v}</@>",
                 "{a=1, b=2, c=3}{11 22}");
-        assertOutput("<@directive?spreadArgs({'a': 1, 'b': 2}) c=3; u, v>${u} ${v}</@>",
+        assertOutput("<@directive?withArgs({'a': 1, 'b': 2}) c=3; u, v>${u} ${v}</@>",
                 "{a=1, b=2, c=3}{11 22}");
-        assertOutput("<@directive?spreadArgs({'a': 1}) b=2 c=3; u, v>${u} ${v}</@>",
+        assertOutput("<@directive?withArgs({'a': 1}) b=2 c=3; u, v>${u} ${v}</@>",
                 "{a=1, b=2, c=3}{11 22}");
-        assertOutput("<@directive?spreadArgs({}) a=1 b=2 c=3; u, v>${u} ${v}</@>",
+        assertOutput("<@directive?withArgs({}) a=1 b=2 c=3; u, v>${u} ${v}</@>",
                 "{a=1, b=2, c=3}{11 22}");
 
-        assertOutput("<@directive?spreadArgs({}); u, v>${u} ${v}</@>",
+        assertOutput("<@directive?withArgs({}); u, v>${u} ${v}</@>",
                 "{}{11 22}");
-        assertOutput("<@directive?spreadArgs({'a': 1, 'b': 2}) b=22 c=3; u>${u}</@>",
+        assertOutput("<@directive?withArgs({'a': 1, 'b': 2}) b=22 c=3; u>${u}</@>",
                 "{a=1, b=22, c=3}{11}");
         Map<String, Integer> args = new LinkedHashMap<String, Integer>();
         args.put("a", null);
@@ -396,7 +396,7 @@ public class SpreadArgsBuiltInTest extends TemplateTest {
         args.put("c", 3);
         args.put("e", 6);
         addToDataModel("args", args);
-        assertOutput("<@directive?spreadArgs(args) b=22 c=null d=55 />",
+        assertOutput("<@directive?withArgs(args) b=22 c=null d=55 />",
                 "{a=null, b=22, c=null, e=6, d=55}{}");
     }
 
diff --git a/src/test/java/freemarker/manual/SpreadArgsExamples.java b/src/test/java/freemarker/manual/WithArgsExamples.java
similarity index 88%
rename from src/test/java/freemarker/manual/SpreadArgsExamples.java
rename to src/test/java/freemarker/manual/WithArgsExamples.java
index 95ad3cd..51d10b8 100644
--- a/src/test/java/freemarker/manual/SpreadArgsExamples.java
+++ b/src/test/java/freemarker/manual/WithArgsExamples.java
@@ -25,11 +25,11 @@ import org.junit.Test;
 
 import freemarker.template.TemplateException;
 
-public class SpreadArgsExamples extends ExamplesTest {
+public class WithArgsExamples extends ExamplesTest {
 
     @Test
     public void usingWithArgsSpecialVariable() throws IOException, TemplateException {
-        assertOutputForNamed("SpreadArgsExamples-usingWithArgsSpecialVariable.ftl");
+        assertOutputForNamed("WithArgsExamples-usingWithArgsSpecialVariable.ftl");
     }
 
 }
diff --git a/src/test/resources/freemarker/manual/SpreadArgsExamples-usingWithArgsSpecialVariable.ftl b/src/test/resources/freemarker/manual/WithArgsExamples-usingWithArgsSpecialVariable.ftl
similarity index 85%
rename from src/test/resources/freemarker/manual/SpreadArgsExamples-usingWithArgsSpecialVariable.ftl
rename to src/test/resources/freemarker/manual/WithArgsExamples-usingWithArgsSpecialVariable.ftl
index ceb3941..9819fa0 100644
--- a/src/test/resources/freemarker/manual/SpreadArgsExamples-usingWithArgsSpecialVariable.ftl
+++ b/src/test/resources/freemarker/manual/WithArgsExamples-usingWithArgsSpecialVariable.ftl
@@ -5,7 +5,7 @@
 <#macro m2 a b c>
   m2 does things with ${a}, ${b}, ${c}
   Delegate to m1:
-  <@m1?spread_args(.args) />
+  <@m1?with_args(.args) />
 </#macro>
 
 <@m2 a=1 b=2 c=3 />
diff --git a/src/test/resources/freemarker/manual/SpreadArgsExamples-usingWithArgsSpecialVariable.ftl.out b/src/test/resources/freemarker/manual/WithArgsExamples-usingWithArgsSpecialVariable.ftl.out
similarity index 100%
rename from src/test/resources/freemarker/manual/SpreadArgsExamples-usingWithArgsSpecialVariable.ftl.out
rename to src/test/resources/freemarker/manual/WithArgsExamples-usingWithArgsSpecialVariable.ftl.out


Mime
View raw message