Commit | Line | Data |
d0eafc11 |
1 | package Excel::Template::Iterator; |
2 | |
3 | use strict; |
4 | |
5 | BEGIN { |
6 | use vars qw(@ISA); |
7 | @ISA = qw(Excel::Template::Base); |
8 | |
9 | use Excel::Template::Base; |
10 | } |
11 | |
12 | sub 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 | |
61 | sub 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 | |
77 | sub 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 | |
93 | sub 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 | |
104 | sub 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. |
116 | sub _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 | |
135 | sub 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 | |
154 | sub back_up |
155 | { |
156 | my $self = shift; |
157 | |
158 | return 0 if $self->{NO_PARAMS}; |
159 | |
160 | $self->exit_scope; |
161 | |
162 | $self->{INDEX}--; |
163 | |
164 | $self->_do_globals; |
165 | |
166 | $self->enter_scope; |
167 | |
168 | return 1; |
169 | } |
170 | |
171 | sub reset |
172 | { |
173 | my $self = shift; |
174 | |
175 | return 0 if $self->{NO_PARAMS}; |
176 | |
177 | $self->{INDEX} = -1; |
178 | |
179 | return 1; |
180 | } |
181 | |
182 | 1; |
183 | __END__ |
184 | |
185 | =head1 NAME |
186 | |
187 | Excel::Template::Iterator |
188 | |
189 | =head1 PURPOSE |
190 | |
6dd4c89d |
191 | This is meant for internal use only. Documentation is provided for subclassing. |
192 | |
d0eafc11 |
193 | =head1 NODE NAME |
194 | |
6dd4c89d |
195 | None |
196 | |
d0eafc11 |
197 | =head1 INHERITANCE |
198 | |
6dd4c89d |
199 | None |
200 | |
d0eafc11 |
201 | =head1 ATTRIBUTES |
202 | |
6dd4c89d |
203 | None |
204 | |
d0eafc11 |
205 | =head1 CHILDREN |
206 | |
6dd4c89d |
207 | None |
208 | |
d0eafc11 |
209 | =head1 AFFECTS |
210 | |
6dd4c89d |
211 | This is a helper class for LOOP |
212 | |
d0eafc11 |
213 | =head1 DEPENDENCIES |
214 | |
6dd4c89d |
215 | None |
216 | |
217 | =head1 METHODS |
218 | |
219 | =head2 back_up |
220 | |
221 | Go to the previous iteration of the loop |
222 | |
223 | =head2 can_continue |
224 | |
225 | Determines if the iterator can continue. |
226 | |
227 | Currently, this wraps more_params(), but there other possible situations, such as the page ending. |
228 | |
229 | =head2 more_params |
230 | |
231 | Determines if the iterator for the loop has more parameters that it can consume |
232 | |
233 | =head2 next |
234 | |
235 | Go to the next iteration of the loop |
236 | |
237 | =head2 reset |
238 | |
239 | Resets the iterator |
d0eafc11 |
240 | |
241 | =head1 AUTHOR |
242 | |
c09684ff |
243 | Rob Kinyon (rob.kinyon@gmail.com) |
d0eafc11 |
244 | |
245 | =head1 SEE ALSO |
246 | |
6dd4c89d |
247 | LOOP |
248 | |
d0eafc11 |
249 | =cut |