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.4.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   2482 use utf8;
  6         12  
  6         26  
39 6     6   185 use v5.16;
  6         40  
40 6     6   26 use strict;
  6         11  
  6         118  
41 6     6   27 use warnings;
  6         9  
  6         243  
42              
43 6     6   33 use File::Path qw/make_path/;
  6         16  
  6         336  
44 6     6   52 use File::Basename qw/basename dirname/;
  6         12  
  6         361  
45 6     6   39 use File::Spec;
  6         10  
  6         170  
46              
47 6     6   2812 use IO::File;
  6         35954  
  6         653  
48 6     6   493 use Encode::Locale;
  6         15394  
  6         197  
49 6     6   33 use Encode;
  6         13  
  6         339  
50 6     6   43 use Carp;
  6         10  
  6         268  
51              
52 6     6   42 use parent 'PFT::Content::Base';
  6         11  
  6         65  
53              
54             use overload
55             '""' => sub {
56 100     100   155 my $self = shift;
57 100         125 my($name, $path) = @{$self}{'name', 'path'};
  100         214  
58 100         574 ref($self) . "({name => \"$name\", path => \"$path\"})"
59             },
60             'cmp' => sub {
61 26     26   19407 my($self, $oth, $swap) = @_;
62 26         109 my $out = $self->{path} cmp $oth->{path};
63 26 50       341 $swap ? -$out : $out;
64             },
65 6     6   931 ;
  6         22  
  6         54  
66              
67             sub new {
68 133     133 0 1064 my $cls = shift;
69 133         194 my $params = shift;
70              
71 133 50       286 exists $params->{path} or confess 'Missing param: path';
72 133         196 my $path = $params->{path};
73 133 100       795 defined $params->{name} or $params->{name} = basename $path;
74 133         499 my $self = $cls->SUPER::new($params);
75              
76 133         1946 $self->{path} = File::Spec->rel2abs($path);
77 133         455 $self->{encpath} = encode(locale_fs => $path);
78 133         7027 $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 229 sub path { shift->{path} }
99              
100             =item encpath
101              
102             Absolute path, encoded with locale
103              
104             =cut
105              
106 243     243 1 5002 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 317 my($self, $mode) = @_;
139              
140             # Regular behavior
141 148         267 my $encpath = $self->{encpath};
142 148 100       6924 make_path dirname $encpath if $mode =~ /w|a/;
143 148 50       940 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 10 shift->open('a')
155             }
156              
157             =item exists
158              
159             Verify if the file exists
160              
161             =cut
162              
163 240     240 1 519 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 8 sub empty { -z shift->encpath }
172              
173             =item unlink
174              
175             =cut
176              
177             sub unlink {
178 1     1 1 12 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         195 make_path dirname $enc_new_path;
195 1 50       59 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         7 $self->{path} = $new_path;
200 1         8 $self->{encpath} = $enc_new_path;
201             }
202              
203             =back
204              
205             =cut
206              
207             1;