File Coverage

lib/Functional/Iterator.pm
Criterion Covered Total %
statement 40 40 100.0
branch 18 18 100.0
condition n/a
subroutine 7 7 100.0
pod 4 4 100.0
total 69 69 100.0


line stmt bran cond sub pod time code
1 2     2   62389 use strict;
  2         4  
  2         65  
2 2     2   10 use warnings;
  2         2  
  2         92  
3              
4             package Functional::Iterator;
5 2     2   11 use base qw(Exporter);
  2         9  
  2         1168  
6              
7             our @EXPORT = qw(iterator);
8              
9             our $VERSION = 1.05;
10              
11 17     17 1 2733 sub iterator { __PACKAGE__->new(@_) }
12              
13             sub new {
14 17     17 1 44 my ($class, %args) = @_;
15 17         134 return bless +{
16             %args,
17             index => 0,
18             }, $class;
19             }
20              
21             sub next {
22 249     249 1 2797 my ($self) = @_;
23              
24 249         244 my $record;
25 249         327 my $index = $self->{index};
26              
27 249 100       605 if (exists $self->{generated_record}) {
    100          
28             # If the previous call to ->next() yielded an iterator, then we stashed that
29             # iterator into $self->{generated_record} and returned that stashed iterator's
30             # ->next record. Now it's time to ask that stashed previously-generated-but
31             # now-active iterator for another record.
32 40         70 $record = delete $self->{generated_record};
33             } elsif (exists $self->{generator}) {
34             # We have no current stashed iterator: either our generator doesn't produce
35             # iterators, or the last iterator it produced has been exhausted.
36 20         63 $record = $self->{generator}->();
37             } else {
38             # Oh, we're just a simple iterator over records, how nice.
39 189         306 $record = $self->{records}[$index];
40             }
41              
42 249 100       816 if (UNIVERSAL::isa($record, ref($self))) {
43 101 100       242 $self->{generated_record} = $record # The putative $record is actually an iterator, so stash it away...
44             if exists $self->{generator}; # ...(maybe)...
45 101         201 $record = $record->next; # ...and ask it for its next record.
46              
47 101 100       215 if (! defined($record)) { # Whoops, the stashed-away iterator is exhausted...
48 14 100       48 if (exists $self->{records}[$index + 1]) { # Simple iterator-over-records case
49 5         21 $self->{index}++;
50 5         11 return $self->next;
51             } else { # Oh, there's no next record available: why not?
52 9 100       22 if (exists $self->{generator}) { # ...because we're an iterator over generated iterators.
53 5         25 delete $self->{generated_record}; # ...Okay, discard this iterator (it's clearly exhausted)
54 5         11 return $self->next; # ...and ask myself for another
55             } else { # ...because we're an iterator over records
56 4         11 return undef; # ...but there is no next record, so signal exhaustion
57             }
58             }
59             }
60             } else {
61 148         260 $self->{index}++;
62             }
63 235 100       493 return undef unless defined $record;
64              
65 217 100       611 return $self->{mutator}
66             ? $self->{mutator}->($record)
67             : $record;
68             }
69              
70             sub reset {
71 3     3 1 688 my ($self) = @_;
72 3         5 $self->{index} = 0;
73 3         4 delete $self->{generated_record};
74 3         5 foreach (grep { UNIVERSAL::isa($_, __PACKAGE__) } @{$self->{records}}) {
  38         118  
  3         6  
75 2         7 $_->reset;
76             }
77             }
78              
79             1;
80              
81             __END__