File Coverage

lib/App/Followme/PodData.pm
Criterion Covered Total %
statement 133 147 90.4
branch 16 34 47.0
condition n/a
subroutine 24 26 92.3
pod 2 15 13.3
total 175 222 78.8


line stmt bran cond sub pod time code
1             package App::Followme::PodData;
2              
3 1     1   640 use 5.008005;
  1         16  
4 1     1   8 use strict;
  1         2  
  1         26  
5 1     1   6 use warnings;
  1         1  
  1         43  
6 1     1   7 use integer;
  1         2  
  1         8  
7 1     1   25 use lib '../..';
  1         1  
  1         9  
8              
9 1     1   164 use base qw(App::Followme::FileData);
  1         3  
  1         490  
10              
11 1     1   7 use Pod::Simple::XHTML;
  1         2  
  1         42  
12 1     1   6 use File::Spec::Functions qw(abs2rel catfile rel2abs splitdir);
  1         2  
  1         57  
13              
14 1     1   6 use App::Followme::FIO;
  1         2  
  1         80  
15 1     1   6 use App::Followme::Web;
  1         2  
  1         1700  
16              
17             our $VERSION = "2.01";
18              
19             #----------------------------------------------------------------------
20             # Read the default parameter values
21              
22             sub parameters {
23 4     4 1 9 my ($self) = @_;
24              
25             return (
26 4         15 package => '',
27             pod_directory => '',
28             final_directory => '',
29             extension => 'pm,pod',
30             title_template => '<h2></h2>',
31             );
32             }
33              
34             #----------------------------------------------------------------------
35             # Alter urls in body of pod file to corect final location
36              
37             sub alter_url {
38 16     16 0 775 my ($self, $url) = @_;
39              
40 16         53 my $site_url = $self->get_site_url($url);
41              
42 16         20 my $package;
43 16 100       57 if ($site_url eq substr($url, 0, length($site_url))) {
44 15         36 $package = substr($url, length($site_url));
45             } else {
46 1         2 $package = $url;
47             }
48              
49 16         88 $package =~ s/^$self->{package}:://;
50 16         45 my @package_path = split(/::/, $package);
51              
52 16         79 my $filename = catfile($self->{base_directory}, @package_path);
53              
54 16         29 my $found;
55 16         32 foreach my $ext ('pod', 'pm', 'pl') {
56 33 100       607 if (-e "$filename.$ext") {
57 15         39 $filename .= ".$ext";
58 15         25 $found = 1;
59 15         24 last;
60             }
61             }
62              
63 16 100       34 if ($found) {
64             $url = $self->filename_to_url($self->{top_directory},
65             $filename,
66 15         51 $self->{web_extension});
67             } else {
68 1         4 $url = '';
69             }
70              
71 16         165 return $url;
72             }
73              
74             #-----------------------------------------------------------------------
75             # Get the name of the web file a file will be converted to
76              
77             sub convert_filename {
78 16     16 0 399 my ($self, $filename) = @_;
79              
80 16 50       37 die "Base directory is undefined" unless $self->{base_directory};
81              
82 16         52 my $new_file = abs2rel($filename, $self->{base_directory});
83 16         993 $new_file = join('-', splitdir(lc($new_file)));
84              
85 16         152 $new_file =~ s/\.[^\.]*$/.$self->{web_extension}/;
86 16         72 $new_file = catfile($self->{final_directory}, $new_file);
87              
88 16         44 return $new_file;
89             }
90              
91             #-----------------------------------------------------------------------
92             # Get the name of the source directory for ConvertPage
93              
94             sub convert_source_directory {
95 0     0 0 0 my ($self, $directory) = @_;
96              
97 0 0       0 die "Base directory is undefined" unless $self->{base_directory};
98              
99 0         0 my $source_directory;
100 0 0       0 if (fio_same_file($directory, $self->{final_directory},
101             $self->{case_sensitivity})) {
102 0         0 $source_directory = $self->{base_directory};
103             }
104              
105 0         0 return $source_directory;
106             }
107              
108             #----------------------------------------------------------------------
109             # Extract the content between body tags in a web page
110              
111             sub extract_body {
112 3     3 0 70 my ($self, $html) = @_;
113              
114 3         451 my @section = split(/<\s*\/?body[^>]*>/i, $html);
115 3         275 s/^\s+// foreach @section;
116            
117 3         10 my $body = $section[1];
118              
119 3         182 $body =~ s/src="([^"]*)"/'src="' . $self->alter_url($1) . '"'/ge;
  0         0  
