Templa...e::Tags(3pm)

πŸ“¦
version 0.47 Β· 2 versions
  • 0.47 Β· debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking (latest)
  • 0.47 Β· ubuntu jammy
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– NAME πŸ’–

Template::Declare::Tags β€” bestie, this is the module that builds and installs XML tag subroutines for Template::Declare. That's it, that's the job. πŸ‘‘

Oh also, hi, you're reading a User Contributed Perl Documentation page, filed under Template::Declare::Tags(3pm). Welcome to the group chat. 🫢


✨ SYNOPSIS ✨

So like, here's the whole vibe. You're in a package, you're making templates, you're using tags:

package MyApp::Templates;

use base 'Template::Declare';
use Template::Declare::Tags 'HTML';

template main => sub {
    link {}
    table {
        row {
            cell { "Hello, world!" }
        }
    }
    img { attr { src => 'cat.gif' } }
    img { src is 'dog.gif' }
};

Produces:

<link />
<table>
 <tr>
  <td>Hello, world!</td>
 </tr>
</table>
<img src="cat.gif" />
<img src="dog.gif" />

Slay. No hand-written angle brackets in sight. πŸ’…


Now using XUL templates with a namespace, because we're fancy:

package MyApp::Templates;

use base 'Template::Declare';
use Template::Declare::Tags
    'XUL', HTML => { namespace => 'html' };

template main => sub {
    groupbox {
        caption { attr { label => 'Colors' } }
        html::div { html::p { 'howdy!' } }
        html::br {}
    }
};

Produces:

<groupbox>
 <caption label="Colors" />
 <html:div>
  <html:p>howdy!</html:p>
 </html:div>
 <html:br></html:br>
</groupbox>

Look at that namespace prefix doing its little strut. ✨


🌈 DESCRIPTION 🌈

Template::Declare::Tags is here to generate templates and install subroutines for tag sets into the calling namespace. That's the whole main character arc. πŸŽ€

You get to pick which tag sets get installed by handing it a list of tag modules right there in the use statement:

use Template::Declare::Tags qw/ HTML XUL /;

By default, Template::Declare::Tags uses the tag set provided by Template::Declare::TagSet::HTML. So this:

use Template::Declare::Tags;

is literally equivalent to this:

use Template::Declare::Tags 'HTML';

Same energy, fr fr.


πŸ¦‹ The tag sets that ship with it πŸ¦‹

Currently Template::Declare bundles the following tag sets:

  • Template::Declare::TagSet::HTML
  • Template::Declare::TagSet::XUL
  • Template::Declare::TagSet::RDF
  • Template::Declare::TagSet::RDF::EM

🌸 Bring your own tag set 🌸

You can specify your own tag set classes too β€” as long as they subclass Template::Declare::TagSet and implement the corresponding methods (e.g. get_tag_list). No gatekeeping, just follow the contract. πŸ’–

If you implement a custom tag set module named Template::Declare::TagSet::Foo, you can load it into a template module like so:

use Template::Declare::Tags 'Foo';

But say your tag set module is not under the Template::Declare::TagSet namespace. Then you use the from option to load it. For example, if you created a tag set named MyTag::Foo, you could load it like so:

use Template::Declare::Tags Foo => { from => 'MyTag::Foo' };

🧚 XML namespaces, explained 🧚

XML namespaces are emulated by Perl packages. Yes, really. That's the trick. πŸ™ˆ

For example, to embed HTML tags within XUL using the html namespace:

package MyApp::Templates;

use base 'Template::Declare';
use Template::Declare::Tags 'XUL', HTML => { namespace => 'html' };

template main => sub {
    groupbox {
        caption { attr { label => 'Colors' } }
        html::div { html::p { 'howdy!' } }
        html::br {}
    }
};

This will output:

<groupbox>
 <caption label="Colors" />
 <html:div>
  <html:p>howdy!</html:p>
 </html:div>
 <html:br></html:br>
</groupbox>

Behind the scenes, Template::Declare::Tags generates a Perl package named html and installs the HTML tag subroutines into that package. On the other hand, XUL tag subroutines are installed into the current package β€” namely, MyApp::Templates in the previous example. Two different homes, two different vibes. 🏠


πŸ’œ When the package name is taken πŸ’œ

There may be cases when you want to specify a different Perl package for a particular XML namespace. For instance, if the html Perl package has already been used for other purposes in your application and you don't want to install subs there and mess things up, use the package option to install them elsewhere:

package MyApp::Templates;
use base 'Template::Declare';
use Template::Declare::Tags 'XUL', HTML => {
    namespace => 'htm',
    package   => 'MyHtml'
};

