File Coverage

blib/lib/File/is.pm
Criterion Covered Total %
statement 50 50 100.0
branch 14 16 87.5
condition 3 3 100.0
subroutine 26 26 100.0
pod 10 10 100.0
total 103 105 98.1


line stmt bran cond sub pod time code
1             package File::is;
2              
3             =head1 NAME
4              
5             File::is - file is older? oldest? is newer? newest? similar? the same?
6              
7             =cut
8              
9 1     1   64920 use warnings;
  1         2  
  1         30  
10 1     1   5 use strict;
  1         1  
  1         26  
11              
12             our $VERSION = '0.04';
13              
14 1     1   4 use Carp 'confess';
  1         1  
  1         34  
15 1     1   4 use File::Spec;
  1         1  
  1         610  
16              
17             #my $stat_mode = 2;
18             #my $stat_nlink = 3;
19             #my $stat_uid = 4;
20             #my $stat_gid = 5;
21             #my $stat_rdev = 6;
22             #my $stat_atime = 8;
23             #my $stat_ctime = 10;
24             #my $stat_blksize = 11;
25             #my $stat_blocks = 12;
26              
27             my $stat_dev = 0;
28             my $stat_ino = 1;
29             my $stat_size = 7;
30             my $stat_mtime = 9;
31              
32             =head1 SYNOPSIS
33              
34             use File::is;
35              
36             # return if F is newer than F or F.
37             return
38             if File::is->newer('file1', 'file2', 'file3');
39              
40             # do something if F is older than F or F.
41             do_some_work()
42             if File::is->older([ 'path1', 'file1'], 'file2', [ 'path3', 'file3' ]);
43              
44             =head1 DESCRIPTION
45              
46             This module is a result of /me not wanting to write:
47              
48             if ($(stat('filename'))[9] < $(stat('tmp/other-filename'))[9]) { do_someting(); };
49              
50             Instead I wrote a module with ~80 lines of code and ~90 lines of tests
51             for it... So how is the module different from the above C? Should be
52             reusable, has more functionality, should be clear from the code it self
53             what the condition is doing and was fun to play with it. Another advantage
54             is that the file names can be passed as array refs. In this case
55             L is used to construct the filename. The resulting code
56             is:
57              
58             if (File::is->older('filename', [ 'tmp', 'other-filename' ])) { do_something(); };
59              
60             =head1 FUNCTIONS
61              
62             =head2 newer($primary_filename, $other_filename, $other_filename2, ...)
63              
64             Returns true/false if the C<$primary_filename> is newer (has modification
65             time-stamp recent) then any of the rest passed as argument.
66              
67             =head2 newest($primary_filename, $other_filename, $other_filename2, ...)
68              
69             Returns true/false if the C<$primary_filename> is newest (has the biggest
70             modification time-stamp) compared to the rest of the passed filenames.
71              
72             =head2 older($primary_filename, $other_filename, $other_filename2, ...)
73              
74             Returns true/false if the C<$primary_filename> is older (has the later
75             modification time-stamp) then any of the rest passed as argument.
76              
77             =head2 oldest($primary_filename, $other_filename, $other_filename2, ...)
78              
79             Returns true/false if the C<$primary_filename> is oldest (has the latest
80             modification time-stamp) compared to the rest of the passed filenames.
81              
82             =head2 similar($primary_filename, $other_filename, $other_filename2, ...)
83              
84             Returns true/false if the C<$primary_filename> has the same size and modification
85             time-stamp than any of the rest of the passed filenames.
86              
87             =head2 thesame($primary_filename, $other_filename, $other_filename2, ...)
88              
89             Returns true/false if the C<$primary_filename> has the same inode and dev
90             (is hard link) to any of the rest of the passed filenames.
91              
92             NOTE: see L, L
93              
94             =head2 bigger($primary_filename, $other_filename, $other_filename2, ...)
95              
96             Returns true/false if the C<$primary_filename> is bigger (has the bigger
97             size) then any of the rest passed as argument.
98              
99             =head2 biggest($primary_filename, $other_filename, $other_filename2, ...)
100              
101             Returns true/false if the C<$primary_filename> is biggest (has the biggest
102             size) compared to the rest of the passed filenames.
103              
104             =head2 smaller($primary_filename, $other_filename, $other_filename2, ...)
105              
106             Returns true/false if the C<$primary_filename> is smaller (has the smaller
107             size) then any of the rest passed as argument.
108              
109             =head2 smallest($primary_filename, $other_filename, $other_filename2, ...)
110              
111             Returns true/false if the C<$primary_filename> is smallest (has the smallest
112             size) compared to the rest of the passed filenames.
113              
114             =cut
115              
116             sub newer {
117 6     6 1 31 return shift->_cmp_stat(1, sub { $_[0]->[$stat_mtime] > $_[1]->[$stat_mtime] }, @_);
  5     5   1477  
118             }
119              
120             sub newest {
121 4     4 1 19 return shift->_cmp_stat(0, sub { $_[0]->[$stat_mtime] <= $_[1]->[$stat_mtime] }, @_);
  3     3   17  
122             }
123              
124             sub older {
125 2     2 1 9 return shift->_cmp_stat(1, sub { $_[0]->[$stat_mtime] < $_[1]->[$stat_mtime] }, @_);
  3     3   38  
126             }
127              
128             sub oldest {
129 5     5 1 19 return shift->_cmp_stat(0, sub { $_[0]->[$stat_mtime] >= $_[1]->[$stat_mtime] }, @_);
  3     3   14  
130             }
131              
132             sub similar {
133             return shift->_cmp_stat(
134             1,
135             sub {
136 2 100   2   14 $_[0]->[$stat_size] == $_[1]->[$stat_size]
137             and $_[0]->[$stat_mtime] == $_[1]->[$stat_mtime];
138             },
139             @_
140 2     2 1 11 );
141             }
142              
143             sub thesame {
144 4 50   4 1 344 confess 'unsupported on MSWin32 (see http://perlmonks.org/?node_id=859612)'
145             if $^O eq 'MSWin32';
146            
147             return shift->_cmp_stat(1, sub {
148 4 100   4   45 ($_[0]->[$stat_ino] == $_[1]->[$stat_ino])
149             && ($_[0]->[$stat_dev] == $_[1]->[$stat_dev])
150 4         20 }, @_);
151             }
152              
153             sub bigger {
154 3     3 1 12 return shift->_cmp_stat(1, sub { $_[0]->[$stat_size] > $_[1]->[$stat_size] }, @_);
  2     2   10  
155             }
156              
157             sub biggest {
158 3     3 1 12 return shift->_cmp_stat(0, sub { $_[0]->[$stat_size] <= $_[1]->[$stat_size] }, @_);
  2     2   15  
159             }
160              
161             sub smaller {
162 3     3 1 12 return shift->_cmp_stat(1, sub { $_[0]->[$stat_size] < $_[1]->[$stat_size] }, @_);
  2     2   11  
163             }
164              
165             sub smallest {
166 3     3 1 11 return shift->_cmp_stat(0, sub { $_[0]->[$stat_size] >= $_[1]->[$stat_size] }, @_);
  2     2   9  
167             }
168              
169             =head1 INTERNALS
170              
171             Call/use at your own risk ;-)
172              
173             =head2 _construct_filename()
174              
175             Accepts one or more arguments. It passes them to C<catfile()>>
176             dereferencing the array if one argument array ref is passed.
177              
178             Example:
179              
180             _construct_filename('file') => 'file'
181             _construct_filename([ 'folder', 'file' ]) => File::Spec->catfile('folder', 'file');
182             _construct_filename('folder', 'file') => File::Spec->catfile('folder', 'file');
183              
184             This function is called on every argument passed to cmp methods
185             (newer, smaller, older, ...).
186              
187             =cut
188              
189             sub _construct_filename {
190 68 100   68   1143 confess 'need at least one argument'
191             if @_ == 0;
192            
193 67 100 100     194 return File::Spec->catfile(@{$_[0]})
  4         35  
194             if ((@_ == 1) and (ref $_[0] eq 'ARRAY'));
195            
196 63         291 return File::Spec->catfile(@_);
197             }
198              
199             =head2 _cmp_stat($class, $return_value_if_match, $cmp_function, $primary_filename, $other_filename, $other_filename2, ...)
200              
201             This function is called by all of the public C, C, C,
202             ... methods do loop through files and do some cmp on them.
203              
204             =cut
205              
206             sub _cmp_stat {
207 28     28   50 my $class = shift;
208 28         31 my $return = shift;
209 28         35 my $cmp_func = shift;
210 28         37 my $file1 = _construct_filename(shift);
211 28         60 my @files = @_;
212            
213 28         279 my @file1_stat = stat $file1;
214 28 50       61 confess 'file "'.$file1.'" not reachable'
215             if not @file1_stat;
216              
217 28         49 foreach my $file (@files) {
218 36         56 $file = _construct_filename($file);
219 36         215 my @file_stat = stat $file;
220 36 100       81 confess 'file "'.$file.'" not reachable'
221             if not @file_stat;
222              
223             # return success if condition is met
224 35 100       60 return $return
225             if $cmp_func->(\@file1_stat, \@file_stat);
226             }
227              
228             # no file was newer
229 12         47 return not $return;
230             }
231              
232             'sleeeeeeeeeeep';
233              
234             __END__