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   13049 use strict;
  1         2  
  1         21  
4 1     1   3 use warnings;
  1         1  
  1         23  
5 1     1   3 use base 'Class::Accessor::Fast';
  1         3  
  1         437  
6 1     1   2502 use File::Find::Rule;
  1         5671  
  1         5  
7 1     1   446 use File::Modified;
  1         1900  
  1         24  
8 1     1   4 use File::Spec;
  1         1  
  1         15  
9              
10 1     1   3 use vars '$VERSION';
  1         1  
  1         352  
11              
12             $VERSION = '0.99_1';
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 12 my ( $class, %args ) = @_;
30              
31 1         4 my $self = {%args};
32              
33 1         1 bless $self, $class;
34              
35 1         3 $self->_init;
36              
37 1         74 return $self;
38             }
39              
40             sub _init {
41 3     3   4 my $self = shift;
42              
43 3         4 my $watch_list = $self->_index_directory;
44 3         7 $self->watch_list($watch_list);
45              
46             $self->modified(
47             File::Modified->new(
48             # mtime works on directories, while 'MD5' doesn't
49             method => 'mtime',
50 3         12 files => [ keys %{$watch_list} ],
  3         18  
51             )
52             );
53             }
54              
55             sub watch {
56 8     8 1 2752 my $self = shift;
57              
58 8         8 my @changes;
59             my @changed_files;
60            
61 8         12 eval { @changes = $self->modified->changed };
  8         14  
62 8 100       269 if ($@) {
63             # warn "error: $@";
64             # File::Modified will die if a file is deleted.
65 1         7 my ($deleted_file) = $@ =~ /stat '(.+)'/;
66 1   50     4 push @changed_files, $deleted_file || 'unknown file';
67              
68             # re-scan to remove the deleted file
69 1         2 $self->_init;
70             }
71              
72 8 100       54 if (@changes) {
73             # update all mtime information
74 1         3 $self->modified->update;
75              
76             # check if any files were changed
77 1 50       16 @changed_files = grep { defined $_ && -f $_ } @changes;
  1         9  
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         2 my $old_watch = $self->watch_list;
89              
90             # re-index to find new files
91 1         4 $self->_init;
92              
93 1         66 @changed_files = grep { !defined $old_watch->{$_} } keys %{ $self->watch_list };
  2         8  
  1         4  
94              
95 1 50       19 return unless @changed_files;
96             }
97             }
98             else {
99             # no changes found;
100             }
101              
102 8         20 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     6 my $dir = $self->directory || die "No directory specified";
123 3   50     23 my $regex = $self->regex || '\.pm$';
124              
125             # Find all the directories in this directory, as well as any files matching the regex
126 3         76 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         1937 my %list;
132 3         8 while ( my $match = $iterator->match ) {
133 4         34 $list{$match} = 1
134             }
135              
136 3         34 return \%list;
137             }
138              
139             1;
140             __END__