1#================================================================= -*-Perl-*-
2#
3# Template::Namespace::Constants
4#
5# DESCRIPTION
6#   Plugin compiler module for performing constant folding at compile time
7#   on variables in a particular namespace.
8#
9# AUTHOR
10#   Andy Wardley   <abw@wardley.org>
11#
12# COPYRIGHT
13#   Copyright (C) 1996-2007 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::Namespace::Constants;
21
22use strict;
23use warnings;
24use base 'Template::Base';
25use Template::Config;
26use Template::Directive;
27use Template::Exception;
28
29our $VERSION = 1.27;
30our $DEBUG   = 0 unless defined $DEBUG;
31
32
33sub _init {
34    my ($self, $config) = @_;
35    $self->{ STASH } = Template::Config->stash($config)
36        || return $self->error(Template::Config->error());
37    return $self;
38}
39
40
41
42#------------------------------------------------------------------------
43# ident(\@ident)                                             foo.bar(baz)
44#------------------------------------------------------------------------
45
46sub ident {
47    my ($self, $ident) = @_;
48    my @save = @$ident;
49
50    # discard first node indicating constants namespace
51    splice(@$ident, 0, 2);
52
53    my $nelems = @$ident / 2;
54    my ($e, $result);
55    local $" = ', ';
56
57    print STDERR "constant ident [ @$ident ] " if $DEBUG;
58
59    foreach $e (0..$nelems-1) {
60        # node name must be a constant
61        unless ($ident->[$e * 2] =~ s/^'(.+)'$/$1/s) {
62            $self->DEBUG(" * deferred (non-constant item: ", $ident->[$e * 2], ")\n")
63                if $DEBUG;
64            return Template::Directive->ident(\@save);
65        }
66
67        # if args is non-zero then it must be eval'ed
68        if ($ident->[$e * 2 + 1]) {
69            my $args = $ident->[$e * 2 + 1];
70            my $comp = eval "$args";
71            if ($@) {
72                $self->DEBUG(" * deferred (non-constant args: $args)\n") if $DEBUG;
73                return Template::Directive->ident(\@save);
74            }
75            $self->DEBUG("($args) ") if $comp && $DEBUG;
76            $ident->[$e * 2 + 1] = $comp;
77        }
78    }
79
80
81    $result = $self->{ STASH }->get($ident);
82
83    if (! length $result || ref $result) {
84        my $reason = length $result ? 'reference' : 'no result';
85        $self->DEBUG(" * deferred ($reason)\n") if $DEBUG;
86        return Template::Directive->ident(\@save);
87    }
88
89    $result =~ s/'/\\'/g;
90
91    $self->DEBUG(" * resolved => '$result'\n") if $DEBUG;
92
93    return "'$result'";
94}
95
961;
97
98__END__
99
100=head1 NAME
101
102Template::Namespace::Constants - Compile time constant folding
103
104=head1 SYNOPSIS
105
106    # easy way to define constants
107    use Template;
108
109    my $tt = Template->new({
110        CONSTANTS => {
111            pi => 3.14,
112            e  => 2.718,
113        },
114    });
115
116    # nitty-gritty, hands-dirty way
117    use Template::Namespace::Constants;
118
119    my $tt = Template->new({
120        NAMESPACE => {
121            constants => Template::Namespace::Constants->new({
122                pi => 3.14,
123                e  => 2.718,
124            },
125        },
126    });
127
128=head1 DESCRIPTION
129
130The C<Template::Namespace::Constants> module implements a namespace handler
131which is plugged into the C<Template::Directive> compiler module.  This then
132performs compile time constant folding of variables in a particular namespace.
133
134=head1 METHODS
135
136=head2 new(\%constants)
137
138The new() constructor method creates and returns a reference to a new
139Template::Namespace::Constants object.  This creates an internal stash
140to store the constant variable definitions passed as arguments.
141
142    my $handler = Template::Namespace::Constants->new({
143        pi => 3.14,
144        e  => 2.718,
145    });
146
147=head2 ident(\@ident)
148
149Method called to resolve a variable identifier into a compiled form.  In this
150case, the method fetches the corresponding constant value from its internal
151stash and returns it.
152
153=head1 AUTHOR
154
155Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/>
156
157=head1 COPYRIGHT
158
159Copyright (C) 1996-2007 Andy Wardley.  All Rights Reserved.
160
161This module is free software; you can redistribute it and/or
162modify it under the same terms as Perl itself.
163
164=head1 SEE ALSO
165
166L<Template::Directive>
167
168=cut
169
170# Local Variables:
171# mode: perl
172# perl-indent-level: 4
173# indent-tabs-mode: nil
174# End:
175#
176# vim: expandtab shiftwidth=4:
177