File Coverage

blib/lib/Directory/Scanner/Stream/Recursive.pm
Criterion Covered Total %
statement 66 69 95.6
branch 10 14 71.4
condition 2 5 40.0
subroutine 14 15 93.3
pod 1 7 14.2
total 93 110 84.5


line stmt bran cond sub pod time code
1             package Directory::Scanner::Stream::Recursive;
2             # ABSTRACT: Recrusive streaming directory iterator
3              
4 7     7   36 use strict;
  7         13  
  7         154  
5 7     7   25 use warnings;
  7         11  
  7         121  
6              
7 7     7   26 use Carp ();
  7         8  
  7         65  
8 7     7   24 use Scalar::Util ();
  7         10  
  7         295  
9              
10             our $VERSION = '0.04';
11             our $AUTHORITY = 'cpan:STEVAN';
12              
13 7   50 7   30 use constant DEBUG => $ENV{DIR_SCANNER_STREAM_RECURSIVE_DEBUG} // 0;
  7         12  
  7         449  
14              
15             ## ...
16              
17 7     7   42 use parent 'UNIVERSAL::Object';
  7         10  
  7         37  
18 7     7   350 use roles 'Directory::Scanner::API::Stream';
  7         11  
  7         26  
19             use slots (
20             stream => sub {},
21             # internal state ...
22             _head => sub {},
23 13         33 _stack => sub { [] },
24 13         38 _is_done => sub { 0 },
25 13         41 _is_closed => sub { 0 },
26 7     7   2534 );
  7         12  
  7         96  
27              
28             ## ...
29              
30             sub BUILD {
31 13     13 1 295 my ($self, $params) = @_;
32              
33 13         34 my $stream = $self->{stream};
34              
35 13 50 33     79 (Scalar::Util::blessed($stream) && $stream->roles::DOES('Directory::Scanner::API::Stream'))
36             || Carp::confess 'You must supply a directory stream';
37              
38 13         2258 push @{$self->{_stack}} => $stream;
  13         42  
39             }
40              
41             sub clone {
42 0     0 0 0 my ($self, $dir) = @_;
43 0         0 return $self->new( stream => $self->{stream}->clone( $dir ) );
44             }
45              
46             ## accessor
47              
48 48     48 0 2472 sub head { $_[0]->{_head} }
49              
50 44     44 0 8993 sub is_done { $_[0]->{_is_done} }
51 36     36 0 1918 sub is_closed { $_[0]->{_is_closed} }
52              
53             sub close {
54 13     13 0 304 my $self = $_[0];
55 13         21 while ( my $stream = pop @{ $self->{_stack} } ) {
  13         60  
56 0         0 $stream->close;
57             }
58 13         29 $self->{_is_closed} = 1;
59 13         30 return;
60             }
61              
62             sub next {
63 105     105 0 6841 my $self = $_[0];
64              
65 105 50       186 return if $self->{_is_done};
66              
67             Carp::confess 'Cannot call `next` on a closed stream'
68 105 50       178 if $self->{_is_closed};
69              
70 105         113 my $next;
71 105         120 while (1) {
72 163         488 undef $next; # clear any previous values, just cause ...
73 163         174 $self->_log('Entering loop ... ') if DEBUG;
74              
75 163 100       323 if ( my $current = $self->{_stack}->[-1] ) {
76 150         150 $self->_log('Stream available in stack') if DEBUG;
77 150 100       294 if ( my $candidate = $current->next ) {
78             # if we have a directory, prepare
79             # to recurse into it the next time
80             # we are called, then ....
81 92 100       219 if ( $candidate->is_dir ) {
82 45         600 push @{$self->{_stack}} => $current->clone( $candidate );
  45         142  
83             }
84              
85             # return our successful candidate
86 92         841 $next = $candidate;
87 92         142 last;
88             }
89             else {
90 58         64 $self->_log('Current stream has been exhausted, moving to next') if DEBUG;
91              
92             # something, something, ... check is_done on $current here ...
93              
94 58         65 my $old = pop @{$self->{_stack}};
  58         97  
95 58 50       131 $old->close unless $old->is_closed;
96 58         199 next;
97             }
98             }
99             else {
100 13         20 $self->_log('No more streams available in stack') if DEBUG;
101 13         21 $self->_log('Exiting loop ... DONE') if DEBUG;
102              
103 13         28 $self->{_head} = undef;
104 13         19 $self->{_is_done} = 1;
105 13         19 last;
106             }
107             }
108              
109 105         278 return $self->{_head} = $next;
110             }
111              
112             1;
113              
114             __END__