File Coverage

blib/lib/Pod/Constants.pm
Criterion Covered Total %
statement 106 116 91.3
branch 62 80 77.5
condition 6 9 66.6
subroutine 15 16 93.7
pod 3 7 42.8
total 192 228 84.2


line stmt bran cond sub pod time code
1             # Copyright (C) 2001, 2002, 2007 Sam Vilain. All Rights Reserved.
2             # This module is free software. It may be used, redistributed and/or
3             # modified under the terms of the Perl Artistic License, version 2 or
4             # later, OR the terms of the GNU General Public License, v3 or later.
5              
6             package Pod::Constants;
7              
8             =head1 NAME
9              
10             Pod::Constants - Include constants from POD
11              
12             =head1 SYNOPSIS
13              
14             use vars qw($myvar $VERSION @myarray $html %myhash);
15              
16             use Pod::Constants -trim => 1,
17             'Pod Section Name' => \$myvar,
18             'Version' => sub { eval },
19             'Some list' => \@myarray,
20             html => \$html,
21             'Some hash' => \%myhash;
22              
23             =head2 Pod Section Name
24              
25             This string will be loaded into $myvar
26              
27             =head2 Version
28              
29             # This is an example of using a closure. $_ is set to the
30             # contents of the paragraph. In this example, "eval" is
31             # used to execute this code at run time.
32             $VERSION = 0.17;
33              
34             =head2 Some list
35              
36             Each line from this section of the file
37             will be placed into a seperate array element.
38             For example, this is $myarray[2].
39              
40             =head2 Some hash
41              
42             This text will not go into the hash, because
43             it doesn't look like a definition list.
44             key1 => Some value (this will go into the hash)
45             var2 => Some Other value (so will this)
46             wtf = This won't make it in.
47              
48             =head2 %myhash's value after the above:
49              
50             ( key1 => "Some value (this will go into the hash)",
51             var2 => "Some Other value (so will this)" )
52              
53             =begin html

This text will be in $html

