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   446818 use strict;
  2         4  
  2         76  
4 2     2   9 use warnings;
  2         8  
  2         165  
5              
6 2     2   1019 use Array::Iterator;
  2         6  
  2         69  
7 2     2   14 use Carp;
  2         4  
  2         1283  
8              
9             # AUTHORITY
10             # DATE
11             # DIST
12              
13             =head1 VERSION
14              
15             Version 0.135
16              
17             =cut
18              
19             our $VERSION = '0.135';
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 173 my ($self, $n) = @_;
47              
48 32 100       122 if(not defined $n) { $n = 1 }
  25 100       45  
    100          
49 1         14 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         92 my $idx = $self->_current_index - $n;
53              
54 30 100 66     153 if(!defined($self->{_iterated}) || ($self->{_iterated} >= 0)) {
55 9 100       51 return ($idx > 0) ? 1 : 0;
56             }
57 21 100       108 return ($idx >= 0) ? 1 : 0;
58             }
59              
60 25     25 0 3447 sub hasPrevious { my $self = shift; $self->has_previous(@_) }
  25         69  
61              
62             sub previous {
63 6     6 1 2718 my $self = shift;
64              
65 6 100       32 if($self->{'_iterated'} >= 0) {
66 1 50       5 (($self->_current_index - 1) > 0) || Carp::croak('previous: Out Of Bounds: no more elements');
67             } else {
68 5 100       19 (($self->_current_index - 1) >= 0) || Carp::croak('previous: Out Of Bounds: no more elements');
69             }
70 5         45 $self->_iterated = -1;
71 5         16 return $self->_getItem($self->_iteratee, --$self->_current_index);
72             }
73              
74             sub get_previous
75             {
76 7     7 1 12 my $self = shift;
77              
78 7 100       19 return undef unless $self->hasPrevious(); ## no critic: Subroutines::ProhibitExplicitReturnUndef
79 6 100       21 if($self->_iterated == 1) { # RT126034
80 2         7 --$self->{_current_index};
81             }
82 6         15 $self->_iterated = -1;
83 6 50       15 return undef unless $self->hasPrevious(); ## no critic: Subroutines::ProhibitExplicitReturnUndef
84 6         24 return $self->_getItem($self->_iteratee, --$self->{_current_index});
85             }
86              
87 7     7 0 3286 sub getPrevious { my $self = shift; $self->get_previous(@_) }
  7         24  
88              
89             sub look_back {
90 14     14 1 117 my ($self, $n) = @_;
91              
92 14 100       64 if(not defined $n) { $n = 1 }
  5 100       10  
    100          
93 1         12 elsif(not $n) { die "look_back(0) doesn't make sense, did you mean get_previous()?" }
94 1         12 elsif($n < 0) { die "look_back() with negative argument doesn't make sense, did you mean get_next()?" }
95              
96 12         37 my $idx = $self->_current_index - ($n + 1);
97              
98 12 100       61 return undef unless ($idx > 0); ## no critic: Subroutines::ProhibitExplicitReturnUndef
99 7         26 return $self->_getItem($self->_iteratee, $idx);
100             }
101              
102 4     4 0 10 sub lookBack { my $self = shift; $self->look_back(@_) }
  4         16  
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 ORIGINAL AUTHOR
142              
143             stevan little, Estevan@iinteractive.comE
144              
145             =head1 ORIGINAL COPYRIGHT AND LICENSE
146              
147             Copyright 2004 by Infinity Interactive, Inc.
148              
149             L
150              
151             This library is free software; you can redistribute it and/or modify
152             it under the same terms as Perl itself.
153              
154             =cut