The <al-macro> tag is used to define a macro.
Executing the macro registers the macro with the execution context via the register_macro() method using the name in the name attribute.
Note that the execution of the macro content is deferred until later when the macro is expanded via the <al-expand> tag. This means that executing a macro definition produces no output. Output is produced only when the macro is executed.
>>> import albatross >>> ctx = albatross.SimpleContext('.') >>> albatross.Template(ctx, '<magic>', ''' ... <al-macro name="noargs"> ... Will be executed when macro is expanded. ... </al-macro> ... ''').to_html(ctx) >>> ctx.flush_content() >>> albatross.Template(ctx, '<magic>', ''' ... <al-expand name="noargs"/> ... ''').to_html(ctx) >>> ctx.flush_content() Will be executed when macro is expanded.
The deferred execution also means that you can include content that only works within the context of the <al-expand> tag.
>>> import albatross >>> ctx = albatross.SimpleContext('.') >>> albatross.Template(ctx, '<magic>', ''' ... <al-macro name="oops"> ... <al-value expr="oops"> ... </al-macro> ... ''').to_html(ctx) >>> ctx.flush_content() >>> templ = albatross.Template(ctx, '<magic>', ''' ... <al-expand name="oops"/> ... ''') >>> try: ... templ.to_html(ctx) ... ctx.flush_content() ... except NameError, e: ... print e ... name 'oops' is not defined >>> ctx.locals.oops = 'there is now' >>> templ.to_html(ctx) >>> ctx.flush_content() there is now
In the above example the content of the macro makes reference to a oops that is not defined in the execution context when the macro was defined.
The <al-usearg> tag is used in the macro definition to define where content enclosed by the <al-expand> tag should be placed when the macro is expanded. All content enclosed by the <al-expand> tag is passed to the macro as the unnamed argument. The unnamed argument is retrieved in the macro definition by using an <al-usearg> tag without specifying a name attribute. When a macro expects only one argument it is best to use this mechanism.
>>> import albatross >>> ctx = albatross.SimpleContext('.') >>> albatross.Template(ctx, '<magic>', ''' ... <al-macro name="double"> ... 1. <al-usearg> ... 2. <al-usearg> ... </al-macro> ... ''').to_html(ctx) >>> ctx.flush_content() >>> albatross.Template(ctx, '<magic>', ''' ... <al-expand name="double"> ... spam ... </al-expand>''').to_html(ctx) >>> ctx.flush_content() 1. spam 2. spam
Inside a macro definition you can use as yet undefined macros.
>>> import albatross >>> ctx = albatross.SimpleContext('.') >>> albatross.Template(ctx, '<magic>', ''' ... <al-macro name="bold-red"> ... <font color="red">more <al-expand name="bold"><al-usearg></al-expand> please</font> ... <font color="red"><al-expand name="bold">more <al-usearg> please</al-expand></font> ... </al-macro> ... ... <al-macro name="bold"> ... <b><al-usearg></b></al-macro> ... ''').to_html(ctx) >>> ctx.flush_content() >>> albatross.Template(ctx, '<magic>', ''' ... <al-expand name="bold-red">spam</al-expand> ... ''').to_html(ctx) >>> ctx.flush_content() <font color="red">more <b>spam</b> please</font> <font color="red"><b>more spam please</b></font>
Care must by taken to ensure that you do not make circular macro references else you will cause a stack overflow.
You can also pass macro expansions as arguments to other macros.
>>> import albatross >>> ctx = albatross.SimpleContext('.') >>> albatross.Template(ctx, '<magic>', ''' ... <al-macro name="red"> ... <font color="red"><al-usearg></font> ... </al-macro> ... ... <al-macro name="bold"><b><al-usearg></b></al-macro> ... ''').to_html(ctx) >>> ctx.flush_content() >>> albatross.Template(ctx, '<magic>', ''' ... <al-expand name="red">more <al-expand name="bold">spam</al-expand> please</al-expand> ... <al-expand name="red"><al-expand name="bold">more spam please</al-expand></al-expand> ... ''').to_html(ctx) >>> ctx.flush_content() <font color="red">more <b>spam</b> please</font> <font color="red"><b>more spam please</b></font>
All arguments to macros are executed before they are passed to the macro. This means that there are no side effects for using arguments more than once inside a macro.
>>> import albatross >>> ctx = albatross.SimpleContext('.') >>> albatross.Template(ctx, '<magic>', ''' ... <al-macro name="yummy"> ... <al-for iter="i" expr="range(3)"> ... <al-usearg whitespace="indent"> ... </al-for> ... </al-macro> ... ''').to_html(ctx) >>> ctx.locals.food = 'spam' >>> albatross.Template(ctx, '<magic>', ''' ... <al-expand name="yummy"> ... <al-exec expr="food = food + '!'"> ... <al-value expr="food"> ... </al-expand whitespace> ... ''').to_html(ctx) >>> ctx.flush_content() spam! spam!! spam!!!
Macros can be defined to accept multiple arguments. The name attribute of the <al-usearg> tag is used to retrieve named arguments. When invoking a macro that accepts named arguments the <al-setarg> tag and name attribute is used to define the content for each named argument.
>>> import albatross >>> ctx = albatross.SimpleContext('.') >>> albatross.Template(ctx, '<magic>', ''' ... <al-macro name="namedargs" whitespace="indent"> ... The unnamed arg (<al-usearg>) still works, ... but we can also include named arguments (<al-usearg name="arg1">) ... </al-macro> ... ''').to_html(ctx) >>> albatross.Template(ctx, '<magic>', ''' ... <al-expand name="namedargs"> ... unnamed arg<al-setarg name="arg1"> ... named arg: arg1</al-setarg> ... </al-expand> ... ''').to_html(ctx) >>> ctx.flush_content() The unnamed arg (unnamed arg) still works, but we can also include named arguments (named arg: arg1)