File Coverage

blib/lib/Iterator/Flex/Gather.pm
Criterion Covered Total %
statement 79 79 100.0
branch 21 28 75.0
condition 14 23 60.8
subroutine 14 14 100.0
pod 1 2 50.0
total 129 146 88.3


line stmt bran cond sub pod time code
1             package Iterator::Flex::Gather;
2              
3             # ABSTRACT: Gather Iterator Class
4              
5 3     3   292360 use v5.28;
  3         12  
6 3     3   18 use strict;
  3         8  
  3         79  
7 3     3   13 use warnings;
  3         5  
  3         215  
8 3     3   426 use experimental 'signatures';
  3         1250  
  3         35  
9              
10             our $VERSION = '0.33';
11              
12 3     3   1046 use Iterator::Flex::Factory 'to_iterator';
  3         9  
  3         261  
13 3     3   42 use Iterator::Flex::Utils qw[ THROW STATE EXHAUSTION :IterAttrs :IterStates ];
  3         8  
  3         769  
14 3     3   24 use Ref::Util;
  3         8  
  3         176  
15 3     3   20 use parent 'Iterator::Flex::Base';
  3         7  
  3         30  
16              
17 3     3   1108 use Iterator::Flex::Gather::Constants ':all';
  3         9  
  3         570  
18              
19              
20 3     3   24 use namespace::clean;
  3         41  
  3         23  