120 3         180 $body =~ s/href="([^"]*)"/'href="' . $self->alter_url($1) . '"'/ge;
  15         48  
121              
122 3         163 return $body;
123             }
124              
125             #----------------------------------------------------------------------
126             # Parse content as html to get values for data
127              
128             sub fetch_content {
129 3     3 0 10 my ($self, $content_block) = @_;
130              
131 3         6 my %content;
132 3         8 $content{body} = $content_block;
133              
134 3 50       14 if ($self->{title_template}) {
135             my $title_parser = sub {
136 28     28   73 my $title = web_only_text(@_);
137 28         63 $title =~ s/\s+/_/g;
138 28         66 return lc($title);
139 3         18 };
140              
141             my $section = web_titled_sections($self->{title_template},
142 3         18 $content_block,
143             $title_parser);
144              
145 3         20 my %mapping = ('title' => 'name',
146             'summary' => 'description',
147             'author' => 'author',
148             );
149              
150 3         20 while (my ($cname, $sname) = each %mapping) {
151 9         32 $content{$cname} = $section->{$sname};
152             }
153              
154 3         9 foreach my $cname (qw(author title)) {
155 6         18 my @tokens = web_split_at_tags($content{$cname});
156 6         18 $content{$cname} = web_only_text(@tokens);
157             }
158             }
159              
160 3 50       12 if ($content{title}) {
161 3         17 my @title_parts = split(/\s+-+\s+/, $content{title}, 2);
162 3         8 $content{title} = $title_parts[0];
163             }
164              
165 3         25 return %content;
166             }
167              
168             #----------------------------------------------------------------------
169             # Convert Pod into html
170              
171             sub fetch_as_html {
172 3     3 0 7 my ($self, $text) = @_;
173              
174 3         12 my $psx = $self->initialize_parser();
175              
176 3         4 my $html;
177 3         17 $psx->output_string(\$html);
178 3         1326 $psx->parse_string_document($text);
179 3         167287 return $self->extract_body($html);
180             }
181              
182             #----------------------------------------------------------------------
183             # Split into text from file into section blocks.
184              
185             sub fetch_sections {
186 3     3 0 10 my ($self, $text) = @_;
187              
188 3         4 my %section;
189 3         10 $section{body} = $self->fetch_as_html($text);
190 3         10 $section{metadata} = '';
191              
192 3         15 return \%section;
193             }
194              
195             #----------------------------------------------------------------------
196             # Convert filename to url
197              
198             sub filename_to_url {
199 15     15 0 40 my ($self, $directory, $filename, $ext) = @_;
200              
201 15         34 $filename = $self->convert_filename($filename);
202 15         52 return $self->SUPER::filename_to_url($directory, $filename, $ext);
203             }
204              
205             #----------------------------------------------------------------------
206             # Find the directory containing the pod files
207              
208             sub find_base_directory {
209 2     2 0 698 my ($self)= @_;
210              
211 2         7 my @package_path = split(/::/, $self->{package});
212 2         11 my $package_folder = catfile(@package_path);
213 2         6 my $package_file = "$package_folder.pm";
214              
215 2         3 my @folders;
216             push(@folders, split(/\s*,\s*/, $self->{pod_directory}))
217 2 50       9 if $self->{pod_directory};
218 2         9 push(@folders, @INC);
219              
220 2         4 for my $folder (@folders) {
221 2 50       49 if (-e catfile($folder, $package_file)) {
    0          
222 2         6 pop(@package_path);
223 2         14 return ($folder, \@package_path);
224              
225             } elsif(-e catfile($folder, $package_folder)) {
226 0         0 return ($folder, \@package_path);
227             }
228             }
229              
230 0         0 return;
231             }
232              
233             #----------------------------------------------------------------------
234             # Treat all pod files as if they were in a single directory
235              
236             sub find_matching_directories {
237 1     1 0 2 my ($self, $directory) = @_;
238              
239 1         2 my @directories = ();
240 1         2 return @directories;
241             }
242              
243             #----------------------------------------------------------------------
244             # Treat all pod files as if they were in a single directory
245              
246             sub find_matching_files {
247 2     2 0 1048 my ($self, $folder) = @_;
248              
249 2         9 my ($filenames, $folders) = fio_visit($folder);
250              
251 2         43 my @files;
252 2         5 foreach my $filename (@$filenames) {
253 54 50       126 push(@files, $filename) if $self->match_file($filename);
254             }
255              
256 2         5 foreach my $folder (@$folders) {
257 0 0       0 push(@files, $self->find_matching_files($folder))
258             if $self->match_directory($folder);
259             }
260              
261 2         30 return @files;
262             }
263              
264             #-----------------------------------------------------------------------
265             # Treat all pod files as if they were in a single directory
266              
267             sub get_folders {
268 0     0 0 0 my ($self, $filename) = @_;
269              
270 0         0 my ($directory, $file) = fio_split_filename($filename);
271 0         0 my @directories = $self->find_matching_directories($directory);
272              
273 0         0 return \@directories;
274             }
275              
276             #----------------------------------------------------------------------
277             # Initialize the pod parser
278              
279             sub initialize_parser {
280 3     3 0 6 my ($self) = @_;
281              
282 3         22 my ($h_level) = $self->{title_template} =~ /(\d+)/;
283 3 50       10 $h_level = 1 unless defined $h_level;
284              
285 3         27 my $psx = Pod::Simple::XHTML->new();
286              
287 3 50       424 $psx->html_h_level($h_level)
288             if $psx->can('html_h_level');
289              
290             $psx->perldoc_url_prefix($self->{site_url})
291 3 50       37 if $psx->can('perldoc_url_prefix');
292              
293 3         18 return $psx;
294             }
295              
296             #----------------------------------------------------------------------
297             # Initialize pod parser and find pod directory
298              
299             sub setup {
300 1     1 1 2 my ($self) = @_;
301              
302 1         3 my ($pod_folder, $package_path) = $self->find_base_directory();
303 1 50       4 die "Couldn't find folder for $self->{package}"
304             unless defined $pod_folder;
305              
306 1         2 $self->{final_directory} = $self->{base_directory};
307 1         14 $self->{base_directory} = catfile($pod_folder, @$package_path);
308 1         4 $self->{package} = join('::', @$package_path);
309              
310 1         3 return;
311             }
312              
313             1;
314             __END__
315             =encoding utf-8
316              
317             =head1 NAME
318              
319             App::Followme::PodData - Convert Pod files to html
320              
321             =head1 SYNOPSIS
322              
323             use App::Followme::PodData;
324             my $data = App::Followme::PodData->new();
325             my $html = App::Followme::Template->new('example.htm', $data);
326              
327             =head1 DESCRIPTION
328              
329             This module converts Perl files with POD markup into html and extracts the
330             metadata from the html.
331              
332             =head1 METHODS
333              
334             All data are accessed through the build method.
335              
336             =over 4
337              
338             =item my %data = $obj->build($name, $filename);
339              
340             Build a variable's value. The first argument is the name of the variable. The
341             second argument is the name of the file the metadata is being computed for. If
342             it is undefined, the filename stored in the object is used.
343              
344             =back
345              
346             =head1 VARIABLES
347              
348             The Pod metadata class can evaluate the following variables. When passing
349             a name to the build method, the sigil should not be used.
350              
351             =over 4
352              
353             =item $body
354              
355             All the contents of the file, minus the title if there is one.
356             Pod::Simple::XHTML is called on the file's content to generate html
357             before being stored in the body variable.
358              
359             =item $description
360              
361             A one line sentence description of the content.
362              
363             =item $title
364              
365             The title of the page is derived from contents of the top header tag, if one is
366             at the front of the file content, or the filename, if it is not.
367              
368             =back
369              
370             =head1 CONFIGURATION
371              
372             The following parameters are used from the configuration:
373              
374             =over 4
375              
376             =item pod_extension
377              
378             The extension of files that contain pod documentation. The default value
379             is pm,pod.
380              
381             =item pod_directory
382              
383             The directory containing the pod files
384              
385             =back
386              
387             =head1 LICENSE
388              
389             Copyright (C) Bernie Simon.
390              
391             This library is free software; you can redistribute it and/or modify
392             it under the same terms as Perl itself.
393              
394             =head1 AUTHOR
395              
396             Bernie Simon E<lt>bernie.simon@gmail.comE<gt>
397              
398             =cut