File Coverage

blib/lib/Text/Bind.pm
Criterion Covered Total %
statement 86 126 68.2
branch 21 50 42.0
condition 7 17 41.1
subroutine 8 8 100.0
pod 0 3 0.0
total 122 204 59.8


line stmt bran cond sub pod time code
1             ##---------------------------------------------------------------------------##
2             ## File:
3             ## @(#) Bind.pm 1.5 99/07/07 21:53:55
4             ## Author:
5             ## Earl Hood earlhood@bigfoot.com
6             ## Description:
7             ## Class for supporting HTML template pages for perl CGI programs.
8             ## More explanation at end of source file.
9             ##---------------------------------------------------------------------------##
10             ## Copyright (C) 1997-1999 Earl Hood, earlhood@bigfoot.com
11             ## All rights reserved.
12             ##
13             ## This program is free software; you can redistribute it and/or
14             ## modify it under the same terms as Perl itself.
15             ##---------------------------------------------------------------------------##
16              
17             package Text::Bind;
18              
19 1     1   634 use strict;
  1         2  
  1         36  
20 1     1   5 use vars '$VERSION';
  1         2  
  1         64  
21             $VERSION = '0.04';
22              
23             ##---------------------------------------------------------------------------##
24              
25 1     1   5 use Carp;
  1         12  
  1         82  
26 1     1   27269 use FileHandle;
  1         23794  
  1         5  
