-Revision history for Perl module Excel::Template
-
-0.14 Wed Nov 04 13:30:00 2004
+Revision history for Perl distribution Excel::Template
+
+0.15 Thu Nov 04 16:15:00 2004
+ - Fixed bugs that were:
+ - preventing a worksheet from using a variable name in a loop
+ - allowing two worksheets to have the same name
+ - preventing a worksheet from being called '0' or '0.0'
+ - Added back-references. This allows for one cell to refer to another
+ cell in an Excel-aware way, especially in formulas.
+ - Added the following nodes:
+ - BACKREF
+ - RANGE
+
+0.14 Thu Nov 04 13:30:00 2004
- Added new format support for (nearly) all formats supported by
Spreadsheet::WriteExcel
- Fixed email address everywhere
lib/Excel/Template/Container/Shadow.pm
lib/Excel/Template/Container/Workbook.pm
lib/Excel/Template/Container/Worksheet.pm
+lib/Excel/Template/Element/Backref.pm
lib/Excel/Template/Element/Cell.pm_
lib/Excel/Template/Element/Formula.pm
+lib/Excel/Template/Element/Range.pm
lib/Excel/Template/Element/Var.pm
t/001_load.t
Makefile.PL
+META.yml Module meta-data (added by MakeMaker)
'Test::Simple' => 0.44,
'XML::Parser' => 0.01,
'IO::File' => 0.01,
+ 'IO::Scalar' => 0.01,
'File::Basename' => 0.01,
'Spreadsheet::WriteExcel' => 0.42,
};
use Excel::Template::Base;
use vars qw ($VERSION @ISA);
- $VERSION = '0.14';
+ $VERSION = '0.15';
@ISA = qw( Excel::Template::Base );
}
my $node = Excel::Template::Factory->create_node($name, @_);
die "'$name' (@_) didn't make a node!\n" unless defined $node;
- if ($name eq 'WORKBOOK')
+ if ( $node->isa( 'WORKBOOK' ) )
{
push @{$self->{WORKBOOKS}}, $node;
}
- elsif ($name eq 'VAR')
+ elsif ( $node->is_embedded )
{
return unless @stack;
There is a mailing list at http://groups-beta.google.com/group/ExcelTemplate
+Robert Graff -
+
+=over 4
+
+=item * Finishing formats
+
+=item * Fixing several bugs in worksheet naming
+
+=back 4
+
=head1 COPYRIGHT
This program is free software; you can redistribute
}
sub isa { Excel::Template::Factory::isa(@_) }
+sub is_embedded { Excel::Template::Factory::is_embedded(@_) }
sub calculate { ($_[1])->get(@_[0,2]) }
#{
my $self = shift;
my ($context) = @_;
- $context->new_worksheet($self->{NAME});
+ $context->new_worksheet( $self );
return $self->SUPER::render($context);
}
# represent an XML object. Rather, every container will use this object to
# maintain the context for its children.
-my %isAbsolute = map { $_ => 1 } qw(
+my %isAbsolute = map { $_ => !!1 } qw(
ROW
COL
);
$self->{ACTIVE_WORKSHEET} = undef;
$self->{ACTIVE_FORMAT} = Excel::Template::Format->blank_format($self);
+ $self->{WORKSHEET_NAMES} = undef;
UNIVERSAL::isa($self->{$_}, 'ARRAY') || ($self->{$_} = [])
for qw( STACK PARAM_MAP NAME_MAP );
$param = uc $param;
$depth ||= 0;
- my $val = undef;
- my $found = 0;
-
+ my ($val, $found);
for my $map (reverse @{$self->{$map}})
{
next unless exists $map->{$param};
$depth--, next if $depth;
- $found = 1;
+ $found = !!1;
$val = $map->{$param};
last;
}
$self->{$key} = $self->resolve($obj, $key);
}
- return 1;
+ return !!1;
}
sub exit_scope
pop @{$self->{STACK}};
- return 1;
+ return !!1;
}
sub get
sub new_worksheet
{
my $self = shift;
- my ($name) = @_;
+ my ($worksheet) = @_;
$self->{ROW} = $self->{COL} = 0;
+ $self->{REFERENCES} = {};
+
+ my $name = $self->get( $worksheet, 'NAME' );
+
+ if ( defined $name && length $name )
+ {
+ if ( exists $self->{WORKSHEET_NAMES}{$name} )
+ {
+ $name = '';
+ }
+ else
+ {
+ $self->{WORKSHEET_NAMES}{$name} = undef;
+ }
+ }
+ else
+ {
+ $name = '';
+ }
$self->active_worksheet(
- $self->{XLS}->add_worksheet(
- $name || '',
- ),
+ $self->{XLS}->add_worksheet( $name ),
);
}
$self->{ACTIVE_WORKSHEET};
}
+sub add_reference
+{
+ my $self = shift;
+ my ($ref, $row, $col) = @_;
+
+ $self->{REFERENCES}{$ref} ||= [];
+
+ push @{$self->{REFERENCES}{$ref}}, [ $row, $col ];
+
+ return !!1;
+}
+
+sub get_all_references
+{
+ my $self = shift;
+ my $ref = uc shift;
+
+ $self->{REFERENCES}{$ref} ||= [];
+
+ return @{ $self->{REFERENCES}{$ref} };
+}
+
+sub get_last_reference
+{
+ my $self = shift;
+ my $ref = uc shift;
+
+ $self->{REFERENCES}{$ref} ||= [];
+
+ return @{ $self->{REFERENCES}{$ref}[-1] };
+}
+
1;
__END__
--- /dev/null
+package Excel::Template::Element::Backref;
+
+use strict;
+use Spreadsheet::WriteExcel::Utility;
+
+BEGIN {
+ use vars qw(@ISA);
+ @ISA = qw(Excel::Template::Element);
+
+ use Excel::Template::Element;
+}
+
+sub resolve
+{
+ my $self = shift;
+ my ($context) = @_;
+
+ my $ref_name = $context->resolve($self, 'REF');
+
+ my ($row, $col) = $context->get_last_reference( $ref_name );
+ return '' unless defined $row && defined $col;
+
+ return xl_rowcol_to_cell( $row, $col );
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Excel::Template::Element::Ref
+
+=head1 PURPOSE
+
+Returns the cell location (i.e. B2) of the last cell to name this reference. To
+return the location of the entire range of cells to name this reference see RANGE.
+
+=head1 NODE NAME
+
+REF
+
+=head1 INHERITANCE
+
+Excel::Template::Element
+
+=head1 ATTRIBUTES
+
+=over 4
+
+=item * REF
+
+This is the name of the reference to look up.
+
+=back 4
+
+=head1 CHILDREN
+
+None
+
+=head1 EFFECTS
+
+None
+
+=head1 DEPENDENCIES
+
+This will only be used within CELL tags.
+
+=head1 USAGE
+
+In the example...
+
+ <row>
+ <cell ref="this_cell"/><cell ref="that_cell"><cell ref="that_cell">
+ </row>
+ <row>
+ <formula>=<ref ref="this_cell">+<ref ref="that_cell"></formula>
+ </row>
+
+The formula in row 2 would be =A1+C1. C1 is the last to reference "that_cell".
+
+=head1 AUTHOR
+
+Rob Kinyon (rkinyon@columbus.rr.com)
+
+=head1 SEE ALSO
+
+CELL, RANGE
+
+=cut
my $self = shift;
my ($context) = @_;
+ my ($row, $col) = map { $context->get($self, $_) } qw(ROW COL);
+
+ my $ref = uc $context->get( $self, 'REF' );
+ if (defined $ref && length $ref)
+ {
+ $context->add_reference( $ref, $row, $col );
+ }
+
$context->active_worksheet->write(
- (map { $context->get($self, $_) } qw(ROW COL)),
+ $row, $col,
$self->get_text($context),
$context->active_format,
);
--- /dev/null
+package Excel::Template::Element::Range;
+
+use strict;
+use Spreadsheet::WriteExcel::Utility;
+
+BEGIN {
+ use vars qw(@ISA);
+ @ISA = qw(Excel::Template::Element);
+
+ use Excel::Template::Element;
+}
+
+sub min { $_[0] < $_[1] ? $_[0] : $_[1] }
+sub max { $_[0] > $_[1] ? $_[0] : $_[1] }
+
+sub resolve
+{
+ my $self = shift;
+ my ($context) = @_;
+
+ my $ref_name = $context->resolve($self, 'REF');
+
+ my @refs = $context->get_all_references( $ref_name );
+ return '' unless @refs;
+
+ my ($top, $left, $bottom, $right) =
+ ( $refs[0][0], $refs[0][1] ) x 2;
+
+ shift @refs;
+ foreach my $ref ( @refs )
+ {
+ $top = min( $top, $ref->[0]);
+ $bottom = max( $bottom, $ref->[0]);
+ $left = min( $left, $ref->[1]);
+ $right = max( $right, $ref->[1]);
+ }
+
+ return join( ':',
+ xl_rowcol_to_cell($top, $left),
+ xl_rowcol_to_cell($bottom, $right)
+ );
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Excel::Template::Element::Range
+
+=head1 PURPOSE
+
+Returns a range of cell locations (i.e. B2:C2) that contains all calls using this
+reference. To return the location of the last cell, use REF.
+
+=head1 NODE NAME
+
+REF
+
+=head1 INHERITANCE
+
+Excel::Template::Element
+
+=head1 ATTRIBUTES
+
+=over 4
+
+=item * REF
+
+This is the name of the reference to look up.
+
+=back 4
+
+=head1 CHILDREN
+
+None
+
+=head1 EFFECTS
+
+None
+
+=head1 DEPENDENCIES
+
+This will only be used within CELL tags.
+
+=head1 USAGE
+
+In the example...
+
+ <row>
+ <cell ref="this_cell"/><cell ref="that_cell"><cell ref="that_cell">
+ </row>
+ <row>
+ <formula>=SUM(<range ref="that_cell">)</formula>
+ </row>
+
+The formula in row 2 would be =SUM(B1:C1).
+
+=head1 AUTHOR
+
+Rob Kinyon (rkinyon@columbus.rr.com)
+
+=head1 SEE ALSO
+
+CELL, REF
+
+=cut
'WORKBOOK' => 'Excel::Template::Container::Workbook',
'WORKSHEET' => 'Excel::Template::Container::Worksheet',
+ 'BACKREF' => 'Excel::Template::Element::Backref',
'CELL' => 'Excel::Template::Element::Cell',
'FORMULA' => 'Excel::Template::Element::Formula',
+ 'RANGE' => 'Excel::Template::Element::Range',
'VAR' => 'Excel::Template::Element::Var',
'FORMAT' => 'Excel::Template::Container::Format',
# These are all the Format short-cut objects
+# They are also instantiable
'BOLD' => 'Excel::Template::Container::Bold',
'HIDDEN' => 'Excel::Template::Container::Hidden',
'ITALIC' => 'Excel::Template::Container::Italic',
'STRIKEOUT' => 'Excel::Template::Container::Strikeout',
# These are the helper objects
-
+# They are also in here to make E::T::Factory::isa() work.
'CONTEXT' => 'Excel::Template::Context',
'ITERATOR' => 'Excel::Template::Iterator',
'TEXTOBJECT' => 'Excel::Template::TextObject',
ITALIC
OUTLINE
LOOP
+ BACKREF
+ RANGE
ROW
SHADOW
STRIKEOUT
: UNIVERSAL::isa(@_)
}
+sub is_embedded
+{
+ return unless @_ >= 1;
+
+ isa( $_[0], $_ ) && return !!1 for qw( VAR BACKREF RANGE );
+ return;
+}
+
1;
__END__
=head1 PURPOSE
-=head1 NODE NAME
+To provide a common way to instantiate Excel::Template nodes
-=head1 INHERITANCE
-
-=head1 ATTRIBUTES
-
-=head1 CHILDREN
+=head1 USAGE
-=head1 AFFECTS
+=head2 register()
-=head1 DEPENDENCIES
+Use this to register your own nodes.
-=head1 USAGE
+Example forthcoming.
=head1 AUTHOR
{
my $val = $tok;
$val = $val->resolve($context)
- if Excel::Template::Factory::isa($val, 'VAR');
+ if Excel::Template::Factory::is_embedded( $val );
UNI_YES $t .= Unicode::String::utf8("$val");
UNI_NO $t .= $val;