Macro Command

The Macro command allows a template section, containing data and/or PTPScript code, to be defined as a macro. In this context, a macro is essentially a sub-template, and behaves very much like a function. By default, it has its own Variable "scope" - it cannot access Variables that are available in the main template (PTPScript 4.1 added the ability to define macro scope). Any Variables that are created or modified within the macro will only affect the data inside that macro, unless the scope is changed.

When a Macro command is first encountered, the macro data is not displayed, but is instead stored for later use. Parameters can be defined, so that values can be passed to the macro. When required, the macro can be displayed by calling it in the same way as a function. This means that the output of a macro can be used in an expression in the same way as that of a function.

There are two commands in the Macro family - Macro and EndMacro. Each Macro command has to have a corresponding EndMacro command.

The Macro command consists of the command, followed by the macro name, and then the names of any parameters, contained within parentheses and separated by commas. The scope can also be changed. The EndMacro command does not use an expression, and so will ignore any expression given.

For example:

{ macro Greeting ( Name, MealOfTheDay ) }…
Hi there, {Name}! Would you like {MealOfTheDay}?
{ endmacro }{ Greeting ("Jim", "fish and chips") }

Hi there, Jim! Would you like fish and chips?

Macro names are case-insensitive, just like functions.

Macro definitions and calls can be nested indefinitely within other Macro definitions, and within other command structures, however each macro is fully enclosed and cannot detect or affect anything else unless its scope is altered. All Macro definitions are global in scope - that is, they can be called from anywhere, no matter where they were defined. However, if defined within a macro, the containing macro has to be called before the definition will be processed.

Macros can be re-declared without error. The latest definition will apply for all code following it.

Checking for macros

Sometimes it may be necessary to check for a macro, and in such a situation, type checking should be used to determine whether the macro has been defined.

For example:

{ if "Greeting" is a macro }{   Greeting ("Jim", "fish and chips") }
{ endif }

Resolving ambiguity

Because macros are called in the same way as functions, a macro could be declared with the same name as a function. In this case, the function will always be called, not the macro.

Scope

The scope of each macro can be set as desired, at declaration time. The "scope" is the behaviour of Variables present in the macro, relative to the environment outside the macro. There are three kinds of scope, with various keywords for each, to provide flexibility to cater for different tastes.

Scope Type Keywords Description
shared inherited mutable same All Variables will be available to the macro, and changes will be reflected in the original environment
clean fresh separate new The macro will not inherit any Variables from the original environment, and vice versa (default)
clone preserved immutable copy The macro will inherit all Variables from the original environment, but changes will not affect the original environment

The scope of each macro can be set by using the syntax macro (parameters...) as scope.

For example:

{ Name = "Jim" }
{ macro Greeting ( MealOfTheDay ) as shared }…
Hi there, {Name}! Would you like {MealOfTheDay}?
{ endmacro }{ Greeting ("fish and chips") }

Scope type keywords are case-insensitive.

Macro scope can only be changed from PTPScript 4.1 onwards. PTPScript 4.0 anly allows macros to have clean scope - the default in PTPScript 4.1.

Note that templates compiled by PTPScript 4.0 are incompatible with PTPScript 4.1 if they contain macros, and vice-versa. This means that cached templates need to be cleared when moving between versions (this is advisable in any case).

Note that when macro scope is set to shared, the parameters passed to the macro will themselves become part of the global environment. This defeats the point of macros, in many ways, as one of the benefits of using macros is encapsulation. If shared variables are needed, using a section may be more appropriate.