File Coverage

lib/App/Followme/EditSections.pm
Criterion Covered Total %
statement 88 97 90.7
branch 29 36 80.5
condition 2 6 33.3
subroutine 12 13 92.3
pod 1 6 16.6
total 132 158 83.5


line stmt bran cond sub pod time code
1             package App::Followme::EditSections;
2              
3 1     1   778 use 5.008005;
  1         19  
4 1     1   10 use strict;
  1         2  
  1         33  
5 1     1   5 use warnings;
  1         2  
  1         39  
6              
7 1     1   5 use lib '../..';
  1         2  
  1         6  
8              
9 1     1   226 use base qw(App::Followme::Module);
  1         3  
  1         617  
10              
11 1     1   8 use File::Spec::Functions qw(catfile);
  1         2  
  1         73  
12 1     1   6 use App::Followme::FIO;
  1         3  
  1         1057  
13              
14             our $VERSION = "2.01";
15              
16             #----------------------------------------------------------------------
17             # Read the default parameter values
18              
19             sub parameters {
20 16     16 1 30 my ($pkg) = @_;
21              
22             return (
23 16         49 remove_comments => 0,
24             data_pkg => 'App::Followme::WebData',
25             );
26             }
27              
28             #----------------------------------------------------------------------
29             # Modify pages to match the most recently modified page
30              
31             sub run {
32 0     0 0 0 my ($self, $folder) = @_;
33              
34 0         0 $self->update_folder($folder);
35 0         0 return;
36             }
37              
38             #----------------------------------------------------------------------
39             # Find the location of a string in a page
40              
41             sub find_location {
42 42     42 0 91 my ($self, $page, $prototype, $propos, $after) = @_;
43              
44 42         51 my $hi;
45 42         55 my $lo = 0;
46 42         51 my $mid = 8;
47              
48 42   33     132 while ($mid > $lo && (! defined $hi || $mid < $hi)) {
      33        
49 49         62 my $str;
50 49 100       84 if ($after) {
51 21         39 $str = substr($prototype, $propos, $mid)
52             } else {
53 28 50       48 $mid = $propos if $mid > $propos;
54 28         57 $str = substr($prototype, $propos-$mid, $mid);
55             }
56              
57 49         72 my $count = 0;
58 49         61 my $pagepos = -1;
59 49         86 while ($count < 2) {
60 98         186 my $newpos = index($page, $str, $pagepos+1);
61 98 100       162 last unless $newpos > $pagepos;
62              
63 56         67 $count ++;
64 56         100 $pagepos = $newpos;
65             }
66              
67 49 100       96 if ($count > 1) {
    50          
68 7         9 $lo = $mid;
69 7 50       14 if (defined $hi) {
70 0         0 $mid = int(0.5 * ($mid + $hi));
71             } else {
72 7         19 $mid = 2 * $mid;
73             }
74              
75             } elsif ($count == 1) {
76 42 100       73 $pagepos += $mid unless $after;
77 42         76 return $pagepos;
78              
79             } else {
80 0         0 $hi = $mid;
81 0         0 $mid = int(0.5 * ($mid + $lo));
82             }
83             }
84              
85 0         0 return;
86             }
87              
88             #----------------------------------------------------------------------
89             # Read page and strip comments
90              
91             sub strip_comments {
92 13     13 0 1983 my ($self, $file, $keep_sections) = @_;
93              
94 13         55 my $page = fio_read_page($file);
95 13 50       67 die "Could not read page" unless length($page);
96              
97 13         26 my @output;
98 13         187 my @tokens = split(/(<!--.*?-->)/, $page);
99              
100 13         44 foreach my $token (@tokens) {
101 169 100       456 if ($token !~ /^(<!--.*?-->)$/) {
    100          
102 91         163 push(@output, $token);
103             } elsif ($token =~ /(<!--\s*end)?section\s+.*?-->/) {
104 24 100       55 push(@output, $token) if $keep_sections;
105             } else {
106 54 100       143 push(@output, $token) unless $self->{remove_comments};
107             }
108             }
109              
110 13         92 return join('', @output);
111             }
112              
113             #----------------------------------------------------------------------
114             # Parse prototype and page and combine them
115              
116             sub update_file {
117 7     7 0 19 my ($self, $file, $prototype) = @_;
118              
119 7         22 my $page = $self->strip_comments($file, 0);
120              
121 7         16 my @output;
122             my $notfound;
123 7         44 while ($prototype =~ /(<!--\s*(?:end)?section\s+.*?-->)/g) {
124 42         96 my $comment = $1;
125 42         61 my $pos = pos($prototype);
126 42         90 my $after = $comment =~ /<!--\s*end/;
127              
128             # locate the position of the comment from the prototype in the page
129 42 100       91 $pos = $pos - length($comment) unless $after;
130 42         80 my $loc = $self->find_location($page, $prototype, $pos, $after);
131              
132 42 50       160 unless (defined $loc) {
133 0         0 $notfound ++;
134 0         0 $loc= 0;
135             }
136              
137             # substitute comment into page
138 42 100       97 $comment = $after ? "\n$comment" : "$comment\n";
139 42         98 push(@output, substr($page, 0, $loc), $comment);
140 42         189 $page = substr($page, $loc);
141             }
142              
143 7         24 push(@output, $page);
144              
145 7 50       18 die "Could not locate tags\n" if $notfound;
146              
147 7         42 fio_write_page($file, join('', @output));
148 7         33 return;
149             }
150              
151             #----------------------------------------------------------------------
152             # Edit all files in the directory
153              
154             sub update_folder {
155 2     2 0 16 my ($self, $folder, $prototype_file, $prototype) = @_;
156              
157 2         31 my $index_file = $self->to_file($folder);
158 2         19 my $files = $self->{data}->build('files_by_mdate_reversed', $index_file);
159              
160 2 100       8 unless (defined $prototype_file) {
161 1 50       4 if (@$files) {
162 1         3 $prototype_file = shift(@$files);
163 1         7 $prototype = $self->strip_comments($prototype_file, 1);
164             }
165             }
166              
167 2         6 foreach my $file (@$files) {
168 7         16 eval {$self->update_file($file, $prototype)};
  7         21  
169 7         46 $self->check_error($@, $folder);
170             }
171              
172 2         21 my $folders = $self->{data}->build('folders', $index_file);
173 2         8 for my $subfolder (@$folders) {
174 1         7 $self->update_folder($subfolder, $prototype_file, $prototype);
175             }
176              
177 2         11 return;
178             }
179              
180             1;
181             __END__
182              
183             =encoding utf-8
184              
185             =head1 NAME
186              
187             App::Followme::EditSections - Edit the section tags on an html page
188              
189             =head1 SYNOPSIS
190              
191             use App::Followme::EditSection;
192             my $edit = App::Followme::EditSection->new();
193             $edit->run($directory);
194              
195             =head1 DESCRIPTION
196              
197             Followme distinguishes between sections of a web page which are the same across
198             the website and sections that differ between each page by html comments starting
199             with section and endsection. This module modifies the placement or number of these
200             tags across a website. It can also used to modify an existing website so it
201             can be maintained by followme. Before running followme with this module, edit a
202             page and put the section and endsection comments in the proper locations. Then
203             create a configuration file containing the name of this module. Then run followme
204             and it will modify all the pages of the website to include the same comments. Any
205             section and endsection tags that were previously in the file will be removed.
206              
207             =head1 CONFIGURATION
208              
209             The following field in the configuration file are used:
210              
211             =over 4
212              
213             =item remove_comments
214              
215             Remove all html comments that are in a file, not just the section and endsection
216             tags.
217              
218             =item data_pkg
219              
220             The package used to retrieve information from each file. The default value is
221             'App::Followme::WebData'.
222              
223             =back
224              
225             =head1 LICENSE
226              
227             Copyright (C) Bernie Simon.
228              
229             This library is free software; you can redistribute it and/or modify
230             it under the same terms as Perl itself.
231              
232             =head1 AUTHOR
233              
234             Bernie Simon E<lt>bernie.simon@gmail.comE<gt>
235              
236             =cut