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 3     3   753694 use warnings;
  3         27  
  3         416  
10 3     3   24 use strict;
  3         10  
  3         375  
11              
12             our $VERSION = '0.03';
13              
14 3     3   107 use Carp 'confess';
  3         12  
  3         430  
15 3     3   16 use File::Spec;
  3         11  
  3         1248  
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 41 return shift->_cmp_stat(1, sub { $_[0]->[$stat_mtime] > $_[1]->[$stat_mtime] }, @_);
  5     5   2422  
118             }
119              
120             sub newest {
121 4     4 1 28 return shift->_cmp_stat(0, sub { $_[0]->[$stat_mtime] <= $_[1]->[$stat_mtime] }, @_);
  3     3   17  
122             }
123              
124             sub older {
125 2     2 1 14 return shift->_cmp_stat(1, sub { $_[0]->[$stat_mtime] < $_[1]->[$stat_mtime] }, @_);
  3     3   1251  
126             }
127              
128             sub oldest {
129 5     5 1 34 return shift->_cmp_stat(0, sub { $_[0]->[$stat_mtime] >= $_[1]->[$stat_mtime] }, @_);
  3     3   18  
130             }
131              
132             sub similar {
133             return shift->_cmp_stat(
134             1,
135             sub {
136 2 100   2   24 $_[0]->[$stat_size] == $_[1]->[$stat_size]
137             and $_[0]->[$stat_mtime] == $_[1]->[$stat_mtime];
138             },
139             @_
140 2     2 1 26 );
141             }
142              
143             sub thesame {
144 4 50   4 1 494 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   46 ($_[0]->[$stat_ino] == $_[1]->[$stat_ino])
149             && ($_[0]->[$stat_dev] == $_[1]->[$stat_dev])
150 4         25 }, @_);
151             }
152              
153             sub bigger {
154 3     3 1 23 return shift->_cmp_stat(1, sub { $_[0]->[$stat_size] > $_[1]->[$stat_size] }, @_);
  2     2   16  
155             }
156              
157             sub biggest {
158 3     3 1 21 return shift->_cmp_stat(0, sub { $_[0]->[$stat_size] <= $_[1]->[$stat_size] }, @_);
  2     2   14  
159             }
160              
161             sub smaller {
162 3     3 1 20 return shift->_cmp_stat(1, sub { $_[0]->[$stat_size] < $_[1]->[$stat_size] }, @_);
  2     2   13  
163             }
164              
165             sub smallest {
166 3     3 1 21 return shift->_cmp_stat(0, sub { $_[0]->[$stat_size] >= $_[1]->[$stat_size] }, @_);
  2     2   14  
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   2117 confess 'need at least one argument'
191             if @_ == 0;
192            
193 67 100 100     324 return File::Spec->catfile(@{$_[0]})
  4         96  
194             if ((@_ == 1) and (ref $_[0] eq 'ARRAY'));
195            
196 63         460 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   44 my $class = shift;
208 28         34 my $return = shift;
209 28         32 my $cmp_func = shift;
210 28         57 my $file1 = _construct_filename(shift);
211 28         71 my @files = @_;
212            
213 28         735 my @file1_stat = stat $file1;
214 28 50       82 confess 'file "'.$file1.'" not reachable'
215             if not @file1_stat;
216              
217 28         52 foreach my $file (@files) {
218 36         73 $file = _construct_filename($file);
219 36         801 my @file_stat = stat $file;
220 36 100       121 confess 'file "'.$file.'" not reachable'
221             if not @file_stat;
222              
223             # return success if condition is met
224 35 100       94 return $return
225             if $cmp_func->(\@file1_stat, \@file_stat);
226             }
227              
228             # no file was newer
229 12         113 return not $return;
230             }
231              
232             'sleeeeeeeeeeep';
233              
234             __END__