File Coverage

blib/lib/PFT/Content/Entry.pm
Criterion Covered Total %
statement 76 87 87.3
branch 18 28 64.2
condition 4 11 36.3
subroutine 17 18 94.4
pod 6 6 100.0
total 121 150 80.6


line stmt bran cond sub pod time code
1             # Copyright 2014-2016 - Giovanni Simoni
2             #
3             # This file is part of PFT.
4             #
5             # PFT is free software: you can redistribute it and/or modify it under the
6             # terms of the GNU General Public License as published by the Free
7             # Software Foundation, either version 3 of the License, or (at your
8             # option) any later version.
9             #
10             # PFT is distributed in the hope that it will be useful, but WITHOUT ANY
11             # WARRANTY; without even the implied warranty of MERCHANTABILITY or
12             # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with PFT. If not, see .
17             #
18             package PFT::Content::Entry v1.3.0;
19              
20             =encoding utf8
21              
22             =head1 NAME
23              
24             PFT::Content::Entry - Content edited by user.
25              
26             =head1 SYNOPSIS
27              
28             use PFT::Content::Entry;
29              
30             my $p = PFT::Content::Entry->new({
31             tree => $tree,
32             path => $path,
33             name => $name,
34             })
35              
36             =head1 DESCRIPTION
37              
38             C is the basetype for all text-based content files.
39             It inherits from C and has two specific subtypes:
40             C (representing an entry with date) and
41             C (representing an entry withouth date).
42              
43             =back
44              
45             =head2 Methods
46              
47             =over
48              
49             =cut
50              
51 6     6   3421 use utf8;
  6         18  
  6         27  
52 6     6   196 use v5.16;
  6         17  
53 6     6   29 use strict;
  6         10  
  6         105  
54 6     6   38 use warnings;
  6         12  
  6         208  
55              
56 6     6   418 use parent 'PFT::Content::File';
  6         357  
  6         29  
57              
58 6     6   2904 use PFT::Header;
  6         18  
  6         212  
59 6     6   52 use PFT::Date;
  6         12  
  6         118  
60              
61 6     6   32 use Encode;
  6         13  
  6         561  
62 6     6   35 use Encode::Locale;
  6         11  
  6         192  
63              
64 6     6   32 use File::Spec;
  6         11  
  6         145  
65 6     6   32 use Carp;
  6         12  
  6         4453  
66              
67             =item open
68              
69             Open the file, return a file handler. Sets the binmode according to the
70             locale.
71              
72             =cut
73              
74             sub open {
75 144     144 1 2676 my $self = shift;
76 144         475 my $out = $self->SUPER::open(@_);
77 3     3   27 binmode $out, 'encoding(locale)';
  3         6  
  3         23  
  144         17550  
78 144         9449 $out;
79             }
80              
81             =item header
82              
83             Reads the header from the page.
84              
85             Returns undef if the entry is not backed by a file. Croaks if the file
86             does not contain a healty header.
87              
88             =cut
89              
90             sub header {
91 62     62 1 2953 my $self = shift;
92 62 100       243 return undef unless $self->exists;
93 61 100       176 eval { PFT::Header->load($self->open('r')) }
  61         179  
94             or croak $@ =~ s/ at .*$//rs;
95             }
96              
97             =item read
98              
99             Read the page.
100              
101             In scalar context returns an open file descriptor configured with the
102             correct C according to the header. In list context returns the
103             header and the same descriptor. Returns C if the file does not exist.
104              
105             Croaks if the header is broken.
106              
107             =cut
108              
109             sub read {
110 22     22 1 1368 my $self = shift;
111              
112 22 100       70 return undef unless $self->exists;
113 21         83 my $fh = $self->open('r');
114              
115             # We read the header even if not required by the caller, since this
116             # moves the cursor of the file descriptor. This allows the header to be
117             # skipped and only the text to be returned.
118 21 100       38 my $h = eval { PFT::Header->load($fh) }
  21         100  
119             or croak $@ =~ s/ at .*$//rs;
120              
121 20 100       104 wantarray ? ($h, $fh) : $fh;
122             }
123              
124             =item void
125              
126             Evaluates as true if the entry is void, that is if the file does not exist,
127             or if it contains only the header.
128              
129             =cut
130              
131             sub void {
132 0     0 1 0 my($h, $fh) = shift->read;
133 0 0       0 return 1 unless defined $h;
134              
135 0         0 local $_;
136 0         0 while (<$fh>) {
137 0 0       0 /\S/ and return ''; # a non-whitespace exists.
138             }
139              
140             1 # No content found.
141 0         0 }
142              
143             =item set_header
144              
145             Sets a new header, passed by parameter.
146              
147             This will rewrite the file. Content will be maintained.
148              
149             =cut
150              
151             sub set_header {
152 3     3 1 16 my $self = shift;
153 3         6 my $hdr = shift;
154              
155 3 50       29 $hdr->isa('PFT::Header')
156             or confess 'Must be PFT::Header';
157              
158 3         7 my @lines;
159 3 100 66     13 if ($self->exists && !$self->empty) {
160 2         14 my($old_hdr, $fh) = $self->read;
161 2         33 @lines = <$fh>;
162 2         34 close $fh;
163             }
164              
165 3         14 my $fh = $self->open('w');
166 3         16 $hdr->dump($fh);
167 3         1496 print $fh $_ foreach @lines;
168             }
169              
170             =item make_consistent
171              
172             Make page consistent with the filesystem tree.
173              
174             =cut
175              
176             sub make_consistent {
177              
178 1     1 1 15 my $self = shift;
179              
180 1         4 my $hdr = $self->header;
181 1         4 my($done, $rename);
182              
183 1         14 my $pdate = $self->tree->detect_date($self);
184 1 50       5 if (defined $pdate) {
185 1         5 my $hdt = $hdr->date;
186 1 50 33     6 if (defined($hdt) and defined($hdt->y) and defined($hdt->m)) {
      33        
187 1 50       4 $rename ++ if $hdt <=> $pdate; # else date is just fine.
188             } else {
189             # The header does not declare a date, we figure it out from the
190             # position in the filesystem and update it.
191 0         0 $hdr->set_date($pdate);
192 0         0 $self->set_header($hdr);
193 0         0 $done ++;
194             }
195             } # else not in blog.
196              
197 1 50       3 if ($hdr->slug ne $self->tree->detect_slug($self)) {
198 1         3 $rename ++;
199             }
200              
201 1 50       4 if ($rename) {
202 1         5 my $newpath = $self->tree->hdr_to_path($hdr);
203 1         27 while (-e $newpath) {
204 0   0     0 $newpath =~ s/(\d*)$/($1 || 0) + 1/e
  0         0  
205             }
206 1         13 $self->rename_as($newpath);
207 1         3 $done ++;
208             }
209              
210             $done
211 1         6 }
212              
213             =back
214              
215             =cut
216              
217             1;