1#============================================================= -*-Perl-*-
2#
3# Template::Plugin::Assert
4#
5# DESCRIPTION
6#   Template Toolkit plugin module which allows you to assert that
7#   items fetchs from the stash are defined.
8#
9# AUTHOR
10#   Andy Wardley   <abw@wardley.org>
11#
12# COPYRIGHT
13#   Copyright (C) 2008 Andy Wardley.  All Rights Reserved.
14#
15#   This module is free software; you can redistribute it and/or
16#   modify it under the same terms as Perl itself.
17#
18#============================================================================
19
20package Template::Plugin::Assert;
21use base 'Template::Plugin';
22use strict;
23use warnings;
24use Template::Exception;
25
26our $VERSION   = 1.00;
27our $MONAD     = 'Template::Monad::Assert';
28our $EXCEPTION = 'Template::Exception';
29our $AUTOLOAD;
30
31sub load {
32    my $class   = shift;
33    my $context = shift;
34    my $stash   = $context->stash;
35    my $vmethod = sub {
36        $MONAD->new($stash, shift);
37    };
38
39    # define .assert vmethods for hash and list objects
40    $context->define_vmethod( hash => assert => $vmethod );
41    $context->define_vmethod( list => assert => $vmethod );
42
43    return $class;
44}
45
46sub new {
47    my ($class, $context, @args) = @_;
48    # create an assert plugin object which will handle simple variable
49    # lookups.
50    return bless { _CONTEXT => $context }, $class;
51}
52
53sub AUTOLOAD {
54    my ($self, @args) = @_;
55    my $item = $AUTOLOAD;
56    $item =~ s/.*:://;
57    return if $item eq 'DESTROY';
58
59    # lookup the named values
60    my $stash = $self->{ _CONTEXT }->stash;
61    my $value = $stash->dotop($stash, $item, \@args);
62
63    if (! defined $value) {
64        die $EXCEPTION->new( assert => "undefined value for $item" );
65    }
66    return $value;
67}
68
69
70package Template::Monad::Assert;
71
72our $EXCEPTION = 'Template::Exception';
73our $AUTOLOAD;
74
75sub new {
76    my ($class, $stash, $this) = @_;
77    bless [$stash, $this], $class;
78}
79
80sub AUTOLOAD {
81    my ($self, @args) = @_;
82    my ($stash, $this) = @$self;
83    my $item = $AUTOLOAD;
84    $item =~ s/.*:://;
85    return if $item eq 'DESTROY';
86
87    my $value = $stash->dotop($stash, $item, \@args);
88
89    if (! defined $value) {
90        die $EXCEPTION->new( assert => "undefined value for $item" );
91    }
92    return $value;
93}
94
951;
96
97__END__
98
99=head1 NAME
100
101Template::Plugin::Assert - trap undefined values
102
103=head1 SYNOPSIS
104
105    [% USE assert %]
106
107    # throws error if any undefined values are returned
108    [% object.assert.method %]
109    [% hash.assert.key %]
110    [% list.assert.item %]
111
112=head1 DESCRIPTION
113
114This plugin defines the C<assert> virtual method that can be used
115to automatically throw errors when undefined values are used.
116
117For example, consider this dotop:
118
119    [% user.name %]
120
121If C<user.name> is an undefined value then TT will silently ignore the
122fact and print nothing.  If you C<USE> the C<assert> plugin then you
123can add the C<assert> vmethod between the C<user> and C<name> elements,
124like so:
125
126    [% user.assert.name %]
127
128Now, if C<user.name> is an undefined value, an exception will be thrown:
129
130    assert error - undefined value for name
131
132=head1 AUTHOR
133
134Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/>
135
136=head1 COPYRIGHT
137
138Copyright (C) 2008 Andy Wardley.  All Rights Reserved.
139
140This module is free software; you can redistribute it and/or
141modify it under the same terms as Perl itself.
142
143=head1 SEE ALSO
144
145L<Template::Plugin>
146
147=cut
148
149# Local Variables:
150# mode: perl
151# perl-indent-level: 4
152# indent-tabs-mode: nil
153# End:
154#
155# vim: expandtab shiftwidth=4:
156