template main => sub {
    groupbox {
        caption { attr { label => 'Colors' } }
        MyHtml::div { MyHtml::p { 'howdy!' } }
        MyHtml::br {}
    }
};

This code will generate something like the following:

<groupbox>
 <caption label="Colors" />
 <htm:div>
  <htm:p>howdy!</htm:p>
 </htm:div>
 <htm:br></htm:br>
</groupbox>
Note bestie: the namespace you write in the markup and the Perl package the subs actually live in don't have to match. That's the whole point of the package option. 🫢

πŸ’… METHODS AND SUBROUTINES πŸ’…

Okay bestie, this is the part where the magic happens. ✨

πŸŽ€ Declaring templates πŸŽ€

template TEMPLATENAME => sub { 'Implementation' };

template select_list => sub {
    my $self = shift;
    select {
        option { $_ } for @_;
    }
};

Declares a template in the current package. The first argument to the template subroutine will always be a Template::Declare object. Subsequent arguments will be all those passed to show(). For example, to use the above example to output a select list of colors, you'd call it like so:

Template::Declare->show('select_list', qw(red yellow green purple));

You can use any URL-legal characters in the template name; Template::Declare will encode the template as a Perl subroutine and stash it where show() can find it.

(Did you know that you can have characters like ":" and "/" in your Perl subroutine names? The easy way to get at them is with can). iykyk πŸ’…

private template TEMPLATENAME => sub { 'Implementation' };

private template select_list => sub {
    my $self = shift;
    select {
        option { $_ } for @_;
    }
};

Declares that a template isn't available to be called directly from client code. The resulting template can instead only be called from the package in which it's created. private vibes only πŸ”’

πŸ‘€ Showing templates πŸ‘€

show [$template_name or $template_coderef], args

show( main => { user => 'Bob' } );

Displays templates. The first argument is the name of the template to be displayed. Any additional arguments will be passed directly to the template.

