File Coverage

lib/UR/Iterator.pm
Criterion Covered Total %
statement 32 39 82.0
branch 7 10 70.0
condition n/a
subroutine 9 11 81.8
pod 5 6 83.3
total 53 66 80.3


line stmt bran cond sub pod time code
1             package UR::Iterator;
2              
3 266     266   950 use strict;
  266         310  
  266         6217  
4 266     266   821 use warnings;
  266         286  
  266         95798  
5              
6             our $VERSION = "0.46"; # UR $VERSION;
7              
8             our @CARP_NOT = qw( UR::Object );
9              
10             # These are not UR Objects. They're regular blessed references that
11             # get garbage collected in the regular ways
12              
13             sub create {
14 0     0 0 0 my $class = shift;
15 0         0 Carp::croak("$class objects cannot be created via create(). Please see the documentation for more details");
16             }
17              
18             sub create_for_list {
19 1     1 1 9 my $class = shift;
20 1         1 my $items = \@_;
21              
22 1         4 foreach my $item ( @$items ) {
23 4 50       9 unless (defined $item) {
24 0         0 Carp::croak('undefined items are not allowed in an iterator list');
25             }
26             }
27              
28             my $code = sub {
29 5     5   10 shift @$items;
30 1         6 };
31 1         3 my $self = bless { _iteration_closure => $code }, __PACKAGE__;
32 1         3 return $self;
33             }
34              
35             sub map($&) {
36 1     1 1 329 my($self, $mapper) = @_;
37              
38             my $wrapper = sub {
39 3     3   9 local $_ = $self->next;
40 3 100       9 defined($_) ? $mapper->() : $_;
41 1         6 };
42              
43 1         5 return bless { _iteration_closure => $wrapper }, __PACKAGE__;
44             }
45              
46             sub _iteration_closure {
47 0     0   0 my $self = shift;
48 0 0       0 if (@_) {
49 0         0 return $self->{_iteration_closure} = shift;
50             }
51 0         0 $self->{_iteration_closure};
52             }
53              
54              
55             sub peek {
56 4     4 1 870 my $self = shift;
57 4 100       11 unless (exists $self->{peek_value}) {
58 3         7 $self->{peek_value} = $self->{_iteration_closure}->();
59             }
60 4         9 $self->{peek_value};
61             }
62              
63              
64             sub next {
65 100239     100239 1 413699 my $self = shift;
66 100239 100       152400 if (exists $self->{peek_value}) {
67 3         9 delete $self->{peek_value};
68             } else {
69 100236         162540 $self->{_iteration_closure}->(@_);
70             }
71             }
72              
73             sub remaining {
74 4     4 1 536 my $self = shift;
75 4         4 my @remaining;
76 4         6 while (defined(my $o = $self->next )) {
77 10         16 push @remaining, $o;
78             }
79 4         12 @remaining;
80             }
81              
82             1;
83              
84             =pod
85              
86             =head1 NAME
87              
88             UR::Iterator - API for iterating through data
89              
90             =head1 SYNOPSIS
91              
92             my $iter = UR::Iterator->create_for_list(1, 2, 3, 4);
93             while (my $i = $iter->next) {
94             print $i\n";
95             }
96              
97             my $mapped_iter = $iter->map(sub { $_ + 1 });
98             while (my $i = $mapped_iter->next) {
99             print "$i\n";
100             }
101              
102             =head1 DESCRIPTION
103              
104             UR::Iterator instances implement the iterator pattern. These objects can
105             be created with either a list of values, or by applying a mapping function
106             to another iterator.
107              
108             UR::Iterator instances are normal Perl object references, not UR-based
109             objects. They do not live in the Context's object cache, and obey the
110             normal Perl rules about scoping.
111              
112             =head1 METHODS
113              
114             =over 4
115              
116             =item create_for_list
117              
118             $iter = UR::Object::Iterator->create_for_list(@values);
119              
120             Creates an iterator based on values contained in the given list. This
121             constructor will throw an exception if any of the supplied values is
122             C.
123              
124             =item map
125              
126             $new_iter = $iter->map(sub { $_ + 1 });
127              
128             Creates a new iterator based on an existing iterator. Values returned by this
129             new iterator are based on the values of the existing iterator after going
130             through a mapping function. This new iterator will be exhausted when the
131             original iterator is exhausted.
132              
133             When the mapping function is called, C<$_> is set to the value obtained from
134             the original iterator.
135              
136             =item next
137              
138             $obj = $iter->next();
139              
140             Return the next object matching the iterator's rule. When there are no more
141             matching objects, it returns undef.
142              
143             =item peek
144              
145             $obj = $iter->peek();
146              
147             Return the next object matching the iterator's rule without removing it. The
148             next call to peek() or next() will return the same object. Returns undef if
149             there are no more matching objects.
150              
151             This is useful to test whether a newly created iterator matched anything.
152              
153             =item remaining
154              
155             @objs = $iter->remaining();
156              
157             Return a list of all the objects remaining in the iterator. The list will be
158             empty if there is no more data.
159              
160             =back
161              
162             =head1 SEE ALSO
163              
164             L
165              
166             =cut