From: Rob Kinyon Date: Thu, 4 Nov 2004 21:14:14 +0000 (+0000) Subject: - Fixed bugs that were: X-Git-Tag: v0.16~1 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=37513eae9a11e4f4364f82dd067b7da534c2b18d;p=p5sagit%2FExcel-Template.git - 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 --- diff --git a/Changes b/Changes index 58ad3d1..05e7456 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,17 @@ -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 diff --git a/MANIFEST b/MANIFEST index 6275da5..88d5c49 100644 --- a/MANIFEST +++ b/MANIFEST @@ -26,8 +26,11 @@ lib/Excel/Template/Container/Strikeout.pm 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) diff --git a/Makefile.PL b/Makefile.PL index 6fdd34a..a7aefc3 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -8,6 +8,7 @@ my $prereqs = { 'Test::Simple' => 0.44, 'XML::Parser' => 0.01, 'IO::File' => 0.01, + 'IO::Scalar' => 0.01, 'File::Basename' => 0.01, 'Spreadsheet::WriteExcel' => 0.42, }; diff --git a/lib/Excel/Template.pm b/lib/Excel/Template.pm index 00e7531..1d7626e 100644 --- a/lib/Excel/Template.pm +++ b/lib/Excel/Template.pm @@ -6,7 +6,7 @@ BEGIN { use Excel::Template::Base; use vars qw ($VERSION @ISA); - $VERSION = '0.14'; + $VERSION = '0.15'; @ISA = qw( Excel::Template::Base ); } @@ -123,11 +123,11 @@ sub parse_xml 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; @@ -347,6 +347,16 @@ but I expect to be adding on to it very soon. 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 diff --git a/lib/Excel/Template/Base.pm b/lib/Excel/Template/Base.pm index 9788c11..9215ac5 100644 --- a/lib/Excel/Template/Base.pm +++ b/lib/Excel/Template/Base.pm @@ -25,6 +25,7 @@ sub new } sub isa { Excel::Template::Factory::isa(@_) } +sub is_embedded { Excel::Template::Factory::is_embedded(@_) } sub calculate { ($_[1])->get(@_[0,2]) } #{ diff --git a/lib/Excel/Template/Container/Worksheet.pm b/lib/Excel/Template/Container/Worksheet.pm index 4b96638..6a1edaf 100644 --- a/lib/Excel/Template/Container/Worksheet.pm +++ b/lib/Excel/Template/Container/Worksheet.pm @@ -14,7 +14,7 @@ sub render my $self = shift; my ($context) = @_; - $context->new_worksheet($self->{NAME}); + $context->new_worksheet( $self ); return $self->SUPER::render($context); } diff --git a/lib/Excel/Template/Context.pm b/lib/Excel/Template/Context.pm index ea5d8f3..7a66225 100644 --- a/lib/Excel/Template/Context.pm +++ b/lib/Excel/Template/Context.pm @@ -15,7 +15,7 @@ use Excel::Template::Format; # 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 ); @@ -27,6 +27,7 @@ sub new $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 ); @@ -43,15 +44,13 @@ sub _find_param_in_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; } @@ -145,7 +144,7 @@ sub enter_scope $self->{$key} = $self->resolve($obj, $key); } - return 1; + return !!1; } sub exit_scope @@ -161,7 +160,7 @@ sub exit_scope pop @{$self->{STACK}}; - return 1; + return !!1; } sub get @@ -209,14 +208,31 @@ sub active_format 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 ), ); } @@ -230,6 +246,38 @@ sub active_worksheet $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__ diff --git a/lib/Excel/Template/Element/Backref.pm b/lib/Excel/Template/Element/Backref.pm new file mode 100755 index 0000000..fe82f1b --- /dev/null +++ b/lib/Excel/Template/Element/Backref.pm @@ -0,0 +1,89 @@ +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... + + + + + + =+ + + +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 diff --git a/lib/Excel/Template/Element/Cell.pm_ b/lib/Excel/Template/Element/Cell.pm_ index f291c4b..e09a4c2 100755 --- a/lib/Excel/Template/Element/Cell.pm_ +++ b/lib/Excel/Template/Element/Cell.pm_ @@ -49,8 +49,16 @@ sub render 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, ); diff --git a/lib/Excel/Template/Element/Range.pm b/lib/Excel/Template/Element/Range.pm new file mode 100755 index 0000000..c880654 --- /dev/null +++ b/lib/Excel/Template/Element/Range.pm @@ -0,0 +1,107 @@ +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... + + + + + + =SUM() + + +The formula in row 2 would be =SUM(B1:C1). + +=head1 AUTHOR + +Rob Kinyon (rkinyon@columbus.rr.com) + +=head1 SEE ALSO + +CELL, REF + +=cut diff --git a/lib/Excel/Template/Factory.pm b/lib/Excel/Template/Factory.pm index 1fc9cd3..7a0a6a4 100644 --- a/lib/Excel/Template/Factory.pm +++ b/lib/Excel/Template/Factory.pm @@ -16,13 +16,16 @@ BEGIN { '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', @@ -32,7 +35,7 @@ BEGIN { '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', @@ -52,6 +55,8 @@ BEGIN { ITALIC OUTLINE LOOP + BACKREF + RANGE ROW SHADOW STRIKEOUT @@ -135,6 +140,14 @@ sub isa : UNIVERSAL::isa(@_) } +sub is_embedded +{ + return unless @_ >= 1; + + isa( $_[0], $_ ) && return !!1 for qw( VAR BACKREF RANGE ); + return; +} + 1; __END__ @@ -144,19 +157,15 @@ Excel::Template::Factory =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 diff --git a/lib/Excel/Template/TextObject.pm_ b/lib/Excel/Template/TextObject.pm_ index db555d5..8fa6b47 100755 --- a/lib/Excel/Template/TextObject.pm_ +++ b/lib/Excel/Template/TextObject.pm_ @@ -38,7 +38,7 @@ UNI_NO my $t = ''; { 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;