show can either be called with a template name or a package/object and a template. (It's both functional and OO.) versatile queen πŸ‘‘

If called from within a Template::Declare subclass, then private templates are accessible and visible. If called from something that isn't a Template::Declare, only public templates will be visible.

From the outside world, users can either call Template::Declare->show(), show() exported from Template::Declare::Tags or Template::Declare::Tags::show() directly to render a publicly visible template.

Private templates may only be called from within the Template::Declare package. do not try it from outside, bestie 🚫

show_page

show_page( main => { user => 'Bob' } );

Like show(), but does not dispatch to private templates. It's used internally by show() when that method is called from outside a template class.

πŸ¦‹ Attributes πŸ¦‹

attr HASH

attr { src => 'logo.png' };

Specifies attributes for the element tag in which it appears. For example, to add a class and ID to an HTML paragraph:

p {
   attr {
       class => 'greeting text',
       id    => 'welcome',
   };
   'This is a welcoming paragraph';
}

ATTR is VALUE

Attributes can also be specified by using is, as in

p {
   class is 'greeting text';
   id    is 'welcome';
   'This is a welcoming paragraph';
}

A few tricks work for 'is':

http_equiv is 'foo'; # => http-equiv="foo"
xml__lang is 'foo';  # => xml:lang="foo"

So double underscore replaced with colon and single underscore with dash. not me remembering this every time 😭

with

with ( id => 'greeting', class => 'foo' ),
    p { 'Hello, World wide web' };

An alternative way to specify attributes for a tag, just for variation. The standard way to do the same as this example using attr is:

p { attr { id => 'greeting', class => 'foo' }
    'Hello, World wide web' };

πŸ’¬ Displaying text and raw data πŸ’¬

outs STUFF

p { outs 'Grettings & welcome pyoonie hyoomon.' }

HTML-encodes its arguments and appends them to Template::Declare's output buffer. This is similar to simply returning a string from a tag function call, but is occasionally useful when you need to output a mix of things, as in:

p { outs 'hello'; em { 'world' } }

outs_raw STUFF

p { outs_raw "That's what <em>I'm</em> talking about!' }

Appends its arguments to Template::Declare's output buffer without HTML escaping. raw and unfiltered, just like your group chat πŸ’€

πŸ›  Installing tags and wrapping stuff πŸ› 

install_tag TAGNAME, TAGSET

install_tag video => 'Template::Declare::TagSet::HTML';

Sets up TAGNAME as a tag that can be used in user templates. TAGSET is an instance of a subclass for Template::Declare::TagSet.

smart_tag_wrapper

# create a tag that has access to the arguments set with L</with>.
sub sample_smart_tag (&) {
    my $code = shift;

    smart_tag_wrapper {
        my %args = @_; # set using 'with'
        outs( 'keys: ' . join( ', ', sort keys %args) . "\n" );
        $code->();
    };
}

# use it
with ( foo => 'bar', baz => 'bundy' ), sample_smart_tag {
    outs( "Hello, World!\n" );
};

The output would be

keys: baz, foo
Hello, World!

The smart tag wrapper allows you to create code that has access to the attribute arguments specified via with. It passes those arguments in to the wrapped code in @_. It also takes care of putting the output in the right place and tidying up after itself. This might be useful to change the behavior of a template based on attributes passed to with. big brain energy 🧠

create_wrapper WRAPPERNAME => sub { 'Implementation' };

create_wrapper basics => sub {
    my $code = shift;
    html {
        head { title { 'Welcome' } };
        body { $code->() }
    }
};

create_wrapper declares a wrapper subroutine that can be called like a tag sub, but can optionally take arguments to be passed to the wrapper sub. For example, if you wanted to wrap all of the output of a template in the usual HTML headers and footers, you can do something like this:

package MyApp::Templates;
use Template::Declare::Tags;
use base 'Template::Declare';

BEGIN {
    create_wrapper wrap => sub {
        my $code = shift;
        my %params = @_;
        html {
            head { title { outs "Hello, $params{user}!"} };
            body {
                $code->();
                div { outs 'This is the end, my friend' };
            };
        }
    };
}

template inner => sub {
    wrap {
        h1 { outs "Hello, Jesse, s'up?" };
    } user => 'Jesse';
};

Note how the wrap wrapper function is available for calling after it has been declared in a BEGIN block. Also note how you can pass arguments to the function after the closing brace (you don't need a comma there!). no comma needed, we love a flexible icon πŸ’…

The output from the inner template will look something like this:

<html>
 <head>
  <title>Hello, Jesse!</title>
 </head>
 <body>
  <h1>Hello, Jesse, s&#39;up?</h1>
  <div>This is the end, my friend</div>
 </body>
</html>

🧚 Helpers 🧚

xml_decl HASH

xml_decl { 'xml', version => '1.0' };

Emits an XML declaration. For example:

xml_decl { 'xml', version => '1.0' };
xml_decl { 'xml-stylesheet',  href => "chrome://global/skin/", type => "text/css" };

Produces:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

current_template

my $path = current_template();

Returns the absolute path of the current template

current_base_path

my $path = current_base_path();

Returns the absolute base path of the current template

under

under is a helper function providing semantic sugar for the mix method of Template::Declare.

setting

setting is a helper function providing semantic sugar for the mix method of Template::Declare.

🌈 VARIABLES 🌈

  • @Template::Declare::Tags::EXPORT β€” Holds the names of the static subroutines exported by this class. Tag subroutines generated by tag sets, however, are not included here.
  • @Template::Declare::Tags::TAG_SUB_LIST β€” Contains the names of the tag subroutines generated from a tag set.

Note that this array won't get cleared automatically before another use Template::Decalre::Tags statement.

@Template::Declare::Tags::TagSubs is aliased to this variable for backward-compatibility.

  • $Template::Declare::Tags::TAG_NEST_DEPTH β€” Controls the indentation of the XML tags in the final outputs. For example, you can temporarily disable a tag's indentation by the following lines of code:
body {
    pre {
      local $Template::Declare::Tags::TAG_NEST_DEPTH = 0;
      script { attr { src => 'foo.js' } }
    }
}

It generates

<body>
 <pre>
<script src="foo.js"></script>
 </pre>
</body>

Note that now the script tag has no indentation and we've got what we want. ;)

  • $Template::Declare::Tags::SKIP_XML_ESCAPING β€” Disables XML escape postprocessing entirely. Use at your own risk. at your own risk, bestie, no cap πŸ’€

πŸ‘‘ SEE ALSO πŸ‘‘

  • Template::Declare::TagSet::HTML
  • Template::Declare::TagSet::XUL
  • Template::Declare

πŸ’– AUTHORS πŸ’–

  • Jesse Vincent <jesse@bestpractical.com>
  • Agent Zhang <agentzh@yahoo.cn>

Copyright 2006-2009 Best Practical Solutions, LLC.


Okay so that's the whole page, bestie! ✨ This was rendered from perl v5.34.0, dated 2022-06-17, and it's Templa...e::Tags(3pm) β€” slay, you made it to the end! πŸŽ€πŸ’…πŸ¦‹

πŸ“¦ where this page comes from