NAME

Template::Caribou::Manual - User Guide to Template::Caribou

VERSION

version 1.2.2

SYNOPSIS

package MyTemplate;

use Template::Caribou;

use Template::Caribou::Tags::HTML qw/ :all /;

has name => ( is => 'ro' );

template page => sub {
    html { 
        head { title { 'Example' } };
        show( 'body' );
    }
};

template body => sub {
    my $self = shift;

    body { 
        h1 { 'howdie ' . $self->name } 
    }
};

package main;

my $template = MyTemplate->new( name => 'Yanick' );
print $template->render('page');

DESCRIPTION

This document describes how to use the Caribou templating system.

The Caribou system is made of two major components: the templating role itself (Template::Caribou) and the tag libraries, (Template::Caribou::Tags, Template::Caribou::Tags::HTML::Extended, etc).

Template::Caribou::Role

The Template::Caribou::Role role behaves like any other Moose role. Typically, a class will consume it via

package MyTemplate;

use Moose;

with 'Template::Caribou';

...;

The use Template::Caribou line is required to imports three keywords into the class's namespace: template, show and attr.

template $name => sub { ... }

template is used to add a template to the class. Its first argument is the name of the template, and the second the coderef that will be executed to generate the template's output.

At its core, the template coderef is straight Perl code that uses a simple rule to generate its output. It is given two output channels, STDOUT and ::RAW; everything passed to ::RAW is printed verbatim, and everything printed to STDOUT is HTML-escaped.

template 'greetings' => sub {
    print       "<h1>Hello world</h1>";    
    print ::RAW "<h2>Lovely day, isn't?</h2>";    
};

# later on...
print $bou->render( 'greetings' );

# will output
#   &lt;h1>Hello world&lt/h1><h2>Lovely day, isn't?</h2>

The rendering rule has one one special case: if the template didn't print anything, its return value will be taken as its output.

template 'clock' => sub {
    print "current time: " . localtime;    
};

# equivalent to

template 'clock' => sub {
    "current time: " . localtime;    
};

render()

A Caribou object processes its templates via the method render(). Templates are passed the object, as well as any additional arguments.

template 'greetings' => sub {
    my( $self, $name ) = @_;
    "Howdie " . $name;
};

# later on...
print $bou->render( 'greetings' => 'Yanick' );

# prints 'Howdie Yanick'

While it's not necessary, I personally like to define the templates with Perl's new signatures, which makes things a little cleaner:

# equivalent to code above
use experimental 'signatures';

template 'greetings' => sub($self, $name) {
     "Howdie " . $name;
 };

And since we are talking about template objects, the arguments to render() can often be modified to be attributes.

has name => (
    is  => 'ro',
    isa => 'Str',
    required => 1,
);

template 'greetings' => sub($self) {
     "Howdie " . $self->name;
};

# and then later on...
my $bou = MyGreeter->new( name => 'Yanick' );

print $bou->render( 'greetings' );

Instead of a template name, render() can also be given a coderef as its first argument, in which case it'll take it as an anonymous template. Which can be useful for debugging or quick template hacking.

package MyGreeter;

use Moose;
with 'Template::Caribou';

print __PACKAGE__->new->render(sub { "Hi there!" });

show()

While it is perfectly possible to call sub-templates via render(), the resulting syntax looks a little clunky:

template head => sub { '<head>..</head>' };
template head => sub { '<body>..</body>' };

template page => sub($self) {
    print ::RAW $self->render( 'head' );
    print ::RAW $self->render( 'body' );
};

Hence show(), which provides a shortcut for the same behavior:

# equivalent to the code above

template head => sub { '<head>..</head>' };
template head => sub { '<body>..</body>' };

template page => sub($self) {
    show('head');
    show('body');
};

attr()

So far, beside the automatic HTML escaping that STDOUT provides, Caribou doesn't provides any tool specific to tag generation. This is where the tag libraries come in. attr() is actually a keyword generated by Template::Caribou::Tags, but as it is used in most cases, it is part of the Template::Caribou exports for convenience.

THE TAG LIBRARIES

Template::Caribou::Tags::HTML

The base library that you are most likely to use is Template::Caribou::Tags::HTML, which exports functions mapping to the most common HTML tags.

# exports the helper functions for the tags 'html', 'body' and 'p'
use Template::Caribou::Tags::HTML qw/ html body p /;

# get'em all
use Template::Caribou::Tags::HTML qw/ :all /;

All functions are called with a coderef, which is treated as an inner template. When called within a template, the functions will output their corresponding tag and the result of the inner template:

template inner => sub {
    p { 
        print "Hello world";
    };
};

# will output '<p>Hello world</p>';

# equivalent, shorter form:
template inner => sub {
    p { "Hello world" };
};

Tags, of course, can be used within one another:

template page => sub {
    html {
        head { title { "Hello world" } };
        body { 
            h1 { "Howdie!" }; 
            p { "Beautiful day, isn't?" }; 
        };
    };
};

Attributes for the tag are set via %_ or the 'attr()' function, which can appear anywhere within the inner template.

use Template::Caribou::Tags::HTML qw/ div /;

template inner => sub {
    div {
        $_{id} = 'inner',
        $_{class}{'main-div'} = 1;

        div {
            "some inner div";
        };

    };
};

# or, equivalently

template inner => sub {
    div {
        attr id    => 'inner',
             class => 'main-div';

        div {
            "some inner div";
        };

    };
};

# will output
#   <div id="inner" class="main-div"><div>some inner div</div></div>

%_ takes attribute name/value pairs. If the value is a hashref, then the final attribute value will be the concatenated list of the keys with true values. Which is mostly useful for the class attribute, where you can toggle the different classes.

Template::Caribou::Tags

This library is useful to craft your own tags and provide semantic shortcuts.

Semantic shortcuts via 'mytag'

New semantic-based shortcut tags can easily be generated via the mytag export directive.

use Template::Caribou::Tags 
    mytag => {
        -as   => 'widget',
        class => 'thingy',
        name  => 'div',
    };

template body => sub {
    widget { '...' };
};

# will output
#   <div class="thingy">...</div>

Note that the tag name does default to 'div', so the code above be further simplified as

use Template::Caribou::Tags 
    mytag => { -as => 'widget', class => 'thingy', };

Creating New Tags

The module can also export render_tag, which can be used to create new tags. For example, a 'favicon' tag can be created via

sub favicon($) {
    my $url = shift;

    render_tag( 'link', sub {
        attr rel => 'shortcut icon', href => $url;
    } );
}

and later can be used like any other tag:

print $bou->render(sub{
    favicon '/logo.png';
});

# will output
<link rel="shortcut icon" href="/logo.png" />

More documentation will come soon. In the meantime, check out the source code of the different tag libraries for examples.

Template::Caribou::Tags::HTML::Extended

This library provides optimized shortcuts for oft-used patterns. For example, it provides anchor, which is a stream-lined a:

anchor 'http://foo.com/' => 'the site';

# same as
a { attr href => 'http://foo.com'; 'the site' };

anchor 'http://bar.com' => sub {
    b{ "the other site" };
};

# same as
a { attr href => 'http://bar.com'; 
    b { "the other site" }; 
};

OTHER PIECES

Once you get started on bigger sets of templates, you'll probably want to have one file for each individual template. Template::Caribou::Files is there just for that. This role can be given directories where it'll locate individual templates and incorporate them in the main class.

AUTHOR

Yanick Champoux <yanick@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2023 by Yanick Champoux.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.