File Coverage

blib/lib/Decl/NodalValuator.pm
Criterion Covered Total %
statement 16 45 35.5
branch 0 16 0.0
condition 0 6 0.0
subroutine 6 8 75.0
pod 3 3 100.0
total 25 78 32.0


line stmt bran cond sub pod time code
1             package Decl::NodalValuator;
2            
3 12     12   80 use warnings;
  12         23  
  12         338  
4 12     12   538 use strict;
  12         1102  
  12         447  
5 12     12   66 use Decl::Node;
  12         24  
  12         217  
6 12     12   10776 use Decl::Template;
  12         41  
  12         419  
7 12     12   99 use Data::Dumper;
  12         26  
  12         7328  
8            
9            
10             =head1 NAME
11            
12             Decl::NodalValuator - implements the template valuator used in a nodal environment.
13            
14             =head1 VERSION
15            
16             Version 0.01
17            
18             =cut
19            
20             our $VERSION = '0.01';
21            
22            
23             =head1 SYNOPSIS
24            
25             This isn't really an object module; it's just a place to instantiate a template engine. Templates are defined in L, and the main
26             L class instantiates a souped-up version of that vanilla engine that can do some fancy Decl-specific stuff.
27            
28             =head2 instantiate()
29            
30             Instantiates a template engine with a nodal valuator. TODO: implement and use an error if a field is not filled in during expression.
31            
32             =cut
33            
34             sub instantiate {
35 12     12 1 156 Decl::Template->new(
36             valuator => \&valuator,
37             leave_misses => 0,
38             spanners => { foreach => \&do_foreach,
39             select => \&do_foreach, },
40             );
41             }
42            
43             =head2 valuator($name, $node)
44            
45             Like all template valuators, this takes a name and a value context. By default, the value context is a Node (duh), but we can also pass in a
46             hashref or an arrayref of alternative data sources. This gives us as much flexibility as possible when expressing our data.
47            
48             =cut
49            
50             sub valuator {
51 0     0 1   my ($name, $node) = @_;
52 0 0         return $node->{$name} if (ref $node eq 'HASH');
53 0 0 0       return $node->express_value($name) if (UNIVERSAL::can($node, 'isa') and $node->can('express_value'));
54 0 0         if (ref $node eq 'ARRAY') {
55 0           foreach (@$node) {
56 0           my $v = valuator ($name, $_);
57 0 0         return $v if defined $v;
58             }
59             }
60 0           undef;
61             }
62            
63             =head2 do_foreach
64            
65             The C function implements a .foreach spanner in nodal templates that retrieves data from the structure and hands it off to the repeat
66             loop code for formatting.
67            
68             =cut
69            
70             sub do_foreach {
71 0     0 1   my ($self, $command, $values, $valuator) = @_;
72            
73 0           my ($keyword, $target, $source, @vars) = Decl::Semantics::Code::parse_select($$command[1]); # Same syntax as ^foreach in code
74            
75 0 0         if ($keyword eq 'error') { # Couldn't parse the foreach
76 0           return $self->express_repeat ($command, [
77             { error => "'.foreach/select " . $$command[1] ."' can't be parsed"},
78             $values
79             ], $valuator);
80             }
81            
82 0           my @results = ();
83 0 0         if ($keyword eq 'foreach') { # a local data access
84 0           my ($datasource, $type) = $values->find_data($source); # TODO: error handling if source not found.
85            
86 0 0 0       if (not @vars and $datasource->is ('data')) {
87             # Take vars from definition of data source.
88 0           push @vars, $datasource->parmlist;
89             }
90            
91 0 0         if ($type ne 'data') { # We can only iterate over data (for now, anyway).
92 0           return $self->express_repeat ($command, [
93             { error => 'source not data'},
94             $values
95             ], $valuator);
96             }
97            
98 0           my $iterator = $datasource->iterate;
99 0           while (my $line = $iterator->next) {
100             # http://stackoverflow.com/questions/38345/is-there-an-elegant-zip-to-interleave-two-lists-in-perl-5
101             # This is a nice one-liner that takes the names of the variables and their values, in separate lists,
102             # zips the two lists together, and makes it a hashref suitable for template interpretation.
103 0           push @results, { (@vars, @$line)[ map { $_, $_ + @vars } ( 0 .. $#vars ) ] };
  0            
104             }
105             } else { # a select!
106 0           my $dbh = $values->find_context ('database')->payload; # TODO: error handling
107 0           my $sth = $dbh->prepare ('select ' . $target . ' from ' . $source); # TODO: error handling here, too
108 0           $sth->execute();
109 0           while (my $row = $sth->fetchrow_hashref()) {
110 0           push @results, $row;
111             }
112             }
113            
114 0           $self->express_repeat ($command, $values, $valuator, @results);
115             }
116            
117            
118             =head1 AUTHOR
119            
120             Michael Roberts, C<< >>
121            
122             =head1 BUGS
123            
124             Please report any bugs or feature requests to C, or through
125             the web interface at L. I will be notified, and then you'll
126             automatically be notified of progress on your bug as I make changes.
127            
128             =head1 LICENSE AND COPYRIGHT
129            
130             Copyright 2011 Michael Roberts.
131            
132             This program is free software; you can redistribute it and/or modify it
133             under the terms of either: the GNU General Public License as published
134             by the Free Software Foundation; or the Artistic License.
135            
136             See http://dev.perl.org/licenses/ for more information.
137            
138             =cut
139            
140             1; # End of Decl::NodalValuator