1#============================================================= -*-Perl-*-
2#
3# Template::Plugin
4#
5# DESCRIPTION
6#
7#   Module defining a base class for a plugin object which can be loaded
8#   and instantiated via the USE directive.
9#
10# AUTHOR
11#   Andy Wardley   <abw@wardley.org>
12#
13# COPYRIGHT
14#   Copyright (C) 1996-2007 Andy Wardley.  All Rights Reserved.
15#
16#   This module is free software; you can redistribute it an/or
17#   modify it under the same terms as Perl itself.
18#
19#============================================================================
20
21package Template::Plugin;
22
23use strict;
24use warnings;
25use base 'Template::Base';
26
27our $VERSION = 2.70;
28our $DEBUG   = 0 unless defined $DEBUG;
29our $ERROR   = '';
30our $AUTOLOAD;
31
32
33#========================================================================
34#                      -----  CLASS METHODS -----
35#========================================================================
36
37#------------------------------------------------------------------------
38# load()
39#
40# Class method called when the plugin module is first loaded.  It
41# returns the name of a class (by default, its own class) or a prototype
42# object which will be used to instantiate new objects.  The new()
43# method is then called against the class name (class method) or
44# prototype object (object method) to create a new instances of the
45# object.
46#------------------------------------------------------------------------
47
48sub load {
49    return $_[0];
50}
51
52
53#------------------------------------------------------------------------
54# new($context, $delegate, @params)
55#
56# Object constructor which is called by the Template::Context to
57# instantiate a new Plugin object.  This base class constructor is
58# used as a general mechanism to load and delegate to other Perl
59# modules.  The context is passed as the first parameter, followed by
60# a reference to a delegate object or the name of the module which
61# should be loaded and instantiated.  Any additional parameters passed
62# to the USE directive are forwarded to the new() constructor.
63#
64# A plugin object is returned which has an AUTOLOAD method to delegate
65# requests to the underlying object.
66#------------------------------------------------------------------------
67
68sub new {
69    my $class = shift;
70    bless {
71    }, $class;
72}
73
74sub old_new {
75    my ($class, $context, $delclass, @params) = @_;
76    my ($delegate, $delmod);
77
78    return $class->error("no context passed to $class constructor\n")
79        unless defined $context;
80
81    if (ref $delclass) {
82        # $delclass contains a reference to a delegate object
83        $delegate = $delclass;
84    }
85    else {
86        # delclass is the name of a module to load and instantiate
87        ($delmod = $delclass) =~ s|::|/|g;
88
89        eval {
90            require "$delmod.pm";
91            $delegate = $delclass->new(@params)
92                || die "failed to instantiate $delclass object\n";
93        };
94        return $class->error($@) if $@;
95    }
96
97    bless {
98        _CONTEXT  => $context,
99        _DELEGATE => $delegate,
100        _PARAMS   => \@params,
101    }, $class;
102}
103
104
105#------------------------------------------------------------------------
106# fail($error)
107#
108# Version 1 error reporting function, now replaced by error() inherited
109# from Template::Base.  Raises a "deprecated function" warning and then
110# calls error().
111#------------------------------------------------------------------------
112
113sub fail {
114    my $class = shift;
115    my ($pkg, $file, $line) = caller();
116    warn "Template::Plugin::fail() is deprecated at $file line $line.  Please use error()\n";
117    $class->error(@_);
118}
119
120
121#========================================================================
122#                      -----  OBJECT METHODS -----
123#========================================================================
124
125#------------------------------------------------------------------------
126# AUTOLOAD
127#
128# General catch-all method which delegates all calls to the _DELEGATE
129# object.
130#------------------------------------------------------------------------
131
132sub OLD_AUTOLOAD {
133    my $self     = shift;
134    my $method   = $AUTOLOAD;
135
136    $method =~ s/.*:://;
137    return if $method eq 'DESTROY';
138
139    if (ref $self eq 'HASH') {
140        my $delegate = $self->{ _DELEGATE } || return;
141        return $delegate->$method(@_);
142    }
143    my ($pkg, $file, $line) = caller();
144#    warn "no such '$method' method called on $self at $file line $line\n";
145    return undef;
146}
147
148
1491;
150
151__END__
152
153=head1 NAME
154
155Template::Plugin - Base class for Template Toolkit plugins
156
157=head1 SYNOPSIS
158
159    package MyOrg::Template::Plugin::MyPlugin;
160    use base qw( Template::Plugin );
161    use Template::Plugin;
162    use MyModule;
163
164    sub new {
165        my $class   = shift;
166        my $context = shift;
167        bless {
168            ...
169        }, $class;
170    }
171
172=head1 DESCRIPTION
173
174A "plugin" for the Template Toolkit is simply a Perl module which
175exists in a known package location (e.g. C<Template::Plugin::*>) and
176conforms to a regular standard, allowing it to be loaded and used
177automatically.
178
179The C<Template::Plugin> module defines a base class from which other
180plugin modules can be derived.  A plugin does not have to be derived
181from Template::Plugin but should at least conform to its object-oriented
182interface.
183
184It is recommended that you create plugins in your own package namespace
185to avoid conflict with toolkit plugins.  e.g.
186
187    package MyOrg::Template::Plugin::FooBar;
188
189Use the L<PLUGIN_BASE|Template::Manual::Config#PLUGIN_BASE> option to specify
190the namespace that you use. e.g.
191
192    use Template;
193    my $template = Template->new({
194        PLUGIN_BASE => 'MyOrg::Template::Plugin',
195    });
196
197=head1 METHODS
198
199The following methods form the basic interface between the Template
200Toolkit and plugin modules.
201
202=head2 load($context)
203
204This method is called by the Template Toolkit when the plugin module
205is first loaded.  It is called as a package method and thus implicitly
206receives the package name as the first parameter.  A reference to the
207L<Template::Context> object loading the plugin is also passed.  The
208default behaviour for the C<load()> method is to simply return the class
209name.  The calling context then uses this class name to call the C<new()>
210package method.
211
212    package MyPlugin;
213
214    sub load {               # called as MyPlugin->load($context)
215        my ($class, $context) = @_;
216        return $class;       # returns 'MyPlugin'
217    }
218
219=head2 new($context, @params)
220
221This method is called to instantiate a new plugin object for the C<USE>
222directive. It is called as a package method against the class name returned by
223L<load()>. A reference to the L<Template::Context> object creating the plugin
224is passed, along with any additional parameters specified in the C<USE>
225directive.
226
227    sub new {                # called as MyPlugin->new($context)
228        my ($class, $context, @params) = @_;
229        bless {
230            _CONTEXT => $context,
231        }, $class;           # returns blessed MyPlugin object
232    }
233
234=head2 error($error)
235
236This method, inherited from the L<Template::Base> module, is used for
237reporting and returning errors.   It can be called as a package method
238to set/return the C<$ERROR> package variable, or as an object method to
239set/return the object C<_ERROR> member.  When called with an argument, it
240sets the relevant variable and returns C<undef.>  When called without an
241argument, it returns the value of the variable.
242
243    package MyPlugin;
244    use base 'Template::Plugin';
245
246    sub new {
247        my ($class, $context, $dsn) = @_;
248
249        return $class->error('No data source specified')
250            unless $dsn;
251
252        bless {
253            _DSN => $dsn,
254        }, $class;
255    }
256
257    package main;
258
259    my $something = MyPlugin->new()
260        || die MyPlugin->error(), "\n";
261
262    $something->do_something()
263        || die $something->error(), "\n";
264
265=head1 DEEPER MAGIC
266
267The L<Template::Context> object that handles the loading and use of plugins
268calls the L<new()> and L<error()> methods against the package name returned by
269the L<load()> method. In pseudo-code terms looks something like this:
270
271    $class  = MyPlugin->load($context);       # returns 'MyPlugin'
272
273    $object = $class->new($context, @params)  # MyPlugin->new(...)
274        || die $class->error();               # MyPlugin->error()
275
276The L<load()> method may alterately return a blessed reference to an
277object instance.  In this case, L<new()> and L<error()> are then called as
278I<object> methods against that prototype instance.
279
280    package YourPlugin;
281
282    sub load {
283        my ($class, $context) = @_;
284        bless {
285            _CONTEXT => $context,
286        }, $class;
287    }
288
289    sub new {
290        my ($self, $context, @params) = @_;
291        return $self;
292    }
293
294In this example, we have implemented a 'Singleton' plugin.  One object
295gets created when L<load()> is called and this simply returns itself for
296each call to L<new().>
297
298Another implementation might require individual objects to be created
299for every call to L<new(),> but with each object sharing a reference to
300some other object to maintain cached data, database handles, etc.
301This pseudo-code example demonstrates the principle.
302
303    package MyServer;
304
305    sub load {
306        my ($class, $context) = @_;
307        bless {
308            _CONTEXT => $context,
309            _CACHE   => { },
310        }, $class;
311    }
312
313    sub new {
314        my ($self, $context, @params) = @_;
315        MyClient->new($self, @params);
316    }
317
318    sub add_to_cache   { ... }
319
320    sub get_from_cache { ... }
321
322    package MyClient;
323
324    sub new {
325        my ($class, $server, $blah) = @_;
326        bless {
327            _SERVER => $server,
328            _BLAH   => $blah,
329        }, $class;
330    }
331
332    sub get {
333        my $self = shift;
334        $self->{ _SERVER }->get_from_cache(@_);
335    }
336
337    sub put {
338        my $self = shift;
339        $self->{ _SERVER }->add_to_cache(@_);
340    }
341
342When the plugin is loaded, a C<MyServer> instance is created. The L<new()>
343method is called against this object which instantiates and returns a C<MyClient>
344object, primed to communicate with the creating C<MyServer>.
345
346=head1 AUTHOR
347
348Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/>
349
350=head1 COPYRIGHT
351
352Copyright (C) 1996-2007 Andy Wardley.  All Rights Reserved.
353
354This module is free software; you can redistribute it and/or
355modify it under the same terms as Perl itself.
356
357=head1 SEE ALSO
358
359L<Template>, L<Template::Plugins>, L<Template::Context>
360
361=cut
362
363# Local Variables:
364# mode: perl
365# perl-indent-level: 4
366# indent-tabs-mode: nil
367# End:
368#
369# vim: expandtab shiftwidth=4:
370