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 use_unicode { $_[0]->{UNICODE} && 1 }
42 sub _find_param_in_map
45 my ($map, $param, $depth) = @_;
50 for my $map (reverse @{$self->{$map}})
52 next unless exists $map->{$param};
53 $depth--, next if $depth;
56 $val = $map->{$param};
60 die "Parameter '$param' not found\n"
61 if !$found && $self->{DIE_ON_NO_PARAM};
69 $self->_find_param_in_map(
78 $self->_find_param_in_map(
87 my ($obj, $key, $depth) = @_;
91 my $obj_val = $obj->{$key};
93 $obj_val = $self->param($1)
94 if $obj_val =~ /^\$(\S+)$/o;
96 #GGG Remove this once NAME_MAP is working
97 # $obj_val = $self->named_param($1)
98 # if $obj_val =~ /^\\(\S+)$/o;
100 #GGG Does this adequately test values to make sure they're legal??
101 # A value is defined as:
102 # 1) An optional operator (+, -, *, or /)
103 # 2) A decimal number
105 #GGG Convert this to use //x
106 my ($op, $val) = $obj_val =~ m!^\s*([\+\*\/\-])?\s*([\d.]*\d)\s*$!oi;
108 # Unless it's a relative value, we have what we came for.
109 return $obj_val unless $op;
111 my $prev_val = $isAbsolute{$key}
113 : $self->get($obj, $key, $depth + 1);
115 return $obj_val unless defined $prev_val;
116 return $prev_val unless defined $obj_val;
118 # Prevent divide-by-zero issues.
119 return $val if $op eq '/' and $val == 0;
124 /^\+$/ && do { $new_val = ($prev_val + $val); last; };
125 /^\-$/ && do { $new_val = ($prev_val - $val); last; };
126 /^\*$/ && do { $new_val = ($prev_val * $val); last; };
127 /^\/$/ && do { $new_val = ($prev_val / $val); last; };
129 die "Unknown operator '$op' in arithmetic resolve\n";
132 return $new_val if defined $new_val;
141 push @{$self->{STACK}}, $obj;
143 for my $key (keys %isAbsolute)
145 next unless exists $obj->{$key};
146 $self->{$key} = $self->resolve($obj, $key);
155 my ($obj, $no_delta) = @_;
159 my $deltas = $obj->deltas($self);
160 $self->{$_} += $deltas->{$_} for keys %$deltas;
163 pop @{$self->{STACK}};
171 my ($dummy, $key, $depth) = @_;
175 return unless @{$self->{STACK}};
177 my $obj = $self->{STACK}[-1];
179 return $self->{$key} if $isAbsolute{$key};
182 my $this_depth = $depth;
183 foreach my $e (reverse @{$self->{STACK}})
185 next unless exists $e->{$key};
186 next if $this_depth-- > 0;
188 $val = $self->resolve($e, $key, $depth);
192 $val = $self->{$key} unless defined $val;
193 return $val unless defined $val;
195 return $self->param($1, $depth) if $val =~ /^\$(\S+)$/o;
204 $self->{ACTIVE_FORMAT} = $_[0]
207 $self->{ACTIVE_FORMAT};
213 my ($worksheet) = @_;
215 $self->{ROW} = $self->{COL} = 0;
216 $self->{REFERENCES} = {};
218 my $name = $self->get( $worksheet, 'NAME' );
220 if ( defined $name && length $name )
222 if ( exists $self->{WORKSHEET_NAMES}{$name} )
228 $self->{WORKSHEET_NAMES}{$name} = undef;
236 $self->active_worksheet(
237 $self->{XLS}->add_worksheet( $name ),
245 $self->{ACTIVE_WORKSHEET} = $_[0]
248 $self->{ACTIVE_WORKSHEET};
254 my ($ref, $row, $col) = @_;
256 $self->{REFERENCES}{$ref} ||= [];
258 push @{$self->{REFERENCES}{$ref}}, [ $row, $col ];
263 sub get_all_references
268 $self->{REFERENCES}{$ref} ||= [];
270 return @{ $self->{REFERENCES}{$ref} };
273 sub get_last_reference
278 $self->{REFERENCES}{$ref} ||= [];
280 return @{ $self->{REFERENCES}{$ref}[-1] };
288 Excel::Template::Context
308 Rob Kinyon (rob.kinyon@gmail.com)