21              
22              
23              
24              
25              
26              
27              
28              
29              
30              
31              
32              
33              
34              
35              
36              
37              
38              
39              
40              
41              
42              
43              
44              
45              
46              
47              
48              
49              
50              
51              
52              
53              
54              
55              
56              
57              
58              
59              
60              
61              
62              
63              
64              
65              
66              
67              
68              
69              
70              
71              
72              
73              
74              
75              
76              
77              
78              
79              
80              
81              
82              
83              
84              
85              
86              
87              
88              
89              
90              
91              
92              
93              
94              
95              
96              
97              
98              
99              
100              
101              
102              
103              
104              
105              
106              
107              
108              
109              
110              
111              
112              
113              
114              
115              
116              
117              
118              
119              
120              
121              
122              
123              
124              
125              
126              
127              
128              
129              
130              
131              
132              
133              
134              
135              
136              
137              
138              
139              
140              
141              
142              
143              
144              
145              
146              
147              
148              
149              
150              
151              
152              
153              
154              
155              
156              
157              
158              
159              
160              
161              
162              
163              
164              
165              
166              
167              
168              
169              
170              
171 10     10 1 43 sub new ( $class, $code, $iterable, $pars = {} ) {
  10         24  
  10         21  
  10         21  
  10         23  
  10         18  
172              
173 10 50       38 throw_failure( parameter => q{'code' parameter is not a coderef} )
174             unless Ref::Util::is_coderef( $code );
175              
176 10         32 my %pars = $pars->%*;
177              
178             my %state = (
179             code => $code,
180 10   100     75 cycle_on_exhaustion => delete( $pars{cycle_on_exhaustion} ) // GATHER_CYCLE_STOP,
181             src => $iterable,
182             );
183              
184             throw_failure( parameter => q{'cycle_on_exhaustion': illegal value} )
185             if defined $pars{cycle_on_exhaustion}
186             and $pars{cycle_on_exhaustion} != GATHER_CYCLE_CHOOSE
187 10 0 33     47 and !$pars{cycle_on_exhaustion} & ( GATHER_CYCLE_STOP | GATHER_CYCLE_ABORT );
      33        
188              
189 10         49 $class->SUPER::new( \%state, \%pars );
190             }
191              
192              
193 10     10 0 22 sub construct ( $class, $state ) {
  10         20  
  10         20  
  10         16  
194              
195 10 50       31 throw_failure( parameter => q{'state' parameter must be a HASH reference} )
196             unless Ref::Util::is_hashref( $state );
197              
198 10         24 my ( $code, $src, $cycle_on_exhaustion ) = @{$state}{qw[ code src cycle_on_exhaustion ]};
  10         33  
199              
200 10         62 $src
201             = to_iterator( $src, { ( +EXHAUSTION ) => THROW } );
202              
203 10         33 my $self;
204              
205             # cached value if current element should be in
206             # next cycle
207 10         24 my $has_cache = !!0;
208 10         24 my $cache;
209              
210             my $iterator_state;
211              
212             # This iterator may have to delay signalling exhaustion for one cycle if the
213             # input iterator is exhausted, and it needs to return the last group of elements.
214             # exhaustion.
215 10         20 my $next_is_exhausted = !!0;
216              
217             return {
218             ( +_NAME ) => 'igather',
219              
220             ( +_SELF ) => \$self,
221              
222             ( +STATE ) => \$iterator_state,
223              
224             ( +NEXT ) => sub {
225 61 100 66 61   287 return $self->signal_exhaustion
226             if $iterator_state == IterState_EXHAUSTED || $next_is_exhausted;
227              
228 54         99 my $cycle;
229             my @gathered;
230 54         96 my $ret = eval {
231 54         75 while ( 1 ) {
232              
233 324 100       938 my $rv = $has_cache ? $cache : $src->();
234 312         570 $has_cache = !!0;
235              
236 312         519 local $_ = $rv;
237 312         675 my $result = $code->( \@gathered, GATHER_GATHERING );
238 312         2760 $cycle = $result & GATHER_CYCLE_MASK;
239              
240 312 50       645 throw_failure( parameter => 'cycle action (continue, stop, abort, restart) was not specified' )
241             unless $cycle;
242              
243 312 100       684 if ( ( $result & GATHER_ELEMENT_MASK ) == GATHER_ELEMENT_INCLUDE ) {
    100          
244 193         420 push @gathered, $rv;
245             }
246             elsif ( ( $result & GATHER_ELEMENT_MASK ) == GATHER_ELEMENT_CACHE ) {
247 7 50       21 throw_failure( parameter =>
248             'inconsistent return: element action GATHER_ELEMENT_CACHE requires cycle action GATHER_CYCLE_STOP',
249             ) unless $cycle & GATHER_CYCLE_RESTART;
250 7         11 $cache = $rv;
251 7         12 $has_cache = !!1;
252             }
253              
254 312 100       742 last if $cycle & ( GATHER_CYCLE_RESTART | GATHER_CYCLE_STOP | GATHER_CYCLE_ABORT );
255             }
256 42         91 1;
257             };
258 54 100 66     1028 if ( !$ret && length $@ ) {
259              
260 12 50 33     1283 die $@
261             unless Ref::Util::is_blessed_ref( $@ )
262             && $@->isa( 'Iterator::Flex::Failure::Exhausted' );
263              
264 12         36 local $_ = undef;
265 12 100       42 my $result
266             = $cycle_on_exhaustion == GATHER_CYCLE_CHOOSE
267             ? $code->( \@gathered, GATHER_SRC_EXHAUSTED )
268             : $cycle_on_exhaustion;
269 12 100 66     173 return $self->signal_exhaustion
      100        
270             if ( $result & GATHER_CYCLE_ABORT )
271             || ( $result & GATHER_CYCLE_STOP && !@gathered );
272              
273 7         21 $next_is_exhausted = !!1;
274             }
275              
276 49         178 return \@gathered;
277             },
278             (
279 10         143 map { ( ( +RESET ) => $_, ( +REWIND ) => $_, ) } sub {
280 4     4   11 $next_is_exhausted = $has_cache = !!0;
281             },
282 10         93 ),
283             ( +_DEPENDS ) => $src,
284             };
285             }
286              
287             __PACKAGE__->_add_roles( qw[
288             State::Closure
289             Next::ClosedSelf
290             Rewind::Closure
291             Reset::Closure
292             Current::Closure
293             ] );
294              
295             1;
296              
297             #
298             # This file is part of Iterator-Flex
299             #
300             # This software is Copyright (c) 2018 by Smithsonian Astrophysical Observatory.
301             #
302             # This is free software, licensed under:
303             #
304             # The GNU General Public License, Version 3, June 2007
305             #
306              
307             __END__