Ann Mathews
Ann Mathews

Reputation: 56

Minimum arguments for variable parameters in freemarker macros

When you have variable parameters in a macro, for instance

 <#macro m a b c...>

Do you have to pass a minimum of 3 arguments or 2 while calling the macro? Does the parameter c here have to have at least 1 value? Also is there any way to specify a parameter as null by default?

Upvotes: 3

Views: 4491

Answers (2)

obourgain
obourgain

Reputation: 9336

When you have variable parameters in a macro, you don't have to pass a value for the last argument.

For example:

<#macro m a b c...>
    a = ${a!}
    b = ${b!}
    <#list c?keys as attr>
    ${attr} = ${c[attr]}
    </#list>
</#macro>

<@m a='A' b='B' />

<@m a='A' b='B' c='C' d='D'/>

Will output:

a = A
b = B


a = A
b = B
c = C
d = D

Upvotes: 1

Kian
Kian

Reputation: 1350

<#macro name param1 param2 ... paramN>
  ...
  <#nested loopvar1, loopvar2, ..., loopvarN>
  ...
  <#return>
  ...
</#macro>

Where:

  • name: name of macro variable. It's not an expression. It follows the same syntax as like top-level variable references, like myMacro or my-macro. However, it can also be written as a string literal, which is useful if the macro name contains characters that can't be specified in an identifier, for example <#macro "foo~bar">.... Note that this string literal does not expand interpolations (as "${foo}").
  • param1, param2, ...etc.: the name of the local variables store the parameter values (not expression), optionally followed by = and the default value (that's an expression). The default value can even be another parameter, for example <#macro section title label=title>. The parameter name uses the same syntax as like top-level variable references, so the same features and restrictions apply.
  • paramN, the last parameter may optionally has 3 trailing dots (...), which indicates that the macro takes a variable number of parameters and the parameters that doesn't match any other parameters will be collected in this last parameter (also called the catch-all parameter). When the macro is called with named parameters, paramN will be a hash containing all of the undeclared key/value pairs passed to the macro. When the macro is called using positional parameters, paramN will be the sequence of the extra parameter values. (Inside the macro, to find out which was the case, you can use myCatchAllParam?is_sequence.)

Therefore as you can see macro does not have any limitation to take N parameters.

This structure creates a macro variable (in the current namespace, if you know namespace feature). If you are new to macros and user-defined directives you should read the the tutorial about user-defined directives.

Macro variable stores a template fragment (called macro definition body) that can be used as user-defined directive. The variable also stores the name of allowed parameters to the user-defined directive. You must give value for all of those parameters when you use the variable as directive, except for parameters that has a default value. The default value will be used if and only if you don't give value for the parameter when you call the macro.

The variable will be created at the beginning of the template; it does not mater where the macro directive is placed in the template.

Example: Macro with parameters:

<#macro test foo bar baaz>
  Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<#-- call the macro: -->
<@test foo="a" bar="b" baaz=5*5-2/>

Output:

 Test text, and the params: a, b, 23

Example: Macro with parameters and default parameter values:

<#macro test foo bar="Bar" baaz=-1>
  Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<@test foo="a" bar="b" baaz=5*5-2/>
<@test foo="a" bar="b"/>
<@test foo="a" baaz=5*5-2/>
<@test foo="a"/>

Output:

  Test text, and the params: a, b, 23
  Test text, and the params: a, b, -1
  Test text, and the params: a, Bar, 23
  Test text, and the params: a, Bar, -1

However, about last part of your question there is an explanation:

The null reference is by design an error in FreeMarker. Defining a custom null value - which is a string - is not a good idea for the reasons you mention. The following constructs should be used instead:

  • Macro and function parameters can have a default value, so the callers can omit them
  • To check if a variable is null, you should use the ?? operator: <#if (name??)>
  • When you use a variable that can be null, you should use the ! operator to specify a default value: name!"No name"
  • To check if a sequence (or a string) is empty, use the ?has_content builtin: <#if (names?has_content)>

You can specify an empty sequence as default parameter value in a macro, and simply test whether it's empty.

Upvotes: 6

Related Questions