27              
28             ###############################################################################
29             ## Public Class Methods
30             ###############################################################################
31              
32             ##---------------------------------------------------------------------------##
33              
34             sub new {
35 1     1 0 23 my $this = { };
36 1         3 my $mod = shift; # Name of module
37 1         2 my $file = shift; # Text input
38 1   33     7 my $class = ref($mod) || $mod;
39              
40 1         3 $this->{'file'} = $file;
41 1         3 bless $this, $class;
42 1         3 $this;
43             }
44              
45             ###############################################################################
46             ## Public Object Methods
47             ###############################################################################
48              
49             ##---------------------------------------------------------------------------##
50              
51             sub bind_site {
52 6     6 0 170 my $this = shift;
53 6         9 my $site = shift; # Site name
54 6         7 my $bind = shift; # Bind value to site
55              
56 6         17 $this->{'site'}{$site} = $bind;
57 6         20 $this->{'args'}{$site} = [ @_ ];
58             }
59              
60             ##---------------------------------------------------------------------------##
61              
62             sub read_text {
63 1     1 0 6 my $this = shift;
64 1   50     5 my $outfh = shift(@_) || \*STDOUT; # Output stream (optional)
65 1   33     7 my $file = shift(@_) || $this->{'file'}; # File to read (optional)
66              
67             # Open file. If unable, generate error message and return zero status.
68 1         1 my($fh);
69 1 50       4 if (ref $file) {
70 0         0 $fh = $file;
71             } else {
72 1         11 $fh = new FileHandle $file;
73 1 50       99 if (not defined $fh) {
74 0         0 carp qq|Unable to open "$file": $!|;
75 0         0 return 0;
76             }
77             }
78              
79             # Parse file
80 1         2 my(@list);
81 1         2 my($buf, $notone);
82              
83 1         2 local($_);
84 1         23 while (<$fh>) {
85 25         118 @list = split(/##PL_(?i)beginloop##/o, $_, 2);
86 25 50       63 if (@list < 2) {
87 25         62 $this->_eval_bindings($outfh, $list[0]);
88 25         87 next;
89             }
90 0         0 $notone = 0;
91 0         0 $this->_eval_bindings($outfh, shift(@list));
92 0         0 $_ = shift(@list); $buf = "";
  0         0  
93 0         0 while (!/##PL_(?i)endloop##/) {
94 0         0 $buf .= $_;
95 0 0       0 last unless defined($_ = <$fh>);
96 0         0 $notone = 1;
97             }
98 0         0 @list = split(/##PL_(?i)endloop##/o, $_, 2);
99 0 0       0 if ($notone) {
100 0         0 $buf .= shift(@list);
101             } else {
102 0         0 $buf = shift(@list);
103             }
104 0         0 1 while $this->_eval_bindings($outfh, $buf);
105 0 0       0 $this->_eval_bindings($outfh, shift(@list)) if defined $list[0];
106              
107             } # End while (<$fh>)
108              
109 1         26 1;
110             }
111              
112             ###############################################################################
113             ## Private Functions
114             ###############################################################################
115              
116             sub _eval_bindings {
117 25     25   31 my $this = shift;
118 25         29 my $outfh = shift;
119 25         29 my $text = shift;
120              
121 25 50 33     106 return 0 unless defined($outfh) && defined($text);
122              
123             # Split on data site markup
124 25         110 my @list = split(/##PL_([^#]+)##/, $text);
125              
126             # First item of list is regular data, so just output.
127 25         37 my $data = shift(@list);
128 25 50       78 print $outfh $data if defined($data);
129              
130             # If other items are still in the list, then there are data
131             # sites to resolve.
132 25         25 my($site, $name, $value, $bind, $status, $tmp);
133 25         32 my $retval = 0;
134              
135 25         60 LINE: while (@list) {
136 12         15 $site = shift @list;
137 12         20 $data = shift @list;
138 12 50       56 if ($site =~ /^(\w+)\s*=\s*(.+)/) {
139 12         53 ($name, $value) = (lc $1, $2);
140             } else {
141 0         0 next LINE;
142             }
143              
144             # Check on type of data site
145             SITE: {
146              
147             # File site: open file and include contents where data
148             # site is located. Filename could also include trailing
149             # pipe to allow a program to be invoked.
150 12 100       14 if ($name eq "file") {
  12         26  
151 2         22 my $incfh = new FileHandle $value;
152 2 50       4625 if (defined $incfh) {
153 2         3900 while (<$incfh>) {
154 76         210 print $outfh $_;
155             }
156             }
157 2         8 undef $incfh; # closes file
158 2         1357 last SITE;
159             }
160              
161             # Named site: check if binding registered for value of
162             # site. If so, execute binding.
163 10 50       19 if ($name eq "site") {
164 10         15 $value =~ s/\s//g; # strip any whitespace
165 10         18 $bind = $this->{site}{$value};
166              
167 10 100       20 if (defined $bind) {
168             BIND: {
169             # Function: Call if defined. If not, silently
170             # ignore.
171 9 100       15 if (ref($bind) eq 'CODE') {
  9         22  
172 2         8 $retval = &$bind($this, $outfh, $value,
173 2 50       6 @{$this->{args}{$value}})
174             if defined &$bind;
175 2         23 last BIND;
176             }
177              
178             # Array: shift through the items in the array
179 7 50       16 if (ref($bind) eq 'ARRAY') {
180 0         0 $tmp = shift(@{$bind});
  0         0  
181 0 0       0 $retval = scalar(@{$bind}) unless $retval;
  0         0  
182 0 0       0 last BIND unless defined $tmp;
183             ARRAY: {
184 0 0       0 if (ref($tmp) eq 'CODE') {
  0         0  
185 0         0 &$tmp($this, $outfh, $value,
186 0 0       0 @{$this->{args}{$value}})
187             if defined &$tmp;
188 0         0 last ARRAY;
189             }
190 0 0 0     0 if (ref($tmp) && $tmp =~ /GLOB/) {
191 0         0 local $_; while (<$tmp>) {
  0         0  
192 0         0 print $outfh $_;
193             }
194 0         0 last ARRAY;
195             }
196 0 0       0 if (ref($tmp)) {
197 0         0 $tmp->fill_site($this, $outfh, $site,
198 0         0 @{$this->{args}{$value}});
199 0         0 last ARRAY;
200             }
201 0         0 print $outfh $tmp;
202 0         0 last ARRAY;
203             }
204 0         0 last BIND;
205             }
206              
207             # Filehandle: Have to use regex to check
208             # for filehandle in case a filehandle class
209             # is in use.
210 7 100 100     32 if (ref($bind) && $bind =~ /GLOB/) {
211 1         1 local $_;
212 1         22 while (<$bind>) {
213 4         14 print $outfh $_;
214             }
215 1         2 last BIND;
216             }
217              
218             # Object: Call the method that the object
219             # should define to work with this class. We
220             # only check if $bind is a reference. Other
221             # relevant reference types are checked above.
222 6 100       13 if (ref($bind)) {
223 1         5 $retval = $bind->fill_site($this, $outfh, $site,
224 1         3 @{$this->{args}{$value}});
225 1         8 last BIND;
226             }
227              
228             # String: Fallback case; just output string
229 5         7 print $outfh $bind;
230 5         10 last BIND;
231              
232             } # End BIND
233             }
234 10         12 last SITE;
235             }
236              
237             } # End SITE
238              
239             } continue {
240 12 50       73 print $outfh $data if defined($data);
241              
242             } # End while (@list)
243              
244 25         62 $retval;
245             }
246              
247             ##---------------------------------------------------------------------------##
248             1;
249              
250             __END__