NAME

Template::Plugin::Heritable - OO dispatching and inheritance for templates

SYNOPSIS

[% USE Heritable %]

[%# searches providers for a "view" template method on
    class (which should be a metamodel object, eg
    someobj.meta in Perl 6) %]
[% Heritable.include(class, "view", { self = object }) %]

[%# return list of paths it would look %]
[% paths = Heritable.dispatch_paths(class, "view") %]

[%# if you don't have the class of the object handy, then
    use 'invoke' instead %]
[% Heritable.invoke(object, "method", { self = object } %]

[%# call the next method in the inheritance tree from
    inside a template method %]
[% next_template() %]

DESCRIPTION

Template::Plugin::Heritable provides support for selecting an appropriate template based on the class of an object. It is also possible to call the next template in the inheritance heirarchy/chain.

This provides a form of inheritance for template display.

The core of this is the template dispatch mechanism, which deals in terms of a suitable metamodel class. The module currently deals in the following metamodels; but no doubt you could fool it with modules which encapsulate other metamodels (such as Perl 5, NEXT, Class::C3, DBIx::Class::Schema, etc) with minimal effort by conforming to one of their APIs.

Eventually, no doubt these will be plugins.

T2::Class

T2 is the Tangram MetaModel that also drives Class::Tangram

Perl6::MetaModel

This module implements the Perl6 MetaModel in terms of Perl 5 objects, and can be found in pugs. Currently TODO as this is a first release, but the intention is that this module will be the second primary supported metamodel.

CONSTRUCTION

Basic use:

[% USE Heritable %]

Specifying all options:

[% USE Heritable({ prefix = "mypath",
                   suffix = ".tt",
                   class2path = somefunc,
                   class_attr2path = somefunc,
                   schema = myschema
                 }) %]

Here all dispatch paths returned by Heritable will be prepended with mypath/. Also, a custom method is specified to convert from "Foo::Bar"-style class names to a Template::Provider path.

There is also a schema object; this object is responsible for converting objects to classes.

Normally, you wouldn't specify most of this this - and indeed there is the issue there that this configuration information perhaps doesn't belong every place you make a Heritable object dispatch.

For this reason, it is recommended that you have a single template for object dispatching, and to pass through self appropriately.

[% PROCESS invoke
     object = SomeObject
     method = "foo"
%]

the invoke template might look like:

[% USE Heritable({ suffix = ".tt"
                 });
   Heritable.include(object.meta, method, { self = object }) -%]

METHODS

.dispatch_paths

.include

.invoke

[% paths = Heritable.dispatch_paths( what, "name" ) %]

[% Heritable.include( what, "name", { ... } ) %]
[% Heritable.invoke( object, "name", { ... } ) %]

.dispatch_paths returns a list of dispatch paths for what. what is a metamodel object (see DESCRIPTION).

.include calls the first one that actually exists in the available template providers. It throws a (trappable) not found error if it was not found.

.invoke assumes that the metamodel object is either available as object.meta or via $schema->class(ref $object). Convenient modules to make this Just Work™ with standard Perl 5 and 6 objects/classes are yet to be written, but for T2 this should work fine.

To figure out which template should be called to perform a function, the class names are turned into Template::Provider paths, with the template to call ("view" in the example in the synopsis) appended to them.

For example, if the "class" object in the synopsis represents the "Foo::Bar" class, which has superclass "Foo", the following locations would be searched for a template (assuming you specified TEMPLATE_EXTENSION = ".tt" during your Template object construction):

foo/bar/view.tt
foo/view.tt
object/view.tt

It is also possible to dispatch based on attribute or association types, by calling "attribute methods". In this case, the dispatch order also includes templates for the types of the attribute or association.

So, if you were using T2 classes and wrote:

[% Heritable.include(class.attribute("baz"), "show") %]

Then the first of these templates found would be called (assuming baz is a property of the Foo class, of type set):

foo/baz/show.tt
object/baz/show.tt
foo/types/set/show.tt
object/types/set/show.tt

Note that foo/bar/baz/show.tt was not searched for, even though class is actually Foo::Bar. If you wanted to do that, you should use a 'multiple invocant' include:

[% Heritable.include([class, class.attribute("baz")],
                     "show", { ... }) %]

or simply

[% Heritable.include([class, "baz"], "show", { ... }) %]

Either of these would then search for:

foo/bar/baz/show.tt
foo/baz/show.tt
object/baz/show.tt
foo/bar/types/set/show.tt
foo/types/set/show.tt
object/types/set/show.tt

In principle, if an attribute's type is itself a type with an inheritance chain, that those extra templates will also be added to the list of checked template locations. This will apply later in later T2 versions and/or the Perl 6 MetaModel, when an actual type heirarchy is in place.

DEFINED VARIABLES

next_template

These methods let you find the next template to display in the inheritance chain.

The next template is [% next_template %]

[% next_template.include({ ... }) %]

Note that if there is no next template you will get a nasty error.

SEE ALSO

T2, Template.

AUTHOR

Sam Vilain, <samv@cpan.org>

LICENSE

Copyright (c) 2005, Catalyst IT (NZ) Ltd. This program is free software; you may use it and/or redistribute it under the same terms as Perl itself.

2 POD Errors

The following errors were encountered while parsing the POD:

Around line 65:

You forgot a '=back' before '=head1'

Around line 140:

Non-ASCII character seen before =encoding in 'Work™'. Assuming UTF-8