Improved tests and documentation. Fixed a few bugs in register()
[p5sagit/Excel-Template.git] / lib / Excel / Template / Iterator.pm
CommitLineData
d0eafc11 1package Excel::Template::Iterator;
2
3use strict;
4
5BEGIN {
6 use vars qw(@ISA);
7 @ISA = qw(Excel::Template::Base);
8
9 use Excel::Template::Base;
10}
11
12sub new
13{
14 my $class = shift;
15 my $self = $class->SUPER::new(@_);
16
17 unless (Excel::Template::Factory::isa($self->{CONTEXT}, 'CONTEXT'))
18 {
19 die "Internal Error: No context object passed to ", __PACKAGE__, $/;
20 }
21
22 $self->{MAXITERS} ||= 0;
23
24 # This is the index we will work on NEXT, in whatever direction the
25 # iterator is going.
26 $self->{INDEX} = -1;
27
28 # This is a short-circuit parameter to let the iterator function in a
29 # null state.
30 $self->{NO_PARAMS} = 0;
31 unless ($self->{NAME} =~ /\w/)
32 {
33 $self->{NO_PARAMS} = 1;
34
dee1f239 35 warn "INTERNAL ERROR: 'NAME' was blank was blank when passed to ", __PACKAGE__, $/ if $^W;
d0eafc11 36
37 return $self;
38 }
39
40 # Cache the reference to the appropriate data.
41 $self->{DATA} = $self->{CONTEXT}->param($self->{NAME});
42
43 unless (UNIVERSAL::isa($self->{DATA}, 'ARRAY'))
44 {
45 $self->{NO_PARAMS} = 1;
dee1f239 46 warn "'$self->{NAME}' does not have a list of parameters", $/ if $^W;
d0eafc11 47
48 return $self;
49 }
50
51 unless (@{$self->{DATA}})
52 {
53 $self->{NO_PARAMS} = 1;
54 }
55
56 $self->{MAX_INDEX} = $#{$self->{DATA}};
57
58 return $self;
59}
60
61sub enter_scope
62{
63 my $self = shift;
64
65 return 0 if $self->{NO_PARAMS};
66
67 for my $x ($self->{DATA}[$self->{INDEX}])
68 {
69 $x->{uc $_} = delete $x->{$_} for keys %$x;
70 }
71
72 push @{$self->{CONTEXT}{PARAM_MAP}}, $self->{DATA}[$self->{INDEX}];
73
74 return 1;
75}
76
77sub exit_scope
78{
79 my $self = shift;
80
81 return 0 if $self->{NO_PARAMS};
82
83 # There has to be the base parameter map and at least the one that
84 # Iterator::enter_scope() added on top.
85 @{$self->{CONTEXT}{PARAM_MAP}} > 1 ||
86 die "Internal Error: ", __PACKAGE__, "'s internal param_map off!", $/;
87
88 pop @{$self->{CONTEXT}{PARAM_MAP}};
89
90 return 1;
91}
92
93sub can_continue
94{
95 my $self = shift;
96
97 return 0 if $self->{NO_PARAMS};
98
99 return 1 if $self->more_params;
100
101 return 0;
102}
103
104sub more_params
105{
106 my $self = shift;
107
108 return 0 if $self->{NO_PARAMS};
109
110 return 1 if $self->{MAX_INDEX} > $self->{INDEX};
111
112 return 0;
113}
114
115# Call this method BEFORE incrementing the index to the next value.
116sub _do_globals
117{
118 my $self = shift;
119
120 my $data = $self->{DATA}[$self->{INDEX}];
121
122 # Perl's arrays are 0-indexed. Thus, the first element is at index "0".
123 # This means that odd-numbered elements are at even indices, and vice-versa.
124 # This also means that MAX (the number of elements in the array) can never
125 # be the value of an index. It is NOT the last index in the array.
126
127 $data->{'__FIRST__'} ||= ($self->{INDEX} == 0);
128 $data->{'__INNER__'} ||= (0 < $self->{INDEX} && $self->{INDEX} < $self->{MAX_INDEX});
129 $data->{'__LAST__'} ||= ($self->{INDEX} == $self->{MAX_INDEX});
130 $data->{'__ODD__'} ||= !($self->{INDEX} % 2);
131
132 return 1;
133}
134
135sub next
136{
137 my $self = shift;
138
139 return 0 if $self->{NO_PARAMS};
140
141 return 0 unless $self->more_params;
142
143 $self->exit_scope;
144
145 $self->{INDEX}++;
146
147 $self->_do_globals;
148
149 $self->enter_scope;
150
151 return 1;
152}
153
e976988f 154# This method doesn't seem to be used ...
155# If it is reinstated, here's the POD for it
156#=head2 back_up
157#
158#Go to the previous iteration of the loop
159#
160#sub back_up
161#{
162# my $self = shift;
163#
164# return 0 if $self->{NO_PARAMS};
165#
166# $self->exit_scope;
167#
168# $self->{INDEX}--;
169#
170# $self->_do_globals;
171#
172# $self->enter_scope;
173#
174# return 1;
175#}
176
177# This method doesn't seem to be used ...
178# If it is reinstated, here's the POD for it
179#=head2 reset
180#
181#Resets the iterator
182#
183#sub reset
184#{
185# my $self = shift;
186#
187# return 0 if $self->{NO_PARAMS};
188#
189# $self->{INDEX} = -1;
190#
191# return 1;
192#}
d0eafc11 193
1941;
195__END__
196
197=head1 NAME
198
199Excel::Template::Iterator
200
201=head1 PURPOSE
202
6dd4c89d 203This is meant for internal use only. Documentation is provided for subclassing.
204
d0eafc11 205=head1 NODE NAME
206
6dd4c89d 207None
208
d0eafc11 209=head1 INHERITANCE
210
6dd4c89d 211None
212
d0eafc11 213=head1 ATTRIBUTES
214
6dd4c89d 215None
216
d0eafc11 217=head1 CHILDREN
218
6dd4c89d 219None
220
d0eafc11 221=head1 AFFECTS
222
6dd4c89d 223This is a helper class for LOOP
224
d0eafc11 225=head1 DEPENDENCIES
226
6dd4c89d 227None
228
229=head1 METHODS
230
6dd4c89d 231=head2 can_continue
232
233Determines if the iterator can continue.
234
235Currently, this wraps more_params(), but there other possible situations, such as the page ending.
236
237=head2 more_params
238
239Determines if the iterator for the loop has more parameters that it can consume
240
241=head2 next
242
243Go to the next iteration of the loop
244
d0eafc11 245=head1 AUTHOR
246
c09684ff 247Rob Kinyon (rob.kinyon@gmail.com)
d0eafc11 248
249=head1 SEE ALSO
250
6dd4c89d 251LOOP
252
d0eafc11 253=cut