[Catalyst-commits] r13909 - in
Catalyst-Action-Serialize-SimpleExcel/1.000/trunk: .
lib/Catalyst/Action/Serialize t t/lib/TestApp/Controller
caelum at dev.catalyst.perl.org
caelum at dev.catalyst.perl.org
Wed Jan 5 09:39:55 GMT 2011
Author: caelum
Date: 2011-01-05 09:39:55 +0000 (Wed, 05 Jan 2011)
New Revision: 13909
Removed:
Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/META.yml
Modified:
Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/Changes
Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/Makefile.PL
Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/lib/Catalyst/Action/Serialize/SimpleExcel.pm
Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/excel.t
Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/lib/TestApp/Controller/REST.pm
Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/pod.t
Log:
multiple worksheet support, release 0.014
Modified: Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/Changes
===================================================================
--- Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/Changes 2011-01-04 13:22:54 UTC (rev 13908)
+++ Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/Changes 2011-01-05 09:39:55 UTC (rev 13909)
@@ -1,5 +1,8 @@
Revision history for Catalyst-Action-Serialize-SimpleExcel
+0.014 2011-01-05 09:37:55
+ - Multiple worksheet support.
+
0.013 2009-09-24 10:22:22
Added $worksheet->keep_leading_zeros(1)
Deleted: Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/META.yml
===================================================================
--- Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/META.yml 2011-01-04 13:22:54 UTC (rev 13908)
+++ Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/META.yml 2011-01-05 09:39:55 UTC (rev 13909)
@@ -1,28 +0,0 @@
----
-abstract: 'Serialize tables to Excel files'
-author:
- - 'Rafael Kitover <rkitover at cpan.org>'
-build_requires:
- Spreadsheet::ParseExcel: 0
- Test::Deep: 0
- Test::More: 0
-distribution_type: module
-generated_by: 'Module::Install version 0.77'
-license: perl
-meta-spec:
- url: http://module-build.sourceforge.net/META-spec-v1.4.html
- version: 1.4
-name: Catalyst-Action-Serialize-SimpleExcel
-no_index:
- directory:
- - inc
- - t
-requires:
- Catalyst::Controller::REST: 0
- Scalar::Util: 0
- Spreadsheet::WriteExcel: 0
- namespace::clean: 0
- parent: 0
-resources:
- license: http://dev.perl.org/licenses/
-version: 0.012
Modified: Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/Makefile.PL
===================================================================
--- Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/Makefile.PL 2011-01-04 13:22:54 UTC (rev 13908)
+++ Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/Makefile.PL 2011-01-05 09:39:55 UTC (rev 13909)
@@ -9,7 +9,6 @@
requires 'Spreadsheet::WriteExcel';
requires 'parent';
requires 'namespace::clean';
-requires 'Scalar::Util';
test_requires 'Test::More';
test_requires 'Spreadsheet::ParseExcel';
Modified: Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/lib/Catalyst/Action/Serialize/SimpleExcel.pm
===================================================================
--- Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/lib/Catalyst/Action/Serialize/SimpleExcel.pm 2011-01-04 13:22:54 UTC (rev 13908)
+++ Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/lib/Catalyst/Action/Serialize/SimpleExcel.pm 2011-01-05 09:39:55 UTC (rev 13909)
@@ -4,21 +4,17 @@
use warnings;
no warnings 'uninitialized';
use parent 'Catalyst::Action';
-use Spreadsheet::WriteExcel;
-use Scalar::Util 'reftype';
+use Spreadsheet::WriteExcel ();
+use Catalyst::Exception ();
use namespace::clean;
=head1 NAME
-Catalyst::Action::Serialize::SimpleExcel - Serialize tables to Excel files
+Catalyst::Action::Serialize::SimpleExcel - Serialize to Excel files
-=head1 VERSION
-
-Version 0.013
-
=cut
-our $VERSION = '0.013';
+our $VERSION = '0.014';
=head1 SYNOPSIS
@@ -40,20 +36,40 @@
sub books_GET {
my ($self, $c) = @_;
- my $rs = $c->model('MyDB::Book')->search({}, {
+ my $books_rs = $c->model('MyDB::Book')->search({}, {
order_by => 'author,title'
});
- $rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
+ $books_rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
- my @t = map {
+ my @books = map {
[ @{$_}{qw/author title/} ]
- } $rs->all;
+ } $books_rs->all;
+ my $authors_rs = $c->model('MyDB::Author')->search({}, {
+ order_by => 'last_name,middle_name,last_name'
+ });
+
+ $authors_rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
+
+ my @authors = map {
+ [ @{$_}{qw/first_name middle_name last_name/} ]
+ } $authors_rs->all;
+
my $entity = {
- header => ['Author', 'Title'], # will be bold
- rows => \@t,
- # the part before .xls, which is automatically appended
+ sheets => [
+ {
+ name => 'Books',
+ header => ['Author', 'Title'], # will be bold
+ rows => \@books,
+ },
+ {
+ name => 'Authors',
+ header => ['First Name', 'Middle Name', 'Last Name'],
+ rows => \@authors,
+ },
+ ],
+ # the part before .xls, which is automatically appended
filename => 'myapp-books-'.strftime('%m-%d-%Y', localtime)
};
@@ -78,11 +94,26 @@
=head1 DESCRIPTION
-Your entity should be either an array of arrays or a hash with the keys as
-described below and in the L</SYNOPSIS>.
+Your entity should be either an array of arrays, an array of arrays of arrays,
+or a hash with the keys as described below and in the L</SYNOPSIS>.
If entity is a hashref, keys should be:
+=head2 sheets
+
+An array of worksheets. Either sheets or a worksheet specification at the top
+level is required.
+
+=head2 filename
+
+Optional. The name of the file before .xls. Defaults to "data".
+
+Each sheet should be an array of arrays, or a hashref with the following fields:
+
+=head2 name
+
+Optional. The name of the worksheet.
+
=head2 rows
Required. The array of arrays of rows.
@@ -96,10 +127,8 @@
Optional, the widths in characters of the columns. Otherwise the widths are
calculated automatically from the data and header.
-=head2 filename
+If you only have one sheet, you can put it in the top level hash.
-The name of the file before .xls. Defaults to "data".
-
=cut
sub execute {
@@ -114,12 +143,89 @@
my $data = $c->stash->{$stash_key};
- $data = { rows => $data } if reftype $data eq 'ARRAY';
-
open my $fh, '>', \my $buf;
my $workbook = Spreadsheet::WriteExcel->new($fh);
- my $worksheet = $workbook->add_worksheet;
+ my ($filename, $sheets) = $self->_parse_entity($data);
+
+ for my $sheet (@$sheets) {
+ $self->_add_sheet($workbook, $sheet);
+ }
+
+ $workbook->close;
+
+ $self->_write_file($c, $filename, $buf);
+
+ return 1;
+}
+
+sub _write_file {
+ my ($self, $c, $filename, $data) = @_;
+
+ $c->res->content_type('application/vnd.ms-excel');
+ $c->res->header('Content-Disposition' =>
+ "attachment; filename=${filename}.xls");
+ $c->res->output($data);
+}
+
+sub _parse_entity {
+ my ($self, $data) = @_;
+
+ my @sheets;
+ my $filename = 'data'; # default
+
+ if (ref $data eq 'ARRAY') {
+ if (not ref $data->[0][0]) {
+ $sheets[0] = { rows => $data };
+ }
+ else {
+ @sheets = map
+ ref $_ eq 'HASH' ? $_
+ : ref $_ eq 'ARRAY' ? { rows => $_ }
+ : Catalyst::Exception->throw(
+ 'Unsupported sheet reference type: '.ref($_)), @{ $data };
+ }
+ }
+ elsif (ref $data eq 'HASH') {
+ $filename = $data->{filename} if $data->{filename};
+
+ my $sheets = $data->{sheets};
+ my $rows = $data->{rows};
+
+ if ($sheets && $rows) {
+ Catalyst::Exception->throw('Use either sheets or rows, not both.');
+ }
+
+ if ($sheets) {
+ @sheets = map
+ ref $_ eq 'HASH' ? $_
+ : ref $_ eq 'ARRAY' ? { rows => $_ }
+ : Catalyst::Exception->throw(
+ 'Unsupported sheet reference type: '.ref($_)), @{ $sheets };
+ }
+ elsif ($rows) {
+ $sheets[0] = $data;
+ }
+ else {
+ Catalyst::Exception->throw('Must supply either sheets or rows.');
+ }
+ }
+ else {
+ Catalyst::Exception->throw(
+ 'Unsupported workbook reference type: '.ref($data)
+ );
+ }
+
+ return ($filename, \@sheets);
+}
+
+sub _add_sheet {
+ my ($self, $workbook, $sheet) = @_;
+
+ my $worksheet = $workbook->add_worksheet(
+ $sheet->{name} ? $sheet->{name} : ()
+ );
+
$worksheet->keep_leading_zeros(1);
my ($row, $col) = (0,0);
@@ -127,10 +233,10 @@
my @auto_widths;
# Write Header
- if (exists $data->{header}) {
+ if (exists $sheet->{header}) {
my $header_format = $workbook->add_format;
$header_format->set_bold;
- for my $header (@{ $data->{header} }) {
+ for my $header (@{ $sheet->{header} }) {
$auto_widths[$col] = length $header
if $auto_widths[$col] < length $header;
@@ -141,7 +247,7 @@
}
# Write data
- for my $the_row (@{ $data->{rows} }) {
+ for my $the_row (@{ $sheet->{rows} }) {
for my $the_col (@$the_row) {
$auto_widths[$col] = length $the_col
if $auto_widths[$col] < length $the_col;
@@ -153,27 +259,17 @@
}
# Set column widths
- $data->{column_widths} = \@auto_widths
- unless exists $data->{column_widths};
+ $sheet->{column_widths} = \@auto_widths
+ unless exists $sheet->{column_widths};
- for my $width (@{ $data->{column_widths} }) {
+ for my $width (@{ $sheet->{column_widths} }) {
$worksheet->set_column($col, $col++, $width);
}
# Have to set the width of column 0 again, otherwise Excel loses it!
# I don't know why...
- $worksheet->set_column(0, 0, $data->{column_widths}[0]);
- $col = 0;
+ $worksheet->set_column(0, 0, $sheet->{column_widths}[0]);
-# Write the file
- my $filename = $data->{filename} || 'data';
-
- $workbook->close;
- $c->res->content_type('application/vnd.ms-excel');
- $c->res->header('Content-Disposition' =>
- "attachment; filename=${filename}.xls");
- $c->res->output($buf);
-
- 1;
+ return $worksheet;
}
=head1 AUTHOR
@@ -192,16 +288,6 @@
L<Catalyst::View::Excel::Template::Plus>, L<Spreadsheet::WriteExcel>,
L<Spreadsheet::ParseExcel>
-=head1 TODO
-
-=over 4
-
-=item * Split into mutliple overridable methods.
-
-=item * Multiple sheet support.
-
-=back
-
=head1 SUPPORT
You can find documentation for this module with the perldoc command.
@@ -232,7 +318,7 @@
=head1 COPYRIGHT & LICENSE
-Copyright (c) 2008 Rafael Kitover
+Copyright (c) 2008-2011 Rafael Kitover
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
Modified: Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/excel.t
===================================================================
--- Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/excel.t 2011-01-04 13:22:54 UTC (rev 13908)
+++ Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/excel.t 2011-01-05 09:39:55 UTC (rev 13909)
@@ -7,13 +7,14 @@
use Catalyst::Test 'TestApp';
use Spreadsheet::ParseExcel ();
-use Test::More tests => 17;
+use Test::More tests => 31;
use Test::Deep;
# Test array of array
ok((my $file = get '/rest/a_o_a?content-type=application%2Fvnd.ms-excel'),
'received file');
+
ok((my $excel = Spreadsheet::ParseExcel::Workbook->Parse(\$file)),
'parsed file');
my $sheet = $excel->{Worksheet}[0];
@@ -25,6 +26,7 @@
);
# test that number-like data does not get numified
+
ok(($file = get '/rest/no_numify?content-type=application%2Fvnd.ms-excel'),
'received file');
ok(($excel = Spreadsheet::ParseExcel::Workbook->Parse(\$file)),
@@ -59,8 +61,29 @@
'auto_widths -> sheet'
);
-# Test everything else
+# Test multiple worksheets as array of array of array
+ok(($file = get '/rest/multi_worksheet_a_o_a_o_a?content-type=application%2Fvnd.ms-excel'),
+ 'received file');
+ok(($excel = Spreadsheet::ParseExcel::Workbook->Parse(\$file)),
+ 'parsed file');
+my $sheet1 = $excel->{Worksheet}[0];
+my $sheet2 = $excel->{Worksheet}[1];
+
+cmp_deeply(
+ read_sheet($sheet1),
+ [[1,2,3],[4,5,6]],
+ 'multi worksheet array_of_array_of_array -> sheet1'
+);
+
+cmp_deeply(
+ read_sheet($sheet2),
+ [[7,8,9],[10,11,12]],
+ 'multi worksheet array_of_array_of_array -> sheet2'
+);
+
+# Test hashref with options
+
ok((my $resp = request '/rest/fancy?content-type=application%2Fvnd.ms-excel'),
'received response');
@@ -86,6 +109,45 @@
'with options -> sheet'
);
+# Test multiple worksheets as hash
+
+ok(($resp = request '/rest/multi_worksheet_hash?content-type=application%2Fvnd.ms-excel'),
+ 'received response');
+
+is($resp->header('Content-Type'), 'application/vnd.ms-excel', 'Content-Type');
+
+is($resp->header('Content-Disposition'), 'attachment; filename=mtfnpy.xls', 'Content-Disposition');
+
+ok(($file = $resp->content), 'received file');
+
+ok(($excel = Spreadsheet::ParseExcel::Workbook->Parse(\$file)), 'parsed file');
+
+$sheet1 = $excel->{Worksheet}[0];
+$sheet2 = $excel->{Worksheet}[1];
+my $sheet3 = $excel->{Worksheet}[2];
+
+is eval { $sheet1->get_name }, 'MySheet1', 'multi sheets hash -> sheet1 name';
+
+cmp_deeply(
+ read_sheet($sheet1),
+ [ [qw/Foo Bar/], [1,2], [3,4] ],
+ 'multi sheets hash -> sheet1'
+);
+
+is eval { $sheet2->get_name }, 'MySheet2', 'multi sheets hash -> sheet2 name';
+
+cmp_deeply(
+ read_sheet($sheet2),
+ [ [qw/Baz Quux/], [5,6], [7,8] ],
+ 'multi sheets hash -> sheet2'
+);
+
+cmp_deeply(
+ read_sheet($sheet3),
+ [ [9,10], [11,12] ],
+ 'multi sheets hash -> sheet3 (as array)'
+);
+
sub read_sheet {
my $sheet = shift;
my $res;
Modified: Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/lib/TestApp/Controller/REST.pm
===================================================================
--- Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/lib/TestApp/Controller/REST.pm 2011-01-04 13:22:54 UTC (rev 13908)
+++ Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/lib/TestApp/Controller/REST.pm 2011-01-05 09:39:55 UTC (rev 13909)
@@ -15,11 +15,31 @@
$c,
entity => [
[1,2,3],
- [4,5,6]
+ [4,5,6],
]
);
}
+sub multi_worksheet_a_o_a_o_a : Local ActionClass('REST') {}
+
+sub multi_worksheet_a_o_a_o_a_GET {
+ my ($self, $c) = @_;
+
+ $self->status_ok(
+ $c,
+ entity => [
+ [
+ [1,2,3],
+ [4,5,6],
+ ],
+ [
+ [7,8,9],
+ [10,11,12],
+ ],
+ ],
+ );
+}
+
sub no_numify : Local ActionClass('REST') {}
# test that strings that parse as numbers pass through unmolested
@@ -30,7 +50,7 @@
$c,
entity => [
['01',' 2',3],
- [4,5,'006']
+ [4,5,'006'],
]
);
}
@@ -47,13 +67,48 @@
column_widths => [10, 20],
rows => [
[1,2],
- [3,4]
+ [3,4],
],
filename => 'mtfnpy'
}
);
}
+sub multi_worksheet_hash : Local ActionClass('REST') {}
+
+sub multi_worksheet_hash_GET {
+ my ($self, $c) = @_;
+
+ $self->status_ok(
+ $c,
+ entity => {
+ sheets => [
+ {
+ name => 'MySheet1',
+ header => [qw/Foo Bar/],
+ rows => [
+ [1,2],
+ [3,4],
+ ],
+ },
+ {
+ name => 'MySheet2',
+ header => [qw/Baz Quux/],
+ rows => [
+ [5,6],
+ [7,8],
+ ],
+ },
+ [
+ [9,10],
+ [11,12],
+ ],
+ ],
+ filename => 'mtfnpy'
+ },
+ );
+}
+
sub auto_widths : Local ActionClass('REST') {}
sub auto_widths_GET {
@@ -65,7 +120,7 @@
header => [qw/Foo Bar/],
rows => [
[1,2],
- [3,999999]
+ [3,999999],
],
filename => 'mtfnpy'
}
Modified: Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/pod.t
===================================================================
--- Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/pod.t 2011-01-04 13:22:54 UTC (rev 13908)
+++ Catalyst-Action-Serialize-SimpleExcel/1.000/trunk/t/pod.t 2011-01-05 09:39:55 UTC (rev 13909)
@@ -1,5 +1,3 @@
-#!perl -T
-
use strict;
use warnings;
use Test::More;
More information about the Catalyst-commits
mailing list