File Coverage

blib/lib/Array/Iterator/BiDirectional.pm
Criterion Covered Total %
statement 48 48 100.0
branch 30 32 93.7
condition 2 3 66.6
subroutine 11 11 100.0
pod 4 7 57.1
total 95 101 94.0


line stmt bran cond sub pod time code
1             package Array::Iterator::BiDirectional;
2              
3 2     2   341657 use strict;
  2         4  
  2         84  
4 2     2   12 use warnings;
  2         29  
  2         113  
5              
6 2     2   1080 use Array::Iterator;
  2         8  
  2         72  
7 2     2   16 use Carp;
  2         5  
  2         1582  
8              
9             # AUTHORITY
10             # DATE
11             # DIST
12              
13             =head1 VERSION
14              
15             Version 0.136
16              
17             =cut
18              
19             our $VERSION = '0.136';
20              
21             =head1 SYNOPSIS
22              
23             Occasionally it is useful for an iterator to go in both directions, forward and backward. One example would be token processing. When looping though tokens it is sometimes necessary to advance forward looking for a match to a rule. If the match fails, a bi-directional iterator can be moved back so that the next rule can be tried.
24              
25             use Array::Iterator::BiDirectional;
26              
27             # create an instance of the iterator
28             my $i = Array::Iterator::BiDirectional->new(1 .. 100);
29              
30             while ($some_condition_exists) {
31             # get the latest item from
32             # the iterator
33             my $current = $i->get_next();
34             # ...
35             if ($something_happens) {
36             # back up the iterator
37             $current = $i->get_previous();
38             }
39             }
40              
41             =cut
42              
43             our @ISA = qw(Array::Iterator);
44              
45             sub has_previous {
46 32     32 1 164 my ($self, $n) = @_;
47              
48 32 100       97 if(not defined $n) { $n = 1 }
  25 100       38  
    100          
49 1         13 elsif(not $n) { die "has_previous(0) doesn't make sense, did you mean current()?" }
50 1         11 elsif($n < 0) { die "has_previous() with negative argument doesn't make sense, did you mean has_next()?" }
51              
52 30         106 my $idx = $self->_current_index - $n;
53              
54 30 100 66     161 if(!defined($self->{_iterated}) || ($self->{_iterated} >= 0)) {
55 9 100       91 return ($idx > 0) ? 1 : 0;
56             }
57 21 100       102 return ($idx >= 0) ? 1 : 0;
58             }
59              
60 25     25 0 3329 sub hasPrevious { my $self = shift; $self->has_previous(@_) }
  25         92  
61              
62             sub previous {
63 6     6 1 2878 my $self = shift;
64              
65 6 100       22 if($self->{'_iterated'} >= 0) {
66 1 50       4 (($self->_current_index - 1) > 0) || Carp::croak('previous: Out Of Bounds: no more elements');
67             } else {
68 5 100       20 (($self->_current_index - 1) >= 0) || Carp::croak('previous: Out Of Bounds: no more elements');
69             }
70 5         21 $self->_iterated = -1;
71 5         36 return $self->_getItem($self->_iteratee, --$self->_current_index);
72             }
73              
74             sub get_previous
75             {
76 7     7 1 15 my $self = shift;
77              
78 7 100       17 return undef unless $self->hasPrevious(); ## no critic: Subroutines::ProhibitExplicitReturnUndef
79 6 100       24 if($self->_iterated == 1) { # RT126034
80 2         6 --$self->{_current_index};
81             }
82 6         16 $self->_iterated = -1;
83 6 50       18 return undef unless $self->hasPrevious(); ## no critic: Subroutines::ProhibitExplicitReturnUndef
84 6         62 return $self->_getItem($self->_iteratee, --$self->{_current_index});
85             }
86              
87 7     7 0 3274 sub getPrevious { my $self = shift; $self->get_previous(@_) }
  7         22  
88              
89             sub look_back {
90 14     14 1 114 my ($self, $n) = @_;
91              
92 14 100       56 if(not defined $n) { $n = 1 }
  5 100       10  
    100          
93 1         11 elsif(not $n) { die "look_back(0) doesn't make sense, did you mean get_previous()?" }
94 1         10 elsif($n < 0) { die "look_back() with negative argument doesn't make sense, did you mean get_next()?" }
95              
96 12         41 my $idx = $self->_current_index - ($n + 1);
97              
98 12 100       52 return undef unless ($idx > 0); ## no critic: Subroutines::ProhibitExplicitReturnUndef
99 7         23 return $self->_getItem($self->_iteratee, $idx);
100             }
101              
102 4     4 0 8 sub lookBack { my $self = shift; $self->look_back(@_) }
  4         14  
103              
104             1;
105             #ABSTRACT: A subclass of Array::Iterator to allow forwards and backwards iteration
106              
107             =for Pod::Coverage .+
108              
109             =head1 METHODS
110              
111             This is a subclass of Array::Iterator, only those methods that have been added are documented here, refer to the Array::Iterator documentation for more information.
112              
113             =over 4
114              
115             =item B
116              
117             This method works much like C does, it will return true (C<1>) unless the beginning of the array has been reached, and false (C<0>) otherwise.
118              
119             Optional argument has the same meaning except that it specifies C<$n>th previous element.
120              
121             =item B
122              
123             This method is much like C. It will return the previous item in the iterator, and throw an exception if it attempts to reach past the beginning of the array.
124              
125             =item B
126              
127             This method is much like C. It will return the previous item in the iterator, and return undef if it attempts to reach past the beginning of the array.
128              
129             =item B
130              
131             This is the counterpart to C, it will return the previous items in the iterator, but will not affect the internal counter.
132              
133             Optional argument has the same meaning except that it specifies C<$n>th previous element.
134              
135             =back
136              
137             =head1 SEE ALSO
138              
139             This is a subclass of B, please refer to it for more documentation.
140              
141             =head1 MAINTAINER
142              
143             Nigel Horne, C<< >>
144              
145             2025-2026
146              
147             =head1 ORIGINAL AUTHOR
148              
149             stevan little, Estevan@iinteractive.comE
150              
151             =head1 ORIGINAL COPYRIGHT AND LICENSE
152              
153             Copyright 2004 by Infinity Interactive, Inc.
154              
155             L
156              
157             This library is free software; you can redistribute it and/or modify
158             it under the same terms as Perl itself.
159              
160             =cut