File Coverage

blib/lib/News/FormArticle.pm
Criterion Covered Total %
statement 15 57 26.3
branch 0 34 0.0
condition 0 3 0.0
subroutine 5 10 50.0
pod 1 3 33.3
total 21 107 19.6


line stmt bran cond sub pod time code
1             # -*- Perl -*-
2             ###########################################################################
3             # Written and maintained by Andrew Gierth
4             #
5             # Copyright 1997 Andrew Gierth. Redistribution terms at end of file.
6             #
7             # $Id: FormArticle.pm 1.7 2000/04/14 15:12:28 andrew Exp $
8             #
9              
10             =head1 NAME
11              
12             News::FormArticle - derivative of News::Article
13              
14             =head1 SYNOPSIS
15              
16             use News::FormArticle;
17              
18             See below for functions available.
19              
20             =head1 DESCRIPTION
21              
22             Like News::Article, but designed to be constructed from a file
23             containing form text with substitutions.
24              
25             Currently, the source text is substituted as follows:
26              
27             Variables are denoted by $NAME or @NAME (where NAME is any simple
28             identifier). (The sequences $$ and @@ denote literal $ and @
29             characters.) Variables of the form $NAME are expected to supply
30             scalar values which are interpolated; variables of the form @NAME
31             are expected to supply lists (or references to arrays) which are
32             interpolated with separating newlines.
33              
34             Values of variables are found by consulting the list of sources
35             supplied. Each source may be either a reference to a hash, or a
36             reference to code.
37              
38             Source hashes may contain as values either the desired value (scalar
39             or reference to array), or a typeglob, or a code reference which will
40             be called to return the result. (Since typeglobs are allowed values,
41             it is possible to supply a reference to a module symbol table as a
42             valid source.)
43              
44             Code references supplied as sources are invoked with the variable
45             name (including the leading $ or @) as the only parameter. In the
46             degenerate case, all variables accessible in the source scope may be
47             made available for interpolation by supplying the following as a
48             source:
49              
50             sub { eval shift }
51              
52             If multiple sources are supplied, then each is consulted in turn until
53             a defined value is found.
54              
55             =head1 USAGE
56              
57             use News::FormArticle;
58              
59             Exports nothing.
60              
61             =cut
62              
63             package News::FormArticle;
64              
65 2     2   6434 use strict;
  2         4  
  2         153  
66              
67 2     2   1639 use News::Article;
  2         7  
  2         151  
68 2     2   2029 use FileHandle ();
  2         9936  
  2         58  
69              
70 2     2   16 use vars qw(@ISA);
  2         4  
  2         108  
71 2     2   14 use subs qw(process_line);
  2         3  
  2         14  
72              
73             @ISA = qw(News::Article);
74              
75             # $obj = new News::FormArticle(filename, substs)
76              
77             =head1 Constructor
78              
79             =over 4
80              
81             =item new ( FILE [, SOURCE [...]] )
82              
83             Construct an article from the specified file, performing variable
84             substitution with values supplied by the C parameters (see
85             Description). FILE is any form of data recognised by News::Article\'s
86             read() method.
87              
88             =cut
89              
90             sub new
91             {
92 0     0 1   my $class = shift;
93 0           my $file = shift;
94 0           my $substs = \@_;
95 0           my $src = News::Article::source_init($file);
96 0 0         return undef unless defined($src);
97              
98 0     0     $class->SUPER::new(sub { process_line($src,$substs) });
  0            
99             }
100              
101             ###########################################################################
102             # Private functions
103             ###########################################################################
104              
105             sub subst_scalar
106             {
107 0     0 0   my ($name, $substs) = @_;
108 0           my $val = undef;
109              
110 0           for (@$substs)
111             {
112 0 0         if (ref($_) eq 'HASH')
    0          
113             {
114 0           $val = $$_{$name};
115             }
116             elsif (ref($_) eq 'CODE')
117             {
118 0           $val = &$_("\$".$name);
119             }
120 0 0         if (ref(\$val) eq 'GLOB')
    0          
121             {
122 0 0         $val = defined($ {*$val}) ? $ {*$val} : undef;
  0            
  0            
123             }
124             elsif (ref($val) eq 'CODE')
125             {
126 0           $val = &$val();
127             }
128 0 0         last if defined($val);
129             }
130 0           $val;
131             }
132              
133             sub subst_array
134             {
135 0     0 0   my ($name, $substs) = @_;
136 0           my $val = undef;
137              
138 0           for (@$substs)
139             {
140 0 0         if (ref($_) eq 'HASH')
    0          
141             {
142 0           $val = $$_{$name};
143             }
144             elsif (ref($_) eq 'CODE')
145             {
146 0           $val = [ &$_("\@".$name) ];
147 0 0 0       $val = $val->[0] if @$val == 1 && ref($val->[0]);
148             }
149 0 0         if (ref(\$val) eq 'GLOB')
    0          
150             {
151 0 0         $val = defined(@{*$val}) ? \@{*$val} : undef;
  0            
  0            
152             }
153             elsif (ref($val) eq 'CODE')
154             {
155 0           $val = [ &$val() ];
156             }
157 0 0         last if defined($val);
158             }
159 0           join("\n",@$val);
160             }
161              
162             sub process_line
163             {
164 0     0     my ($src, $substs) = @_;
165              
166 0           local $_ = &$src();
167 0 0         return undef unless defined($_);
168 0           chomp;
169 0           $_ .= "\n";
170              
171             # look for substitution patterns. We recognize:
172             # ?WORD
173             # where ? is either $ or @. Also, $$ = $ and @@ = @.
174              
175 0           s{ ([\$\@]) (\1|\w+) }
176 0 0         { (($1 eq $2) ? $1 : (($1 eq "\$") ? subst_scalar($2,$substs)
    0          
177             : subst_array($2,$substs))) }gex;
178              
179 0           $_;
180             }
181              
182             1;
183              
184             __END__