File Coverage

blib/lib/PFT/Content/File.pm
Criterion Covered Total %
statement 72 74 97.3
branch 9 14 64.2
condition n/a
subroutine 24 26 92.3
pod 10 11 90.9
total 115 125 92.0


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::File v1.3.0;
19              
20             =encoding utf8
21              
22             =head1 NAME
23              
24             PFT::Content::File - On disk content file.
25              
26             =head1 SYNOPSIS
27              
28             use PFT::Content::File;
29              
30             my $f1 = PFT::Content::File->new({
31             tree => $tree,
32             path => $path,
33             name => $name, # optional, defaults to basename($path)
34             });
35              
36             =cut
37              
38 6     6   2539 use utf8;
  6         12  
  6         28  
39 6     6   192 use v5.16;
  6         48  
40 6     6   33 use strict;
  6         11  
  6         127  
41 6     6   30 use warnings;
  6         10  
  6         249  
42              
43 6     6   36 use File::Path qw/make_path/;
  6         10  
  6         358  
44 6     6   43 use File::Basename qw/basename dirname/;
  6         20  
  6         349  
45 6     6   44 use File::Spec;
  6         12  
  6         180  
46              
47 6     6   2864 use IO::File;
  6         36460  
  6         655  
48 6     6   485 use Encode::Locale;
  6         14934  
  6         199  
49 6     6   33 use Encode;
  6         11  
  6         385  
50 6     6   36 use Carp;
  6         10  
  6         294  
51              
52 6     6   34 use parent 'PFT::Content::Base';
  6         11  
  6         66  
53              
54             use overload
55             '""' => sub {
56 100     100   153 my $self = shift;
57 100         136 my($name, $path) = @{$self}{'name', 'path'};
  100         249  
58 100         579 ref($self) . "({name => \"$name\", path => \"$path\"})"
59             },
60             'cmp' => sub {
61 26     26   26245 my($self, $oth, $swap) = @_;
62 26         120 my $out = $self->{path} cmp $oth->{path};
63 26 50       356 $swap ? -$out : $out;
64             },
65 6     6   961 ;
  6         13  
  6         57  
66              
67             sub new {
68 133     133 0 1034 my $cls = shift;
69 133         193 my $params = shift;
70              
71 133 50       333 exists $params->{path} or confess 'Missing param: path';
72 133         230 my $path = $params->{path};
73 133 100       871 defined $params->{name} or $params->{name} = basename $path;
74 133         606 my $self = $cls->SUPER::new($params);
75              
76 133         2401 $self->{path} = File::Spec->rel2abs($path);
77 133         552 $self->{encpath} = encode(locale_fs => $path);
78 133         7466 $self
79             }
80              
81             =head1 DESCRIPTION
82              
83             This class describes a content file on disk.
84              
85             =head2 Properties
86              
87             Besides the properties following in this section, more are inherited from
88             C.
89              
90             =over
91              
92             =item path
93              
94             Absolute path of the file on the filesystem.
95              
96             =cut
97              
98 12     12 1 228 sub path { shift->{path} }
99              
100             =item encpath
101              
102             Absolute path, encoded with locale
103              
104             =cut
105              
106 243     243 1 5337 sub encpath { shift->{encpath} }
107              
108             =item filename
109              
110             Base name of the file
111              
112             =cut
113              
114 0     0 1 0 sub filename { basename shift->{path} }
115              
116             =item mtime
117              
118             Last modification time according to the filesystem.
119              
120             =cut
121              
122             sub mtime {
123 0     0 1 0 (stat shift->{encpath})[9];
124             }
125              
126             =item open
127              
128             Open a file descriptor for the file:
129              
130             $f->open # Read file descriptor
131             $f->open($mode) # Open with r|w|a mode
132              
133             This method does automatic error checking (confessing on error).
134              
135             =cut
136              
137             sub open {
138 148     148 1 328 my($self, $mode) = @_;
139              
140             # Regular behavior
141 148         289 my $encpath = $self->{encpath};
142 148 100       8007 make_path dirname $encpath if $mode =~ /w|a/;
143 148 50       983 IO::File->new($encpath, $mode)
144             or confess 'Cannot open "', $self->path, "\": $!"
145             }
146              
147             =item touch
148              
149             Change modification time on the filesytem to current timestamp.
150              
151             =cut
152              
153             sub touch {
154 2     2 1 8 shift->open('a')
155             }
156              
157             =item exists
158              
159             Verify if the file exists
160              
161             =cut
162              
163 240     240 1 543 sub exists { -e shift->encpath }
164              
165             =item empty
166              
167             Check if the file is empty
168              
169             =cut
170              
171 2     2 1 9 sub empty { -z shift->encpath }
172              
173             =item unlink
174              
175             =cut
176              
177             sub unlink {
178 1     1 1 11 my $self = shift;
179 1 50       3 unlink $self->encpath
180             or confess 'Cannot unlink "' . $self->path . "\": $!"
181             }
182              
183             =item rename_as
184              
185             Move the file in the filesystem, update internal data.
186              
187             =cut
188              
189             # TODO use the path property as setter instead?
190             sub rename_as {
191 1     1 1 4 my($self, $new_path) = @_;
192 1         4 my $enc_new_path = encode(locale_fs => $new_path);
193              
194 1         196 make_path dirname $enc_new_path;
195 1 50       56 rename $self->{encpath}, $enc_new_path
196             or confess "Cannot rename '$self->{path}' → '$new_path': $!";
197              
198 1         9 $self->tree->was_renamed($self->{path}, $new_path);
199 1         5 $self->{path} = $new_path;
200 1         6 $self->{encpath} = $enc_new_path;
201             }
202              
203             =back
204              
205             =cut
206              
207             1;