54              
55             =cut
56              
57             =head1 DESCRIPTION
58              
59             This module allows you to specify those constants that should be
60             documented in your POD, and pull them out a run time in a fairly
61             arbitrary fashion.
62              
63             Pod::Constants uses Pod::Parser to do the parsing of the source file.
64             It has to open the source file it is called from, and does so directly
65             either by lookup in %INC or by assuming it is $0 if the caller is
66             "main" (or it can't find %INC{caller()})
67              
68             =head2 ARBITARY DECISIONS
69              
70             I have made this code only allow the "Pod Section Name" to match
71             `headN', `item', `for' and `begin' POD sections. If you have a good
72             reason why you think it should match other POD sections, drop me a
73             line and if I'm convinced I'll put it in the standard version.
74              
75             For `for' and `begin' sections, only the first word is counted as
76             being a part of the specifier, as opposed to `headN' and `item', where
77             the entire rest of the line counts.
78              
79             =cut
80              
81 1     1   609 use 5.004;
  1         3  
  1         31  
82 1     1   5 use strict;
  1         1  
  1         29  
83              
84 1     1   11 use base qw(Pod::Parser Exporter);
  1         2  
  1         122  
85 1     1   5 use Data::Dumper;
  1         2  
  1         46  
86 1     1   7 use Carp;
  1         1  
  1         53  
87              
88 1     1   4 use vars qw($VERSION);
  1         1  
  1         926  
89             $VERSION = 0.17;
90              
91             # An ugly hack to go from caller() to the relevant parser state
92             # variable
93             my %parsers;
94              
95             sub end_input {
96             #my ($parser, $command, $paragraph, $line_num) = (@_);
97 21     21 0 22 my $parser = shift;
98              
99 21 100       82 return unless $parser->{active};
100              
101 19 100       54 print "Found end of $parser->{active}\n" if ($parser->{DEBUG});
102 19         28 my $whereto = $parser->{wanted_pod_tags}->{$parser->{active}};
103 19 100       35 print "\$_ will be set to:\n---\n$parser->{paragraphs}\n---\n"
104             if ($parser->{DEBUG});
105              
106 19 100       208 $parser->{paragraphs} =~ s/^\s*|\s*$//gs
107             if $parser->{trimmed_tags}->{$parser->{active}};
108              
109 19 100       51 if (ref $whereto eq "CODE") {
    100          
    100          
    50          
110 10 100       21 print "calling sub\n" if $parser->{DEBUG};
111 10         18 local ($_) = $parser->{paragraphs};
112 10         25 $whereto->();
113 10 100       420 print "done\n" if $parser->{DEBUG};
114             } elsif (ref $whereto eq "SCALAR") {
115 7 100       19 print "inserting into scalar\n" if $parser->{DEBUG};
116 7         11 $$whereto = $parser->{paragraphs};
117             } elsif (ref $whereto eq "ARRAY") {
118 1 50       3 print "inserting into array\n" if $parser->{DEBUG};
119 1         4 @$whereto = split /\n/, $parser->{paragraphs};
120             } elsif (ref $whereto eq "HASH") {
121 1 50       6 print "inserting into hash\n" if $parser->{DEBUG};
122             # Oh, sorry, should I be in LISP101?
123 1         26 %$whereto = (map { map { s/^\s*|\s*$//g; $_ }
  2         4  
  4         21  
  4         11  
124             split /=>/, $_ }
125             grep m/^
126             ( (?:[^=]|=[^>])+ ) # scan up to "=>"
127             =>
128             ( (?:[^=]|=[^>])+ =? )# don't allow more "=>"'s
129             $/x,
130             split /\n/, $parser->{paragraphs});
131 0         0 } else { die $whereto }
132 19         69 $parser->{active} = undef;
133             }
134              
135             # Pod::Parser overloaded command
136             sub command {
137 51     51 0 79 my ($parser, $command, $paragraph, $line_num) = @_;
138              
139 51         120 $paragraph =~ s/(?:\r\n|\n\r)/\n/g;
140              
141 51 100       114 print "Got command =$command, value=$paragraph\n"
142             if $parser->{DEBUG};
143              
144 51 100       96 $parser->end_input() if $parser->{active};
145              
146 51         32 my $does_she_want_it_sir;
147              
148             my ($lookup);
149             # first check for a catch-all for this command type
150 51 100       239 if ( exists $parser->{wanted_pod_tags}->{"*$command"} ) {
    50          
151 2         3 $parser->{paragraphs} = $paragraph;
152 2         2 $parser->{active} = "*$command";
153 2         6 $does_she_want_it_sir = "oohw";
154              
155             } elsif ($command =~ m/^(head\d+|item|(for|begin))$/) {
156 49 100       90 if ( $2 ) {
157             # if it's a "for" or "begin" section, the title is the
158             # first word only
159 1         5 ($lookup, $parser->{paragraphs}) =
160             ($paragraph =~ m/^\s*(\S*)\s*(.*)/s);
161             } else {
162             # otherwise, it's up to the end of the line
163 48         253 ($lookup, $parser->{paragraphs})
164             = ($paragraph =~ m/^\s*(\S[^\n]*?)\s*\n(.*)$/s);
165             }
166              
167             # Look for a match by name
168 49 100 66     225 if (defined $lookup
169             and exists $parser->{wanted_pod_tags}->{$lookup}) {
170 17 100       38 print "Found $lookup\n" if ($parser->{DEBUG});
171 17         21 $parser->{active} = $lookup;
172 17         15 $does_she_want_it_sir = "suits you sir";
173             }
174              
175             } else {
176             # nothing
177 0 0       0 print "Ignoring =$command (not known)\n" if $parser->{DEBUG};
178             }
179              
180             {
181 51         46 local $^W = 0;
  51         134  
182 51 50 66     1997 print "Ignoring =$command $paragraph (lookup = $lookup)\n"
183             if (!$does_she_want_it_sir and $parser->{DEBUG})
184             }
185             }
186              
187             # Pod::Parser overloaded verbatim
188             sub verbatim {
189 145     145 0 162 my ($parser, $paragraph, $line_num) = @_;
190 145         318 $paragraph =~ s/(?:\r\n|\n\r)/\n/g;
191              
192 145 50       283 print("Got paragraph: $paragraph ("
    100          
193             .($parser->{active}?"using":"ignoring").")\n")
194             if $parser->{DEBUG};
195              
196 145 100       5349 if (defined $parser->{active}) {
197 43         1579 $parser->{paragraphs} .= $paragraph;
198             }
199             }
200              
201             # Pod::Parser overloaded textblock
202 78     78 0 150 sub textblock { goto \&verbatim }
203              
204             =head1 FUNCTIONS
205              
206             =head2 import(@args)
207              
208             This function is called when we are "use"'d. It determines the source
209             file by inspecting the value of caller() or $0.
210              
211             The form of @args is HOOK => $where.
212              
213             $where may be a scalar reference, in which case the contents of the
214             POD section called "HOOK" will be loaded into $where.
215              
216             $where may be an array reference, in which case the contents of the
217             array will be the contents of the POD section called "HOOK", split
218             into lines.
219              
220             $where may be a hash reference, in which case any lines with a "=>"
221             symbol present will have everything on the left have side of the =>
222             operator as keys and everything on the right as values. You do not
223             need to quote either, nor have trailing commas at the end of the
224             lines.
225              
226             $where may be a code reference (sub { }), in which case the sub is
227             called when the hook is encountered. $_ is set to the value of the
228             POD paragraph.
229              
230             You may also specify the behaviour of whitespace trimming; by default,
231             no trimming is done except on the HOOK names. Setting "-trim => 1"
232             turns on a package "global" (until the next time import is called)
233             that will trim the $_ sent for processing by the hook processing
234             function (be it a given function, or the built-in array/hash
235             splitters) for leading and trailing whitespace.
236              
237             The name of HOOK is matched against any "=head1", "=head2", "=item",
238             "=for", "=begin" value. If you specify the special hooknames "*item",
239             "*head1", etc, then you will get a function that is run for every
240              
241             Note that the supplied functions for array and hash splitting are
242             exactly equivalent to fairly simple Perl blocks:
243              
244             Array:
245              
246             HOOK => sub { @array = split /\n/, $_ }
247              
248             Hash:
249              
250             HOOK => sub {
251             %hash =
252             (map { map { s/^\s+|\s+$//g; $_ } split /=>/, $_ }
253             (grep m/^
254             ( (?:[^=]|=[^>])+ ) # scan up to "=>"
255             =>
256             ( (?:[^=]|=[^>])+ =? )# don't allow more "=>"'s
257             $/x, split /\n/, $_));
258             }
259              
260             Well, they're simple if you can grok map, a regular expression like
261             that and a functional programming style. If you can't I'm sure it is
262             probably voodoo to you.
263              
264             Here's the procedural equivalent:
265              
266             HOOK => sub {
267             for my $line (split /\n/, $_) {
268             my ($key, $value, $junk) = split /=>/, $line;
269             next if $junk;
270             $key =~ s/^\s+|\s+$//g
271             $value =~ s/^\s+|\s+$//g
272             $hash{$key} = $value;
273             }
274             },
275              
276             =cut
277              
278             sub import {
279 6     6   97556 my $class = shift;
280              
281             # if no args, just return
282 6 50       21 return unless (@_);
283              
284             # try to guess the source file of the caller
285 6         7 my $source_file;
286 6 100       19 if (caller ne "main") {
287 5         24 (my $module = caller().".pm") =~ s|::|/|g;
288 5         10 $source_file = $INC{$module};
289             }
290 6   66     16 $source_file ||= $0;
291              
292 6 50       121 ( -f $source_file )
293             or croak ("Cannot find source file (guessed $source_file) for"
294             ." package ".caller());
295              
296             # nasty tricks with the stack so we don't have to be silly with
297             # caller()
298 6         15 unshift @_, $source_file;
299 6         27 goto \&import_from_file;
300             }
301              
302             =head2 import_from_file($filename, @args)
303              
304             Very similar to straight "import", but you specify the source filename
305             explicitly.
306              
307             =cut
308              
309 1     1   604 use IO::Handle;
  1         5594  
  1         513  
310              
311             sub import_from_file {
312 6     6 1 10 my $filename = shift;
313              
314 6         87 my $parser = __PACKAGE__->new();
315              
316 6         22 $parser->{wanted_pod_tags} = {};
317 6         12 $parser->{trimmed_tags} = {};
318 6         10 $parser->{trim_next} = 0;
319 6         12 $parser->{DEBUG} = 0;
320 6         8 $parser->{active} = undef;
321 6         13 $parsers{caller()} = $parser;
322              
323 6         79 $parser->add_hook(@_);
324              
325 6 100       21 print "Pod::Parser: DEBUG: Opening $filename for reading\n"
326             if $parser->{DEBUG};
327 6         35 my $fh = new IO::Handle;
328 6 50       290 open $fh, "<$filename"
329             or die ("cannot open $filename for reading; $!");
330              
331 6         1242 $parser->parse_from_filehandle($fh, \*STDOUT);
332              
333 6         163 close $fh;
334             }
335              
336             =head2 add_hook(NAME => value)
337              
338             This function adds another hook, it is useful for dynamic updating of
339             parsing through the document.
340              
341             For an example, please see t/01-constants.t in the source
342             distribution. More detailed examples will be added in a later
343             release.
344              
345             =cut
346              
347             sub add_hook {
348 7     7 1 14 my $parser;
349 7 100       28 if ( UNIVERSAL::isa($_[0], __PACKAGE__) ) {
350 6         9 $parser = shift;
351             } else {
352 1 50       4 $parser = $parsers{caller()}
353             or die("add_hook called, but don't know what for - "
354             ."caller = ".caller());
355             }
356 7         29 while (my ($pod_tag, $var) = splice @_, 0, 2) {
357             #print "$pod_tag: $var\n";
358 24 100       62 if (lc($pod_tag) eq "-trim") {
    100          
    50          
359 4         11 $parser->{trim_next} = $var;
360             } elsif ( lc($pod_tag) eq "-debug" ) {
361 2         6 $parser->{DEBUG} = $var;
362             } elsif (lc($pod_tag) eq "-usage") {
363             # an idea for later - automatic "usage"
364             #%wanted_pod_tags{@tags}
365             } else {
366 18 50       62 if ((ref $var) =~ /^(?:SCALAR|CODE|ARRAY|HASH)$/) {
367 18 100       66 print "Will look for $pod_tag.\n"
368             if ($parser->{DEBUG});
369 18         37 $parser->{wanted_pod_tags}->{$pod_tag} = $var;
370 18 100       78 $parser->{trimmed_tags}->{$pod_tag} = 1
371             if $parser->{trim_next};
372             } else {
373 0           die ("Sorry - need a reference to import POD "
374             ."sections into, not the scalar value $var"
375             ." importing $pod_tag into ".caller());
376             }
377             }
378             }
379             }
380              
381             =head2 delete_hook(@list)
382              
383             Deletes the named hooks. Companion function to add_hook
384              
385             =cut
386              
387             sub delete_hook {
388 0     0 1   my $parser;
389 0 0         if ( UNIVERSAL::isa($_[0], __PACKAGE__) ) {
390 0           $parser = shift;
391             } else {
392 0 0         $parser = $parsers{caller()}
393             or die("delete_hook called, but don't know what for - "
394             ."caller = ".caller());
395             }
396 0           while ( my $label = shift ) {
397 0           delete $parser->{wanted_pod_tags}->{$label};
398 0           delete $parser->{trimmed_tags}->{$label};
399             }
400             }
401              
402             =head2 CLOSURES AS DESTINATIONS
403              
404             If the given value is a ref CODE, then that function is called, with
405             $_ set to the value of the paragraph. This can be very useful for
406             applying your own custom mutations to the POD to change it from human
407             readable text into something your program can use.
408              
409             After I added this function, I just kept on thinking of cool uses for
410             it. The nice, succinct code you can make with it is one of
411             Pod::Constant's strongest features.
412              
413             Below are some examples.
414              
415             =head1 EXAMPLES
416              
417             =head2 Module Makefile.PL maintenance
418              
419             Tired of keeping those module Makefile.PL's up to date? Note: This
420             method seems to break dh-make-perl.
421              
422             =head2 Example Makefile.PL
423              
424             eval "use Pod::Constants";
425             ($Pod::Constants::VERSION >= 0.11)
426             or die <
427             ####
428             #### ERROR: This module requires Pod::Constants 0.11 or
429             #### higher to be installed.
430             ####
431             EOF
432              
433             my ($VERSION, $NAME, $PREREQ_PM, $ABSTRACT, $AUTHOR);
434             Pod::Constants::import_from_file
435             (
436             'MyTestModule.pm',
437             'MODULE RELEASE' => sub { ($VERSION) = m/(\d+\.\d+)/ },
438             'DEPENDANCIES' => ($PREREQ_PM = { }),
439             -trim => 1,
440             'NAME' => sub { $ABSTRACT=$_; ($NAME) = m/(\S+)/ },
441             'AUTHOR' => \$AUTHOR,
442             );
443              
444             WriteMakefile
445             (
446             'NAME' => $NAME,
447             'PREREQ_PM' => $PREREQ_PM,
448             'VERSION' => $VERSION,
449             ($] >= 5.005 ? ## Add these new keywords supported since 5.005
450             (ABSTRACT => $ABSTRACT,
451             AUTHOR => $AUTHOR) : ()),
452             );
453              
454             =head2 Corresponding Module
455              
456             =head1 NAME
457              
458             MyTestModule - Demonstrate Pod::Constant's Makefile.PL usefulness
459              
460             =head2 MODULE RELEASE
461              
462             This is release 1.05 of this module.
463              
464             =head2 DEPENDANCIES
465              
466             The following modules are required to make this module:
467              
468             Some::Module => 0.02
469              
470             =head2 AUTHOR
471              
472             Ima Twat
473              
474             =cut
475              
476             use vars qw($VERSION);
477             use Pod::Constants -trim => 1,
478             'MODULE RELEASE' => sub { ($VERSION) = m/(\d+\.\d+) or die };
479              
480             =head1 AUTHOR
481              
482             Sam Vilain,
483              
484             =head1 BUGS/TODO
485              
486             I keep thinking it would be nice to be able to import an =item list
487             into an array or something, eg for a program argument list. But I'm
488             not too sure how it would be all that useful in practice; you'd end up
489             putting the function names for callbacks in the pod or something
490             (perhaps not all that bad).
491              
492             Would this be useful?
493              
494             Pod::Constants::import(Foo::SECTION => \$myvar);
495              
496             Debug output is not very readable
497              
498             =head1 PATCHES WELCOME
499              
500             If you have any suggestions for enhancements, they are much more likely
501             to happen if you submit them as a patch to the distribution.
502              
503             Source is kept at
504              
505             git://utsl.gen.nz/Pod-Constants
506              
507             =cut
508              
509             BEGIN {
510             Pod::Constants->import
511             (
512             SYNOPSIS => sub {
513 1         1 eval pop @{[ grep /^\s*\$VERSION/, split /\n/, $_ ]}
  1         67  
514             }
515             )
516 1     1   7 };
517              
518             1.4142;