38 / 41 lines covered (92.7%)
1unit module BDD::Behave::Watch::Watcher;23our class Snapshot {4 has Instant $.mtime is required;5 has Int $.size is required;6}78our class Change {9 has IO::Path $.path is required;10 has Str $.kind is required;11}1213our class Watcher {14 has IO::Path @.paths;15 has Mu $.match = / [ '.rakumod' | '.raku' | '.rakutest' | '.pm6' ] $ /;16 has %!snapshots;17 has Bool $!initialized = False;1819 method add-path(IO::Path $path) {20 @!paths.push: $path;21 $!initialized = False;22 self;23 }2425 method scan-files(--> Seq) {26 gather for @!paths -> $root {27 next unless $root.e;28 if $root.f {29 take $root;30 } elsif $root.d {31 self!walk-dir($root);32 }33 }34 }3536 method !walk-dir(IO::Path $dir) {37 for $dir.dir -> $entry {38 next if $entry.basename eq '.precomp' | '.git';39 if $entry.f {40 take $entry if !$.match.defined || $entry.basename ~~ $.match;41 } elsif $entry.d {42 self!walk-dir($entry);43 }44 }45 }4647 method !current-snapshots(--> Hash) {48 my %snap;49 for self.scan-files() -> $file {50 next unless $file.e;51 my $key = $file.absolute;52 %snap{$key} = Snapshot.new(53 :mtime($file.modified),54 :size($file.s),55 );56 }57 %snap;58 }5960 method initialize() {61 %!snapshots = self!current-snapshots();62 $!initialized = True;63 self;64 }6566 method poll(--> List) {67 self.initialize unless $!initialized;68 my %current = self!current-snapshots();69 my @changes;7071 for %current.kv -> $path, $snap {72 my $prev = %!snapshots{$path};73 if !$prev.defined {74 @changes.push: Change.new(:path($path.IO), :kind('added'));75 } elsif $prev.mtime != $snap.mtime || $prev.size != $snap.size {76 @changes.push: Change.new(:path($path.IO), :kind('modified'));77 }78 }7980 for %!snapshots.keys -> $path {81 next if %current{$path}:exists;82 @changes.push: Change.new(:path($path.IO), :kind('removed'));83 }8485 %!snapshots = %current;86 @changes.List;87 }8889 method tracked-count(--> Int) {90 %!snapshots.elems;91 }92}