Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for merging cells and autofilter parameter #1

Merged
merged 10 commits into from Aug 28, 2013
12 changes: 11 additions & 1 deletion lib/Spreadsheet/Template.pm
Expand Up @@ -45,6 +45,7 @@ been preprocessed is a JSON file, with a structure that looks like this:
"name" : "Sheet1",
"row_heights" : [ 18, 18, 18 ],
"selection" : [ 0, 0 ],
"autofilter" : [ 0, 0, 0, 3],
"cells" : [
[
{
Expand Down Expand Up @@ -104,7 +105,16 @@ been preprocessed is a JSON file, with a structure that looks like this:
"type" : "string"
}
]
]
],
merge : [
["contents":"Merged Contents","format":{"color":#000000"},
"type":"string",
"first_row": 0,
"first_col": 0,
"last_row" : 0,
"last_col" : 3
]
]
}
]
}
Expand Down
29 changes: 27 additions & 2 deletions lib/Spreadsheet/Template/Helpers/Xslate.pm
Expand Up @@ -10,10 +10,10 @@ use Sub::Exporter 'build_exporter';

my $import = build_exporter({
exports => [
map { $_ => \&_curry_package } qw(format c true false)
map { $_ => \&_curry_package } qw(format c merge true false)
],
groups => {
default => [qw(format c true false)],
default => [qw(format c merge true false)],
},
});

Expand All @@ -31,6 +31,30 @@ sub format {
return '';
}

sub merge {
my (
$package, $contents, $format, $type, $first_row,
$first_col, $last_row, $last_col, %args
) = @_;

return $JSON->encode(
{
contents => "$contents",
format => _formats( $package, $format ),
type => $type,
first_row => $first_row,
first_col => $first_col,
last_row => $last_row,
last_col => $last_col,
(
defined $args{formula}
? ( formula => $args{formula} )
: ()
),
}
);
}

sub c {
my ($package, $contents, $format, $type, %args) = @_;

Expand Down Expand Up @@ -66,6 +90,7 @@ sub _curry_package {

format
c
merge
true
false

Expand Down
10 changes: 10 additions & 0 deletions lib/Spreadsheet/Template/Processor/Xslate.pm
Expand Up @@ -39,6 +39,16 @@ C<"date_time">, and C<%args> contains any other parameters (such as C<formula>,
for instance) to declare for the cell. C<$type> is optional, and if not passed,
defaults to C<"string">.

=item merge($content, $format, $type, $first_row, $first_col, $last_row, $last_col, %args)

Returns representation of a range of cells to be merged. C<$content> is the
content to be placed in the merged cell.C<$format> is the name of a format
declared with the C<format> helper or a hashref of format options.
C<$type> is either C<"string">, C<"number">, or C<"date_time">.
C<$first_row>, C<$first_col>, C<$last_row>, C<$last_col> are zero-indexed
Excel row, column numbers. C<%args> contains any other parameters (such as C<formula>,
for instance) to declare for the cell.

=item true

Returns C<JSON::true>.
Expand Down
37 changes: 35 additions & 2 deletions lib/Spreadsheet/Template/Writer/Excel.pm
Expand Up @@ -152,6 +152,41 @@ sub _write_worksheet {
$self->_write_cell($data->{cells}[$row][$col], $sheet, $row, $col);
}
}

if ( exists $data->{merge} ) {
for my $i ( 0 .. $#{ $data->{merge} } ) {
my $merge = $data->{merge}[$i];
my $format = $merge->{format};
my $format_obj;
if ( exists $self->_formats->{$format} ) {
$format_obj = $self->_formats->{$format};
}
else {
$format_obj = $self->excel->add_format(%$format);
$self->_formats->{$format} = $format_obj;
}

$merge->{type} = 'formula' if defined $merge->{formula};

$sheet->merge_range_type(
$merge->{type},
$merge->{first_row},
$merge->{first_col},
$merge->{last_row},
$merge->{last_col},
defined $merge->{formula}
? $merge->{formula}
: $merge->{contents},
$format_obj,
defined $merge->{formula} ? $merge->{contents} : ()
);
}
}
if ( exists $data->{autofilter} ) {
my @autofilter = @{ $data->{autofilter} };
$sheet->autofilter( $autofilter[0], $autofilter[1], $autofilter[2],
$autofilter[3] );
}
}

sub _write_cell {
Expand Down Expand Up @@ -207,8 +242,6 @@ sub _write_cell {
$format = $self->_format($properties);
}

# XXX handle merged cells

if (defined $data->{formula}) {
$sheet->write_formula(
$row, $col,
Expand Down
41 changes: 41 additions & 0 deletions t/data/merge.json
@@ -0,0 +1,41 @@
%% my $default = { color => '#000000', size => 14 };
%% format(basic => $default.merge({bold => true(),align => 'left'}));

{
"selection" : 0,
"worksheets" : [
{
"column_widths" : [ 14.6, 18.5, 15.8, 12.2 ],
"name" : "Merge Report 1",
"selection" : [ 1, 9 ],
"row_heights" : [ 25, 18, 18, 18 ],
"cells" : [
%% for $headers -> $header {
[
[% c($header.value1, "basic") %],
[% c($header.value2, "basic") %],
[% c($header.value3, "basic") %],
[% c($header.value4, "basic") %]
],
%% }
%% for $rows -> $row {
[
[% c($row.value1, "basic", "number") %],
[% c($row.value2, "basic", "number") %],
[% c($row.value3, "basic", "number") %],
[% c($row.value4, "basic", "number") %]
],
%% }
[]
],
"merge" : [
[% merge('Merged Header', 'basic', 'string', 0,0,0,3) %],
[% merge($rows.map(-> $a {$a.value1}).reduce(-> $a,$b {$a + $b}), 'basic',
'number',
3,0,3,3,
formula => 'SUM(A2:A3)'
) %]
]
}
]
}
67 changes: 67 additions & 0 deletions t/merge.t
@@ -0,0 +1,67 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;

use Data::Dumper;

use Spreadsheet::ParseXLSX;
use Spreadsheet::Template;

my $template = Spreadsheet::Template->new;
my $data = do { local $/; local @ARGV = ('t/data/merge.json'); <> };

{
my $excel = $template->render(
$data,
{
headers => [
{
value1 => "Merge 1",
value2 => "Merge 2",
value3 => "Merge 3",
value4 => "Merge 4"
},
],
rows => [
{
value1 => "1",
value2 => '0',
value3 => '0',
value4 => '0'
},
{
value1 => "2",
value2 => '0',
value3 => '0',
value4 => '0'
}
],
}
);

open my $fh, '<', \$excel;
my $wb = Spreadsheet::ParseXLSX->new->parse($fh);
is($wb->worksheet_count, 1);

my $ws = $wb->worksheet(0);
is($ws->get_name, 'Merge Report 1');

# In the template, the 4 columns in row 1 are merged
# with contents = "Merged Cells"
for my $col (0..3) {
if ($col == 0) {
is($ws->get_cell(0, $col)->value, 'Merged Header');
} else {
is($ws->get_cell(0, $col)->value, '');
}
}
is($ws->get_cell(1,0)->value, 1);
is($ws->get_cell(2,0)->value, 2);
my $value1 = $ws->get_cell(1,0)->value;
my $value2 = $ws->get_cell(2,0)->value;
my $sum = $value1 + $value2;
is($ws->get_cell(3,0)->value, $sum);
}

done_testing;