File Coverage

blib/lib/File/Monitor/Simple.pm
Criterion Covered Total %
statement 59 59 100.0
branch 7 10 70.0
condition 3 6 50.0
subroutine 11 11 100.0
pod 2 2 100.0
total 82 88 93.1


line stmt bran cond sub pod time code
1             package File::Monitor::Simple;
2              
3 1     1   31465 use strict;
  1         2  
  1         37  
4 1     1   5 use warnings;
  1         3  
  1         29  
5 1     1   6 use base 'Class::Accessor::Fast';
  1         6  
  1         894  
6 1     1   4682 use File::Find::Rule;
  1         9304  
  1         10  
7 1     1   996 use File::Modified;
  1         3437  
  1         33  
8 1     1   7 use File::Spec;
  1         2  
  1         23  
9              
10 1     1   6 use vars '$VERSION';
  1         3  
  1         584  
11              
12             $VERSION = '1.00';
13              
14             __PACKAGE__->mk_accessors(
15             qw/directory
16             modified
17             regex
18             watch_list
19             /
20             );
21              
22             # directory : scalar location to monitor
23             # modified : File::Modified object with current state
24             # regex : File pattern to monitor. Really a string a not "qr"
25             # watch_list : hashref of monitored files. Keys are names. Values are "1"
26              
27              
28             sub new {
29 1     1 1 19 my ( $class, %args ) = @_;
30              
31 1         4 my $self = {%args};
32              
33 1         4 bless $self, $class;
34              
35 1         4 $self->_init;
36              
37 1         92 return $self;
38             }
39              
40             sub _init {
41 3     3   4 my $self = shift;
42              
43 3         10 my $watch_list = $self->_index_directory;
44 3         14 $self->watch_list($watch_list);
45              
46 3         22 $self->modified(
47             File::Modified->new(
48             # mtime works on directories, while 'MD5' doesn't
49             method => 'mtime',
50 3         20 files => [ keys %{$watch_list} ],
51             )
52             );
53             }
54              
55             sub watch {
56 8     8 1 4107 my $self = shift;
57              
58 8         11 my @changes;
59             my @changed_files;
60            
61 8         11 eval { @changes = $self->modified->changed };
  8         23  
62 8 100       410 if ($@) {
63             # warn "error: $@";
64             # File::Modified will die if a file is deleted.
65 1         8 my ($deleted_file) = $@ =~ /stat '(.+)'/;
66 1   50     5 push @changed_files, $deleted_file || 'unknown file';
67              
68             # re-scan to remove the deleted file
69 1         4 $self->_init;
70             }
71              
72 8 100       87 if (@changes) {
73             # update all mtime information
74 1         4 $self->modified->update;
75              
76             # check if any files were changed
77 1 50       28 @changed_files = grep { defined $_ && -f $_ } @changes;
  1         17  
78              
79             # Check if only directories were changed. This means
80             # a new file was created.
81 1 50       3 if (@changed_files) {
82             # We found some changed files.
83             # Don't bother to look for added files, too.
84             }
85             else {
86              
87             # look through the new list for new files
88 1         4 my $old_watch = $self->watch_list;
89              
90             # re-index to find new files
91 1         7 $self->_init;
92              
93 1         123 @changed_files = grep { !defined $old_watch->{$_} } keys %{ $self->watch_list };
  2         14  
  1         7  
94              
95 1 50       5 return unless @changed_files;
96             }
97             }
98             else {
99             # no changes found;
100             }
101              
102 8         26 return @changed_files;
103              
104             }
105              
106             # =begin private
107             #
108             # =head2 _index_directory()
109             #
110             # $self->_index_directory;
111             #
112             # Looks in $self->directory and compares all files to $self->regex.
113             # Matched files are registered for monitoring.
114             #
115             # =end private
116             #
117             # =cut
118              
119             sub _index_directory {
120 3     3   4 my $self = shift;
121              
122 3   50     13 my $dir = $self->directory || die "No directory specified";
123 3   50     38 my $regex = $self->regex || '\.pm$';
124              
125             # Find all the directories in this directory, as well as any files matching the regex
126 3         129 my $iterator = File::Find::Rule->any(
127             File::Find::Rule->file->name(qr/$regex/),
128             File::Find::Rule->directory,
129             )->start( $dir );
130              
131 3         8749 my %list;
132 3         14 while ( my $match = $iterator->match ) {
133 4         51 $list{$match} = 1
134             }
135              
136 3         55 return \%list;
137             }
138              
139             1;
140             __END__