File Coverage

blib/lib/Template/TAL/Language/TALES.pm
Criterion Covered Total %
statement 45 45 100.0
branch 11 12 91.6
condition 9 12 75.0
subroutine 9 9 100.0
pod 1 3 33.3
total 75 81 92.5


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Template::TAL::Language::TALES - methods to parse TALES strings
4              
5             =head1 SYNOPSIS
6              
7             my $value = Template::TAL::Language::TALES->process_tales_path(
8             "/foo/bar",
9             { foo => { bar => "2" } },
10             );
11            
12             =head1 DESCRIPTION
13              
14             TALES is the recommended syntax for TAL expressions. It is an
15             extensible syntax that allows you to define any number of expression
16             types and use them together. See
17             http://www.zope.org/Wikis/DevSite/Projects/ZPT/TALES
18             for the spec.
19              
20             This module provides the parser hooks for a TALES implementation, and it is
21             called by Template::TAL::ValueParser.
22              
23             =cut
24              
25             package Template::TAL::Language::TALES;
26 1     1   594 use warnings;
  1         2  
  1         30  
27 1     1   6 use strict;
  1         2  
  1         31  
28 1     1   6 use base qw( Template::TAL::Language );
  1         2  
  1         1049  
29 1     1   7 use Scalar::Util qw( blessed );
  1         2  
  1         122  
30 1     1   5 use Carp qw( croak );
  1         2  
  1         306  
31              
32             =over
33              
34             =item process_tales_path( path, contexts, plugins )
35              
36             follows the path into the passed contexts. Will return the value of the
37             key if it is found in any of the contexts, searching first to last, or
38             undef if not. Path is something like
39              
40             /foo/bar/0/baz/narf
41              
42             and this will map to (depending on the object types in the context)
43              
44             $context->{foo}->bar()->[0]->{baz}->narf();
45              
46             =cut
47              
48             # TODO - it would be very nice to distinguish between 'key not found' and
49             # 'key value is undef'.
50              
51             sub process_tales_path {
52 21     21 1 49 my ($class, $path, $contexts, $plugins) = @_;
53 21         72 my @components = split(/\s*\|\s*/, $path);
54              
55 21         92 CONTEXT: for my $context (@$contexts) {
56              
57 21         25 COMPONENT: for my $component (@components) {
58 22         30 $component =~ s!^/!!;
59 22         51 my @atoms = split(m!/!, $component);
60 22         31 my $local = $context;
61 22         48 for my $atom (@atoms) {
62             # TODO - unlike Template Toolkit, we use 'can' here, as opposed to
63             # just trying it and looking for errors. Is this the right thing?
64 32 100 100     450 if (ref($local) and blessed($local) and $local->can($atom) ) {
    100 66        
    100 66        
      66        
65 1         6 $local = $local->$atom();
66             # TODO what about objects that support hash de-referencing or something?
67             } elsif (UNIVERSAL::isa($local, "HASH") or
68             overload::Method($local,'%{}')) {
69 24         115 $local = $local->{ $atom };
70             } elsif (UNIVERSAL::isa($local, "ARRAY") or
71             overload::Method($local,'@{}')) {
72 1     1   9 no warnings 'numeric';
  1         2  
  1         360  
73 6 100       136 if ($atom eq int($atom)) {
74 5         16 $local = $local->[ $atom ];
75             } else {
76             #warn "$atom is not an array index\n";
77 1         4 $local = undef;
78             }
79             } else {
80             # TODO optional death here?
81             #warn "Can't walk path '$atom' into object '$local'\n";
82 1         3985 $local = undef;
83             }
84              
85             } # atom
86 22 100       142 return $local if defined($local);
87              
88             } # component
89              
90             } # context
91 4         21 return undef; # give up.
92             }
93              
94             =item process_string( string, contexts, plugins )
95              
96             interprets 'string' as a string, and returns it. This includes variable
97             interpolation from the contexts, for instance, the string
98              
99             This is my ${weapon}!
100              
101             Where the context is
102              
103             { weapon => "boomstick' }
104              
105             will be interpolated properly. Both ${this} and $this style of placeholder
106             will be interpolated.
107              
108             =cut
109              
110             # TODO if $foo = '$bar' and $bar = 3, then '${foo}' will be interpolated
111             # to '3', not '$bar'. Tricky? need more regexp-fu
112             sub process_tales_string {
113 6     6 0 12 my ($class, $string, $contexts, $plugins) = @_;
114 6 50       15 return unless defined($string);
115 6         18 $string =~ s/\$\{(.*?)\}/Template::TAL::ValueParser->value($1, $contexts, $plugins)/eg;
  2         7  
116 6         14 $string =~ s/\$(\w*)/Template::TAL::ValueParser->value($1, $contexts, $plugins)/eg;
  1         5  
117 6         53 return $string;
118             }
119              
120             =item process_not( value, contexts, plugins )
121              
122             Evaluates 'value' as a TALES string in the context, and return the
123             boolean value that is its opposite. eg
124              
125             not:string:0 - true
126             not:/foo/bar - the opposite of /foo/bar
127              
128             =cut
129              
130             sub process_tales_not {
131 2     2 0 5 my ($class, $string, $contexts, $plugins) = @_;
132 2         12 my $value = Template::TAL::ValueParser->value($string, $contexts, $plugins);
133 2         12 return !$value;
134             }
135              
136             =back
137              
138             =head1 COPYRIGHT
139              
140             Written by Tom Insam, Copyright 2005 Fotango Ltd. All Rights Reserved
141              
142             This program is free software; you can redistribute
143             it and/or modify it under the same terms as Perl itself.
144              
145             =cut
146              
147              
148              
149             1;