1 package Excel::Template::Context;
7 @ISA = qw(Excel::Template::Base);
9 use Excel::Template::Base;
12 use Excel::Template::Format;
14 # This is a helper object. It is not instantiated by the user, nor does it
15 # represent an XML object. Rather, every container will use this object to
16 # maintain the context for its children.
18 my %isAbsolute = map { $_ => !!1 } qw(
26 my $self = $class->SUPER::new(@_);
28 $self->{ACTIVE_WORKSHEET} = undef;
29 $self->{ACTIVE_FORMAT} = Excel::Template::Format->blank_format($self);
30 $self->{WORKSHEET_NAMES} = undef;
32 UNIVERSAL::isa($self->{$_}, 'ARRAY') || ($self->{$_} = [])
33 for qw( STACK PARAM_MAP NAME_MAP );
35 $self->{$_} = 0 for keys %isAbsolute;
40 sub _find_param_in_map
43 my ($map, $param, $depth) = @_;
48 for my $map (reverse @{$self->{$map}})
50 next unless exists $map->{$param};
51 $depth--, next if $depth;
54 $val = $map->{$param};
58 die "Parameter '$param' not found\n"
59 if !$found && $self->{DIE_ON_NO_PARAM};
67 $self->_find_param_in_map(
76 $self->_find_param_in_map(
85 my ($obj, $key, $depth) = @_;
89 my $obj_val = $obj->{$key};
91 $obj_val = $self->param($1)
92 if $obj_val =~ /^\$(\S+)$/o;
94 #GGG Remove this once NAME_MAP is working
95 # $obj_val = $self->named_param($1)
96 # if $obj_val =~ /^\\(\S+)$/o;
98 #GGG Does this adequately test values to make sure they're legal??
99 # A value is defined as:
100 # 1) An optional operator (+, -, *, or /)
101 # 2) A decimal number
103 #GGG Convert this to use //x
104 my ($op, $val) = $obj_val =~ m!^\s*([\+\*\/\-])?\s*([\d.]*\d)\s*$!oi;
106 # Unless it's a relative value, we have what we came for.
107 return $obj_val unless $op;
109 my $prev_val = $isAbsolute{$key}
111 : $self->get($obj, $key, $depth + 1);
113 return $obj_val unless defined $prev_val;
114 return $prev_val unless defined $obj_val;
116 # Prevent divide-by-zero issues.
117 return $val if $op eq '/' and $val == 0;
122 /^\+$/ && do { $new_val = ($prev_val + $val); last; };
123 /^\-$/ && do { $new_val = ($prev_val - $val); last; };
124 /^\*$/ && do { $new_val = ($prev_val * $val); last; };
125 /^\/$/ && do { $new_val = ($prev_val / $val); last; };
127 die "Unknown operator '$op' in arithmetic resolve\n";
130 return $new_val if defined $new_val;
139 push @{$self->{STACK}}, $obj;
141 for my $key (keys %isAbsolute)
143 next unless exists $obj->{$key};
144 $self->{$key} = $self->resolve($obj, $key);
153 my ($obj, $no_delta) = @_;
157 my $deltas = $obj->deltas($self);
158 $self->{$_} += $deltas->{$_} for keys %$deltas;
161 pop @{$self->{STACK}};
169 my ($dummy, $key, $depth) = @_;
173 return unless @{$self->{STACK}};
175 my $obj = $self->{STACK}[-1];
177 return $self->{$key} if $isAbsolute{$key};
180 my $this_depth = $depth;
181 foreach my $e (reverse @{$self->{STACK}})
183 next unless exists $e->{$key};
184 next if $this_depth-- > 0;
186 $val = $self->resolve($e, $key, $depth);
190 $val = $self->{$key} unless defined $val;
191 return $val unless defined $val;
193 return $self->param($1, $depth) if $val =~ /^\$(\S+)$/o;
202 $self->{ACTIVE_FORMAT} = $_[0]
205 $self->{ACTIVE_FORMAT};
211 my ($worksheet) = @_;
213 $self->{ROW} = $self->{COL} = 0;
214 $self->{REFERENCES} = {};
216 my $name = $self->get( $worksheet, 'NAME' );
218 if ( defined $name && length $name )
220 if ( exists $self->{WORKSHEET_NAMES}{$name} )
226 $self->{WORKSHEET_NAMES}{$name} = undef;
234 $self->active_worksheet(
235 $self->{XLS}->add_worksheet( $name ),
243 $self->{ACTIVE_WORKSHEET} = $_[0]
246 $self->{ACTIVE_WORKSHEET};
252 my ($ref, $row, $col) = @_;
254 $self->{REFERENCES}{$ref} ||= [];
256 push @{$self->{REFERENCES}{$ref}}, [ $row, $col ];
261 sub get_all_references
266 $self->{REFERENCES}{$ref} ||= [];
268 return @{ $self->{REFERENCES}{$ref} };
271 sub get_last_reference
276 $self->{REFERENCES}{$ref} ||= [];
278 return @{ $self->{REFERENCES}{$ref}[-1] };
286 Excel::Template::Context
306 Rob Kinyon (rob.kinyon@gmail.com)