Data-Report-1.001/0000755000400000040000000000000013620061360011430 5ustar jvjvData-Report-1.001/t/0000755000400000040000000000000013620061360011673 5ustar jvjvData-Report-1.001/t/03csv04.t0000644000400000040000000000233111046634022013162 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create (type => "csv", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); my $out = ""; $rep->set_stylist(sub { my ($self, $row, $col) = @_; return { ignore => 1 } if $row && $row eq "total" && !$col; return; }); $rep->set_output(\$out); $rep->set_separator(":") if $rep->get_type eq "csv"; $rep->start; $rep->add({ acct => 1234, desc => "two", deb => "three", crd => "four" }); $rep->add({ acct => 1235, desc => "two", deb => "three", crd => "four" }); $rep->add({ acct => 1236, desc => "two", deb => "three", crd => "four" }); $rep->add({ desc => "total", deb => "three", crd => "four", _style => "total" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = } $ref =~ s/[\r\n]/\n/g; $out =~ s/[\r\n]/\n/g; is($out, $ref); __DATA__ "Acct":"Report":"Debet":"Credit" "1234":"two":"three":"four" "1235":"two":"three":"four" "1236":"two":"three":"four" Data-Report-1.001/t/01text02.t0000644000400000040000000000276410425414131013356 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $data = "01text.out"; $data = "t/$data" if -d "t"; my $rep = Data::Report::->create (type => "text", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); $rep->set_output($data); $rep->start; $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four" }); $rep->finish; $rep->close; undef $/; my $ref = ; open(my $fh, "<", $data); my $out = <$fh>; close($fh); $ref =~ s/[\r\n]/\n/g; $out =~ s/[\r\n]/\n/g; is($out, $ref); unlink($data) if $out eq $ref; # Same, capturing output in a scalar. $out = ""; $rep->set_output(\$out); $rep->start; $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four" }); $rep->finish; $rep->close; $out =~ s/[\r\n]/\n/g; is($out, $ref); # Same, capturing output in an array. my @out; $rep->set_output(\@out); $rep->start; $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four" }); $rep->finish; $rep->close; $out = join("", @out); $out =~ s/[\r\n]/\n/g; is($out, $ref); __DATA__ Acct Report Debet Credit ------------------------------------------------------------------------ one two three four Data-Report-1.001/t/03csv01.t0000644000400000040000000000102510425414322013155 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create (type => "csv", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); my $out = ""; $rep->set_output(\$out); $rep->start; $rep->finish; $rep->close; is($out, ""); Data-Report-1.001/t/02html03.t0000644000400000040000000000317611052242454013342 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $out = ""; my $rep = Data::Report::->create (type => "html", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); $rep->set_stylist( sub { my ($rep, $row, $col) = @_; return unless $col; return { class => "bar" } if $row && $row eq "_head" && $col && $col eq "deb"; return { class => "foo" } if $col eq "deb"; return; } ); $rep->set_output(\$out); $rep->start; $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "xyz" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = } $ref =~ s/[\r\n]/\n/g; $out =~ s/[\r\n]/\n/g; is($out, $ref); __DATA__
Acct Report Debet Credit
one two three four
one two three four
Data-Report-1.001/t/09poc06.t0000644000400000040000000000420111046611442013157 0ustar jvjv#! perl use strict; use warnings; use Test::More tests => 2; package POC::Report; use base qw(Data::Report); package POC::Report::Html; use base qw(Data::Report::Plugin::Html); sub _std_stylist { my ($rep, $row, $col) = @_; return unless $col; return { raw_html => 1 } if $col eq "address"; return { ignore => 1 } if $col =~ /^city|zip$/; return; } sub add { my ($self, $data) = @_; $data->{address} = join('
', map { $self->_html($_) } @$data{qw(address city zip)}); $self->SUPER::add($data); } package main; my $rep = POC::Report::->create(type => "html"); isa_ok($rep, 'POC::Report::Html'); $rep->set_layout( [ { name => "id", title => "ID", width => 4 }, { name => "name", title => "Name", width => 20 }, { name => "address", title => "Address", width => 40 }, { name => "city", title => "City", width => 20 }, { name => "zip", title => "Zip", width => 10 }, ] ); my $out = ""; $rep->set_output(\$out); $rep->start(); $rep->add( { id => 1, name => "Rijksmuseum", address => "Museumplein", city => "Amsterdam", zip => "1000 AA", _style => "normal" } ); $rep->add( { id => 2, name => "Kabouterland", address => "Zuid&einde", city => "Exloo", zip => "7889 AA", _style => "normal" } ); $rep->finish; $rep->close; my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; is($out, $ref, "contents"); __DATA__
ID Name Address
1 Rijksmuseum Museumplein
Amsterdam
1000 AA
2 Kabouterland Zuid&einde
Exloo
7889 AA
Data-Report-1.001/t/09poc04.t0000644000400000040000000000663110427174070013171 0ustar jvjv#! perl use strict; use warnings; use Test::More tests => 4; package POC::Report; use base qw(Data::Report); package POC::Report::Html; use base qw(Data::Report::Plugin::Html); sub start { my $self = shift; $self->_argcheck(3); $self->{_title1} = shift; $self->{_title2} = shift; $self->{_title3} = shift; $self->SUPER::start; } sub _std_heading { my $self = shift; $self->_print("\n", "\n", "", $self->_html($self->{_title1}), "\n", '', "\n", "\n", "\n", "

", $self->_html($self->{_title1}), "

\n", "

", $self->_html($self->{_title2}), "
\n", $self->_html($self->{_title3}), "

\n"); $self->SUPER::_std_heading; } sub _std_stylist { my ($rep, $row, $col) = @_; return { line_after => 1 } if $row eq "total" && !$col; return; } sub finish { my $self = shift; $self->_argcheck(0); $self->SUPER::finish; $self->_print("\n\n"); } package main; my $rep = POC::Report::->create(type => "html"); isa_ok($rep, 'POC::Report::Html'); $rep->set_layout ([ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ]); my $out = ""; $rep->set_output(\$out); $rep->start(qw(Title_One Title_Two Title_Three_Left&Right)); is($rep->get_stylist, \&POC::Report::Html::_std_stylist, "CB: stylist"); is($rep->get_heading, \&POC::Report::Html::_std_heading, "CB: heading"); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "total" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; is($out, $ref, "contents"); __DATA__ Title_One

Title_One

Title_Two
Title_Three_Left&Right

Acct Report Debet Credit
one two three four
one two three four
one two three four
one two three four
Data-Report-1.001/t/01text04.t0000644000400000040000000000375310425400377013366 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create(type => "text", stylist => \&my_stylist); $rep->set_layout ([ { name => "acct", title => "Acct", width => 6, truncate => 1 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ]); my $out = ""; $rep->set_output(\$out); $rep->set_fields([qw(desc crd deb acct)]); $rep->start; $rep->add({ acct => "one two", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "total" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; is($out, $ref); sub my_stylist { my ($rep, $row, $col) = @_; unless ( $col ) { return { line_after => 1 } if $row eq "total"; return; } return { line_after => 1 } if $col eq "deb"; return; } __DATA__ Report Credit Debet Acct ------------------------------------------------------------------------ two four three one tw ---------- two four three one ---------- two four three one ---------- two four three one ---------- ------------------------------------------------------------------------ Data-Report-1.001/t/02html01.t0000644000400000040000000000102610425414302013324 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create (type => "html", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); my $out = ""; $rep->set_output(\$out); $rep->start; $rep->finish; $rep->close; is($out, ""); Data-Report-1.001/t/02html02.t0000644000400000040000000000256710427174572013356 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $out = ""; my $rep = Data::Report::->create (type => "html", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); $rep->set_output(\$out); $rep->start; $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "xyz" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = } $ref =~ s/[\r\n]/\n/g; $out =~ s/[\r\n]/\n/g; is($out, $ref); __DATA__
Acct Report Debet Credit
one two three four
one two three four
Data-Report-1.001/t/03csv05.t0000644000400000040000000000225311046634037013174 0ustar jvjv#! perl use strict; use warnings; use Test::More; plan(tests => 1); use Data::Report; my $rep = Data::Report::->create (type => "csv", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); my $out = ""; $rep->set_stylist(sub { my ($self, $row, $col) = @_; return { ignore => 1 } if $row && $row eq "total" && !$col; return; }); $rep->set_output(\$out); $rep->start; $rep->add({ acct => 1234, desc => "two", deb => "thrëe", crd => "four" }); $rep->add({ acct => 1235, desc => "two", deb => "thrée", crd => "four" }); $rep->add({ acct => 1236, desc => "two", deb => "thrÿe", crd => "four" }); $rep->add({ desc => "total", deb => "three", crd => "four", _style => "total" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = } $ref =~ s/[\r\n]/\n/g; $out =~ s/[\r\n]/\n/g; is($out, $ref); __DATA__ "Acct","Report","Debet","Credit" "1234","two","thrëe","four" "1235","two","thrée","four" "1236","two","thrÿe","four" Data-Report-1.001/t/09poc05.t0000644000400000040000000001134211045337231013162 0ustar jvjv#! perl use strict; use warnings; use Test::More tests => 4; package POC::Report; use base qw(Data::Report); package POC::Report::Html; use base qw(Data::Report::Plugin::Html); sub start { my $self = shift; $self->_argcheck(3); $self->{_title1} = shift; $self->{_title2} = shift; $self->{_title3} = shift; $self->SUPER::start; } sub _top_heading { my $self = shift; $self->_print("\n", "\n", "", $self->_html($self->{_title1}), "\n", '', "\n", "\n", "\n", "
\n", "

", $self->_html($self->{_title1}), "

\n", "

", $self->_html($self->{_title2}), "
\n", $self->_html($self->{_title3}), "

\n"); } sub _std_stylist { my ($rep, $row, $col) = @_; # No style mods. return; } sub finish { my $self = shift; $self->_argcheck(0); $self->SUPER::finish; $self->_print("
\n\n\n"); } package main; my $rep = POC::Report::->create(type => "html", stylist => \&my_stylist); isa_ok($rep, 'POC::Report::Html'); $rep->set_layout( [ { name => "check", title => "Check", width => 5, align => "|", }, { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ] ); my $out = ""; $rep->set_output(\$out); $rep->start(qw(Title_One Title_Two Title_Three_Left&Right)); is($rep->get_stylist, \&main::my_stylist, "CB: stylist"); is($rep->get_topheading, \&POC::Report::Html::_top_heading, "CB: heading"); $rep->add( { check => "", acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" } ); $rep->add( { check => "", acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" } ); $rep->add( { check => "", acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" } ); $rep->add( { check => "", acct => "one", desc => "two", deb => "three", crd => "four", _style => "total" } ); $rep->finish; $rep->close; my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; is($out, $ref, "contents"); sub my_stylist { my ($rep, $row, $col) = @_; # Enable raw HTML contents for the 'check' column. return { raw_html => 1 } if $col && $col eq "check"; return; } __DATA__ Title_One

Title_One

Title_Two
Title_Three_Left&Right

Check Acct Report Debet Credit
one two three four
one two three four
one two three four
one two three four
Data-Report-1.001/t/09poc03.t0000644000400000040000000000446310434414132013163 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); package POC::Report; use base qw(Data::Report); package POC::Report::Text; use base qw(Data::Report::Plugin::Text); sub _std_heading { my $self = shift; $self->_print("Title line 1\n"); $self->_print("Title line 2\n"); $self->_print("\n"); $self->SUPER::_std_heading; } sub _std_stylist { my ($rep, $row, $col) = @_; if ( $col ) { return { line_after => "=" } if $row eq "special" && $col =~ /^(deb|crd)$/; } else { return { line_after => 1 } if $row eq "total"; } return; } package main; my $rep = POC::Report::->create(type => "text"); isa_ok($rep, 'POC::Report::Text'); $rep->set_layout ([ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ]); my $out = ""; $rep->set_output(\$out); $rep->start; is($rep->get_stylist, \&POC::Report::Text::_std_stylist, "CB: stylist"); is($rep->get_heading, \&POC::Report::Text::_std_heading, "CB: heading"); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "special"}); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "total" }); $rep->finish; $rep->close; is($rep->{lines}, $= - 11, "linecount"); my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; is($out, $ref, "contents"); __DATA__ Title line 1 Title line 2 Acct Report Debet Credit ------------------------------------------------------------------------ one two three four one two three four one two three four ========== ========== one two three four ------------------------------------------------------------------------ Data-Report-1.001/t/01text07.t0000644000400000040000000000363511046651211013363 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create(type => "text", stylist => \&my_stylist); $rep->set_layout ([ { name => "one", title => "One", width => 10, }, { name => "two", title => "Two", width => 11, }, { name => "thr", title => "Three", width => 12, }, { name => "fou", title => "Four", width => 13, }, { name => "fiv", title => "Five", width => 14, }, ]); my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; my $out = ""; my $dd = "The quick brown fox jumps over the lazy dog."; $dd = "$dd $dd $dd"; $rep->set_output(\$out); $rep->start; $rep->add({ one => $dd, two => $dd, thr => $dd, fou => $dd, fiv => $dd }); $rep->finish; is($out, $ref); sub my_stylist { my ($rep, $row, $col) = @_; return unless defined $col; return { ignore => 1, indent => 2 } if $col eq "two"; return { indent => 1, wrap_indent => 0 } if $col eq "thr"; return { wrap_indent => 2 } if $col eq "fou"; return { indent => 1, wrap_indent => 2 } if $col eq "fiv"; return; } __DATA__ One Three Four Five ------------------------------------------------------- The quick The quick The quick The quick brown fox brown fox brown fox brown fox jumps over jumps over jumps over jumps over the lazy the lazy the lazy the lazy dog. The dog. The dog. The dog. The quick quick brown quick brown quick brown brown fox fox jumps fox jumps fox jumps jumps over over the over the over the the lazy lazy dog. lazy dog. lazy dog. dog. The The quick The quick The quick quick brown fox brown fox brown fox brown fox jumps over jumps over jumps over jumps over the lazy the lazy the lazy the lazy dog. dog. dog. dog. Data-Report-1.001/t/00basic.t0000644000400000040000000000055113620052460013303 0ustar jvjv#! perl use strict; use warnings; use Test::More tests => 5; BEGIN { use_ok('Data::Report'); } BEGIN { use_ok('Data::Report::Base'); } BEGIN { use_ok('Data::Report::Plugin::Text'); } BEGIN { use_ok('Data::Report::Plugin::Html'); } BEGIN { use_ok('Data::Report::Plugin::Csv' ); } diag( "Testing Data::Report $Data::Report::VERSION, ". "Perl $], $^X" ); Data-Report-1.001/t/03csv02.t0000644000400000040000000000336010442021144013155 0ustar jvjv#! perl ################################################################ #### #### #### BIG FAT WARNING BIG FAT WARNING #### #### #### ################################################################ #### #### This test is for the Data::Report internals only. It contains #### trickery that is not suitable for end users. Please do not attempt #### to borrow any of these tricks. #### #### In particular, the method _set_csv_method exists only for this #### test and should never be used for other purposes. You have been #### warned. use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create (type => "csv", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); my $ref; { undef $/; $ref = } $ref =~ s/[\r\n]/\n/g; my $out; SKIP: { skip "Text::CSV_XS not found", 1 unless eval { require Text::CSV_XS }; dotest(Text::CSV_XS::); } SKIP: { skip "Text::CSV not found", 1 unless eval { require Text::CSV }; dotest(Text::CSV::); } dotest(); sub dotest { my ($cls) = shift; $out = ""; $rep->set_output(\$out); $rep->start; $rep->_set_csv_method($cls); $rep->add({ acct => 1234, desc => "two two", deb => "th,ree", crd => '"four"' }); $rep->finish; $out =~ s/[\r\n]/\n/g; is($out, $ref); } __DATA__ "Acct","Report","Debet","Credit" "1234","two two","th,ree","""four""" Data-Report-1.001/t/01text05.t0000644000400000040000000000327710434545523013373 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create(type => "text"); $rep->set_layout ([ { name => "one", title => "One", width => 10, }, { name => "two", title => "Two", width => 11, }, { name => "thr", title => "Three", width => 12, }, { name => "fou", title => "Four", width => 13, }, { name => "fiv", title => "Five", width => 14, }, ]); my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; my $out = ""; my $dd = "The quick brown fox jumps over the lazy dog."; $dd = "$dd $dd $dd"; $rep->set_output(\$out); $rep->start; $rep->add({ one => $dd, two => $dd, thr => $dd, fou => $dd, fiv => $dd }); $rep->finish; is($out, $ref); __DATA__ One Two Three Four Five -------------------------------------------------------------------- The quick The quick The quick The quick The quick brown fox brown fox brown fox brown fox brown fox jumps over jumps over jumps over jumps over jumps over the the lazy the lazy the lazy the lazy dog. lazy dog. The dog. The dog. The dog. The The quick quick brown quick quick brown quick brown brown fox fox jumps over brown fox fox jumps fox jumps jumps over the lazy dog. jumps over over the over the the lazy dog. The quick the lazy lazy dog. lazy dog. The quick brown fox dog. The The quick The quick brown fox jumps over the quick brown fox brown fox jumps over lazy dog. brown fox jumps over jumps over the lazy dog. jumps over the lazy the lazy the lazy dog. dog. dog. Data-Report-1.001/t/01text03.t0000644000400000040000000000171010425173147013356 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create(type => "text"); $rep->set_layout ([ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ]); my $out = ""; $rep->set_output(\$out); $rep->set_fields([qw(desc crd deb acct)]); $rep->set_width({ deb => 9, crd => '-1' }); $rep->start; $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; is($out, $ref); __DATA__ Report Credit Debet Acct ---------------------------------------------------------------------- two four three one Data-Report-1.001/t/09poc02.t0000644000400000040000000000657410434360675013203 0ustar jvjv#! perl use strict; use warnings; use Test::More tests => 4; package POC::Report; use base qw(Data::Report); package POC::Report::Html; use base qw(Data::Report::Plugin::Html); sub start { my $self = shift; $self->_argcheck(3); $self->{_title1} = shift; $self->{_title2} = shift; $self->{_title3} = shift; $self->SUPER::start; } sub _top_heading { my $self = shift; $self->_print("\n", "\n", "", $self->_html($self->{_title1}), "\n", '', "\n", "\n", "\n", "

", $self->_html($self->{_title1}), "

\n", "

", $self->_html($self->{_title2}), "
\n", $self->_html($self->{_title3}), "

\n"); } sub _std_stylist { my ($rep, $row, $col) = @_; return { line_after => 1 } if $row eq "total" && !$col; return; } sub finish { my $self = shift; $self->_argcheck(0); $self->SUPER::finish; $self->_print("\n\n"); } package main; my $rep = POC::Report::->create(type => "html"); isa_ok($rep, 'POC::Report::Html'); $rep->set_layout ([ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ]); my $out = ""; $rep->set_output(\$out); $rep->start(qw(Title_One Title_Two Title_Three_Left&Right)); is($rep->get_stylist, \&POC::Report::Html::_std_stylist, "CB: stylist"); is($rep->get_topheading, \&POC::Report::Html::_top_heading, "CB: heading"); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "total" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; is($out, $ref, "contents"); __DATA__ Title_One

Title_One

Title_Two
Title_Three_Left&Right

Acct Report Debet Credit
one two three four
one two three four
one two three four
one two three four
Data-Report-1.001/t/03csv06.t0000644000400000040000000000234611046651375013204 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create (type => "csv", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); my $out = ""; $rep->set_stylist(sub { my ($self, $row, $col) = @_; return { ignore => 1 } if $row && $row eq "total" && !$col; return { ignore => 1 } if $col eq "deb"; return; }); $rep->set_output(\$out); $rep->set_separator(":") if $rep->get_type eq "csv"; $rep->start; $rep->add({ acct => 1234, desc => "two", deb => "three", crd => "four" }); $rep->add({ acct => 1235, desc => "two", deb => "three", crd => "four" }); $rep->add({ acct => 1236, desc => "two", deb => "three", crd => "four" }); $rep->add({ desc => "total", deb => "three", crd => "four", _style => "total" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = } $ref =~ s/[\r\n]/\n/g; $out =~ s/[\r\n]/\n/g; is($out, $ref); __DATA__ "Acct":"Report":"Credit" "1234":"two":"four" "1235":"two":"four" "1236":"two":"four" Data-Report-1.001/t/09poc01.t0000644000400000040000000000442610434360527013170 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); package POC::Report; use base qw(Data::Report); package POC::Report::Text; use base qw(Data::Report::Plugin::Text); sub _top_heading { my $self = shift; $self->_print("Title line 1\n"); $self->_print("Title line 2\n"); $self->_print("\n"); } sub _std_stylist { my ($rep, $row, $col) = @_; if ( $col ) { return { line_after => "=" } if $row eq "special" && $col =~ /^(deb|crd)$/; } else { return { line_after => 1 } if $row eq "total"; } return; } package main; my $rep = POC::Report::->create(type => "text"); isa_ok($rep, 'POC::Report::Text'); $rep->set_layout ([ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ]); my $out = ""; $rep->set_output(\$out); $rep->start; is($rep->get_stylist, \&POC::Report::Text::_std_stylist, "CB: stylist"); is($rep->get_topheading, \&POC::Report::Text::_top_heading, "CB: heading"); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "special"}); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "total" }); $rep->finish; $rep->close; is($rep->{lines}, $= - 11, "linecount"); my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; is($out, $ref, "contents"); __DATA__ Title line 1 Title line 2 Acct Report Debet Credit ------------------------------------------------------------------------ one two three four one two three four one two three four ========== ========== one two three four ------------------------------------------------------------------------ Data-Report-1.001/t/01text01.t0000644000400000040000000000107610425414047013356 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create (layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); isa_ok($rep, 'Data::Report::Plugin::Text'); my $data = ""; $rep->set_output(\$data); $rep->start; $rep->finish; $rep->close; is($data, "", "contents"); Data-Report-1.001/t/03csv03.t0000644000400000040000000000224411046633755013200 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create (type => "csv", layout => [ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "|" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ], ); my $out = ""; $rep->set_stylist(sub { my ($self, $row, $col) = @_; return { ignore => 1 } if $row && $row eq "total" && !$col; return; }); $rep->set_output(\$out); $rep->start; $rep->add({ acct => 1234, desc => "two", deb => "three", crd => "four" }); $rep->add({ acct => 1235, desc => "two", deb => "three", crd => "four" }); $rep->add({ acct => 1236, desc => "two", deb => "three", crd => "four" }); $rep->add({ desc => "total", deb => "three", crd => "four", _style => "total" }); $rep->finish; $rep->close; my $ref; { undef $/; $ref = } $ref =~ s/[\r\n]/\n/g; $out =~ s/[\r\n]/\n/g; is($out, $ref); __DATA__ "Acct","Report","Debet","Credit" "1234","two","three","four" "1235","two","three","four" "1236","two","three","four" Data-Report-1.001/t/01text06.t0000644000400000040000000000416310434545361013367 0ustar jvjv#! perl use strict; use warnings; use Test::More qw(no_plan); use Data::Report; my $rep = Data::Report::->create(type => "text", stylist => \&my_stylist); $rep->set_layout ([ { name => "one", title => "One", width => 10, }, { name => "two", title => "Two", width => 11, }, { name => "thr", title => "Three", width => 12, }, { name => "fou", title => "Four", width => 13, }, { name => "fiv", title => "Five", width => 14, }, ]); my $ref; { undef $/; $ref = ; } $ref =~ s/[\r\n]/\n/g; my $out = ""; my $dd = "The quick brown fox jumps over the lazy dog."; $dd = "$dd $dd $dd"; $rep->set_output(\$out); $rep->start; $rep->add({ one => $dd, two => $dd, thr => $dd, fou => $dd, fiv => $dd }); $rep->finish; is($out, $ref); sub my_stylist { my ($rep, $row, $col) = @_; return unless defined $col; return { indent => 2 } if $col eq "two"; return { indent => 1, wrap_indent => 0 } if $col eq "thr"; return { wrap_indent => 2 } if $col eq "fou"; return { indent => 1, wrap_indent => 2 } if $col eq "fiv"; return; } __DATA__ One Two Three Four Five -------------------------------------------------------------------- The quick The quick The quick The quick The quick brown fox brown fox brown fox brown fox brown fox jumps over jumps jumps over jumps over jumps over the lazy over the the lazy the lazy the lazy dog. The lazy dog. dog. The dog. The dog. The quick The quick quick brown quick brown quick brown brown fox brown fox fox jumps fox jumps fox jumps jumps over jumps over the over the over the the lazy over the lazy dog. lazy dog. lazy dog. dog. The lazy dog. The quick The quick The quick quick The quick brown fox brown fox brown fox brown fox brown fox jumps over jumps over jumps over jumps over jumps the lazy the lazy the lazy the lazy over the dog. dog. dog. dog. lazy dog. Data-Report-1.001/README0000644000400000040000000000163613620060107012314 0ustar jvjvData-Report, a flexible plugin-driven reporting framework. You define the columns, add the data row by row, and get reports in text, HTML, CSV and so on. Textual ornaments like extra empty lines, dashed lines, and cell lines can be added in a way similar to HTML style sheets. INSTALLATION To install this module, run the following commands: perl Makefile.PL make make test make install SUPPORT AND DOCUMENTATION Development of this module takes place on GitHub: https://github.com/sciurius/perl-Data-Report. After installing, you can find documentation for this module with the perldoc command. perldoc Data::Report Please report any bugs or feature requests using the issue tracker on GitHub. COPYRIGHT AND LICENCE Copyright 2006,2008,2020 Squirrel Consultancy, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Data-Report-1.001/lib/0000755000400000040000000000000013620061360012176 5ustar jvjvData-Report-1.001/lib/Data/0000755000400000040000000000000013620061360013047 5ustar jvjvData-Report-1.001/lib/Data/Report/0000755000400000040000000000000013620061360014322 5ustar jvjvData-Report-1.001/lib/Data/Report/Base.pm0000644000400000040000000002207013620057272015542 0ustar jvjv# Data::Report::Base.pm -- Base class for reporters # Author : Johan Vromans # Created On : Wed Dec 28 13:18:40 2005 # Last Modified By: Johan Vromans # Last Modified On: Sun Feb 9 20:34:18 2020 # Update Count : 319 # Status : Unknown, Use with caution! package Data::Report::Base; =head1 NAME Data::Report::Base - Base class for reporter plugins =head1 SYNOPSIS This module implements that basic functionality common to all reporters. Its documentation still has to be written. =cut use strict; use warnings; use Carp; my $style_pat = qr/^[a-zA-Z]\w*$/; ################ User API ################ sub new { my ($class, $args) = @_; $class = ref($class) || $class; my $type = delete($args->{type}); my $style = delete($args->{style}) || "default"; my $self = bless { _base_type => lc( $type // "" ), _base_fields => [], _base_fdata => {}, _base_style => $style, }, $class; $self->_checkname($style) or croak("Invalid style name: \"$style\""); foreach my $arg ( keys(%$args) ) { my $val = delete($args->{$arg}); if ( my $c = $self->can("set_$arg") ) { $c->($self, $val); } else { croak("Unhandled attribute: \"$arg\""); } } # Return object. $self; } sub start { my $self = shift; $self->_argcheck(0); croak("No layout specified") unless $self->{_base_fdata}; croak("Reporter already started") if $self->{_base_started}; $self->{_base_needpre} = 1; $self->{_base_needhdr} = 1; $self->{_base_needskip} = 0; $self->set_output(\*STDOUT) unless $self->{_base_out}; $self->set_style("default") unless $self->{_base_style}; $self->set_topheading($self->can("_top_heading")) unless $self->{_base_topheading}; $self->set_heading($self->can("_std_heading")) unless $self->{_base_heading}; $self->set_stylist($self->can("_std_stylist")) unless $self->{_base_stylist}; $self->{_base_close} ||= sub {}; $self->{_base_started} = 1; $self->{_base_used} = 0; } sub add { my ($self, $data) = @_; croak("Reporter not started") unless $self->{_base_started}; while ( my($k,$v) = each(%$data) ) { next if $k =~ /^_/; croak("Invalid field: \"$k\"\n") unless defined $self->{_base_fdata}->{$k}; } } sub finish { my $self = shift; $self->_argcheck(0); croak("Reporter not started") unless $self->{_base_started}; $self->{_base_started} = 0; } sub close { my $self = shift; $self->_argcheck(0); croak("Reporter is not finished") if $self->{_base_started}; $self->{_base_close}->(); } ################ Attributes ################ #### Type sub get_type { shift->{_base_type} } #### Style sub set_style { my ($self, $style) = @_; $self->_argcheck(1); $self->_checkname($style) or croak("Invalid style name: \"$style\""); $self->{_base_style} = $style; } sub get_style { my $self = shift; $self->_argcheck(0); $self->{_base_style}; } #### Layout sub set_layout { my ($self, $layout) = @_; $self->_argcheck(1); foreach my $col ( @$layout ) { if ( $col->{name} ) { $self->_checkname($col->{name}) or croak("Invalid column name: \"$col->{name}\""); my $a = { name => $col->{name}, title => $col->{title} || ucfirst(lc(_T($a->{name}))), width => $col->{width} || length($a->{title}), align => $col->{align} || "<", style => $col->{style} || $col->{name}, truncate => $col->{truncate}, }; $self->_checkname($a->{style}) or croak("Invalid column style: \"$a->{style}\""); $self->{_base_fdata}->{$a->{name}} = $a; push(@{$self->{_base_fields}}, $a); } else { croak("Missing column name in layout\n"); } } # Return object. $self; } #### Fields (order of) sub set_fields { my ($self, $f) = @_; $self->_argcheck(1); my @nf; # new order of fields foreach my $fld ( @$f ) { my $a = $self->{_base_fdata}->{$fld}; croak("Unknown field: \"$fld\"\n") unless defined($a); push(@nf, $a); } $self->{_base_fields} = \@nf; # PBP: Return nothing sensible. return; } sub get_fields { my $self = shift; $self->_argcheck(0); [ map { $_->{name} } @{$self->{_base_fields}} ]; } #### Width (set one or more) sub set_width { my ($self, $w) = @_; while ( my($fld,$width) = each(%$w) ) { croak("Unknown field: \"$fld\"\n") unless defined($self->{_base_fdata}->{$fld}); my $ow = $self->{_base_fdata}->{$fld}->{width}; if ( $width =~ /^\+(\d+)$/ ) { $ow += $1; } elsif ( $width =~ /^-(\d+)$/ ) { $ow -= $1; } elsif ( $width =~ /^(\d+)\%$/ ) { $ow *= $1; $ow = int($ow/100); } elsif ( $width =~ /^\d+$/ ) { $ow = $width; } else { croak("Invalid width specification \"$width\" for field \"$fld\"\n"); } $self->{_base_fdata}->{$fld}->{width} = $ow; } # PBP: Return nothing sensible. return; } #### Width (get all) sub get_widths { my $self = shift; $self->_argcheck(0); { map { $_ => $self->{_base_fdata}->{$_}->{width} } $self->get_fields } } #### Output sub set_output { my ($self, $out) = @_; $self->_argcheck(1); $self->{_base_close} = sub {}; if ( ref($out) ) { if ( UNIVERSAL::isa($out, 'SCALAR') ) { $self->{_base_out} = sub { $$out .= join("", @_) }; } elsif ( UNIVERSAL::isa($out, 'ARRAY') ) { $self->{_base_out} = sub { push(@$out, map { +"$_\n" } split(/\n/, $_)) foreach @_; }; } else { $self->{_base_out} = sub { print {$out} (@_) }; $self->{_base_close} = sub { CORE::close($out) or croak("Close: $!") }; } } else { open(my $fd, ">", $out) or croak("Cannot create \"$out\": $!"); $self->{_base_out} = sub { print {$fd} (@_) }; $self->{_base_close} = sub { CORE::close($fd) or croak("Close \"$out\": $!") }; } } #### Stylist sub set_stylist { my ($self, $stylist_code) = @_; $self->_argcheck(1); croak("Stylist must be a function (code ref)") if $stylist_code && !UNIVERSAL::isa($stylist_code, 'CODE'); $self->{_base_stylist} = $stylist_code; } sub get_stylist { my ($self) = @_; $self->_argcheck(0); $self->{_base_stylist}; } #### Heading generator sub set_heading { my ($self, $heading_code) = @_; $self->_argcheck(1); croak("Header must be a function (code ref)") if $heading_code && !UNIVERSAL::isa($heading_code, 'CODE'); $self->{_base_heading} = $heading_code; } sub get_heading { my ($self) = @_; $self->_argcheck(0); $self->{_base_heading}; } sub set_topheading { my ($self, $heading_code) = @_; $self->_argcheck(1); croak("Header must be a function (code ref)") if $heading_code && !UNIVERSAL::isa($heading_code, 'CODE'); $self->{_base_topheading} = $heading_code; } sub get_topheading { my ($self) = @_; $self->_argcheck(0); $self->{_base_topheading} || sub {}; } ################ Friend methods ################ sub _argcheck { my ($pkg, $exp) = @_; my ($package, $filename, $line, $subroutine) = do { package DB; caller(1) }; my $got = scalar(@DB::args)-1; return if $exp == $got; $got ||= "none"; $Carp::CarpLevel++; Carp::croak($subroutine." requires ". ( $exp == 0 ? "no arguments" : $exp == 1 ? " 1 argument" : " $exp arguments" ). " ($got supplied)"); } sub _get_fields { my $self = shift; $self->_argcheck(0); $self->{_base_fields}; } sub _get_fdata { my $self = shift; $self->_argcheck(0); $self->{_base_fdata}; } sub _print { my $self = shift; $self->{_base_out}->(@_); $self->{_base_used}++; } sub _started { my $self = shift; $self->_argcheck(0); $self->{_base_started}; } sub _getstyle { my ($self, $row, $cell) = @_; $self->_argcheck(defined $cell ? 2 : 1); my $stylist = $self->{_base_stylist}; return unless $stylist; return $stylist->($self, $row) unless $cell; my $a = $stylist->($self, "*", $cell) || {}; my $b = $stylist->($self, $row, $cell) || {}; return { %$a, %$b }; } sub _checkhdr { my $self = shift; $self->_argcheck(0); if ( $self->{_base_needhdr} ) { $self->{_base_needhdr} = 0; $self->_pageskip if $self->can("_pageskip"); $self->get_topheading->($self); $self->get_heading->($self); } } sub _needhdr { my $self = shift; $self->_argcheck(1); $self->{_base_needhdr} = shift; } sub _does_needhdr { my $self = shift; $self->_argcheck(0); $self->{_base_needhdr}; } sub _checkname { my $self = shift; $self->_argcheck(1); shift =~ $style_pat; } 1; =head1 AUTHOR Johan Vromans, C<< >> =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 COPYRIGHT & LICENSE Copyright 2006 Squirrel Consultancy, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Data-Report-1.001/lib/Data/Report/Plugin/0000755000400000040000000000000013620061360015560 5ustar jvjvData-Report-1.001/lib/Data/Report/Plugin/Csv.pm0000644000400000040000000000736613620052347016672 0ustar jvjv# Data::Report::Plugin::Csv.pm -- CSV plugin for Data::Report # Author : Johan Vromans # Created On : Thu Jan 5 18:47:37 2006 # Last Modified By: Johan Vromans # Last Modified On: Sun Feb 9 19:52:23 2020 # Update Count : 120 # Status : Unknown, Use with caution! package Data::Report::Plugin::Csv; use strict; use warnings; use base qw(Data::Report::Base); ################ API ################ my $csv_implementation = 0; sub start { my ($self, @args) = @_; $self->SUPER::start(@args); $self->set_separator(",") unless $self->get_separator; $self->_select_csv_method unless $csv_implementation; return; } sub finish { my ($self) = @_; $self->SUPER::finish(); } sub add { my ($self, $data) = @_; my $style = delete($data->{_style}); my $sep = $self->get_separator; $self->SUPER::add($data); return unless %$data; if ( $style and my $t = $self->_getstyle($style) ) { return if $t->{ignore}; } $self->_checkhdr; my $line; $line = $self->_csv ( map { $data->{$_->{name}} || "" } grep { my $t = $self->_getstyle($style, $_->{name}); ! $t->{ignore}; } @{$self->_get_fields} ); $self->_print($line, "\n"); } sub set_separator { $_[0]->{sep} = $_[1] } sub get_separator { $_[0]->{sep} || "," } ################ Pseudo-Internal (used by Base class) ################ sub _std_heading { my ($self) = @_; my $sep = $self->get_separator; $self->_print($self->_csv (map { $_->{title} } grep { my $t = $self->_getstyle("_head", $_->{name}); ! $t->{ignore}; } @{$self->_get_fields}), "\n"); } ################ Internal (used if no alternatives) ################ sub _csv_internal { join(shift->get_separator, map { # Quotes must be doubled. s/"/""/g; # Always quote (compatible with Text::CSV) $_ = '"' . $_ . '"'; $_; } @_); } sub _set_csv_method { my ($self, $class) = @_; no warnings qw(redefine); if ( $class && $class->isa("Text::CSV_XS") ) { # Use always_quote to be compatible with Text::CSV. # Use binary to deal with non-ASCII text. $csv_implementation = Text::CSV_XS->new ({ sep_char => $self->get_separator, always_quote => 1, binary => 1, }); # Assign the method. *_csv = sub { shift; $csv_implementation->combine(@_); $csv_implementation->string; }; warn("# CSV plugin uses Text::CSV_XS $Text::CSV_XS::VERSION\n") if $ENV{AUTOMATED_TESTING}; } elsif ( $class && $class->isa("Text::CSV") ) { # With modern Text::CSV, it will use Text::CSV_XS if possible. # So this gotta be Text::CSV_PP... $csv_implementation = Text::CSV->new ({ always_quote => 1, binary => 1, }); # Assign the method. *_csv = sub { shift; $csv_implementation->combine(@_); $csv_implementation->string; }; warn("# CSV plugin uses Text::CSV $Text::CSV::VERSION, PP version $Text::CSV_PP::VERSION\n") if $ENV{AUTOMATED_TESTING}; } else { # Use our internal method. *_csv = \&_csv_internal; $csv_implementation = "Data::Report::Plugin::Csv::_csv_internal"; warn("# CSV plugin uses built-in CSV packer\n") if $ENV{AUTOMATED_TESTING}; } return $csv_implementation; } sub _select_csv_method { my $self = shift; $csv_implementation = 0; eval { require Text::CSV_XS; $self->_set_csv_method(Text::CSV_XS::); }; return $csv_implementation if $csv_implementation; if ( $self->get_separator eq "," ) { eval { require Text::CSV; $self->_set_csv_method(Text::CSV::); }; } return $csv_implementation if $csv_implementation; # Use our internal method. $self->_set_csv_method(); return $csv_implementation; } 1; Data-Report-1.001/lib/Data/Report/Plugin/Html.pm0000644000400000040000000000522513620052354017031 0ustar jvjv# Data::Report::Plugin::Html.pm -- HTML plugin for Data::Report # Author : Johan Vromans # Created On : Thu Dec 29 15:46:47 2005 # Last Modified By: Johan Vromans # Last Modified On: Sun Feb 9 19:52:28 2020 # Update Count : 84 # Status : Unknown, Use with caution! package Data::Report::Plugin::Html; use strict; use warnings; use base qw(Data::Report::Base); ################ API ################ my $html_use_entities = 0; sub start { my ($self) = @_; $self->_argcheck(0); eval { require HTML::Entities; $html_use_entities = 1; }; $self->SUPER::start(); $self->{used} = 0; } sub finish { my ($self) = @_; $self->_argcheck(0); if ( $self->{used} ) { $self->_print("\n"); } $self->SUPER::finish(); } sub add { my ($self, $data) = @_; my $style = delete($data->{_style}); $self->SUPER::add($data); return unless %$data; if ( $style and my $t = $self->_getstyle($style) ) { return if $t->{ignore}; } $self->{used}++; $self->_checkhdr; $self->_print("\n"); foreach my $col ( @{$self->_get_fields} ) { my $fname = $col->{name}; my $value = defined($data->{$fname}) ? $data->{$fname} : ""; # Examine style mods. my $t = $self->_getstyle($style, $fname); next if $t->{ignore}; my $class = $t->{class} || "c_$fname"; $self->_print("{align}), "class=\"$class\">", $value eq "" ? " " : $t->{raw_html} ? $value : $self->_html($value), "\n"); } $self->_print("\n"); } ################ Pseudo-Internal (used by Base class) ################ sub _std_heading { my ($self) = @_; $self->_argcheck(0); $self->_print("\n"); $self->_print("\n"); foreach ( @{$self->_get_fields} ) { # Examine style mods. my $t = $self->_getstyle("_head", $_->{name}); next if $t->{ignore}; my $class = $t->{class} || "h_" . $_->{name}; $self->_print("\n"); } $self->_print("\n"); } ################ Internal methods ################ sub _align { return 'align="right" ' if $_[0] eq '>'; return 'align="left" ' if $_[0] eq '<'; return 'align="center" ' if $_[0] eq '|'; "" } sub _html { shift; if ( $html_use_entities ) { return HTML::Entities::encode(shift); } my ($t) = @_; $t =~ s/&/&/g; $t =~ s//>/g; $t =~ s/\240/ /g; $t =~ s/\x{eb}/ë/g; # for IVP. $t; } 1; Data-Report-1.001/lib/Data/Report/Plugin/Text.pm0000644000400000040000000001443513620052360017051 0ustar jvjv# Data::Report::Plugin::Text.pm -- Text plugin for Data::Report # Author : Johan Vromans # Created On : Wed Dec 28 13:21:11 2005 # Last Modified By: Johan Vromans # Last Modified On: Sun Feb 9 19:52:32 2020 # Update Count : 150 # Status : Unknown, Use with caution! package Data::Report::Plugin::Text; use strict; use warnings; use base qw(Data::Report::Base); use Carp; ################ User API ################ sub start { my $self = shift; $self->_argcheck(0); $self->SUPER::start; $self->_make_format; $self->{lines} = 0; $self->{page} = $=; } sub add { my ($self, $data) = @_; my $style = delete($data->{_style}); if ( $style && !$self->_checkname($style) ) { croak("Invalid style name: \"$style\""); } $self->SUPER::add($data); $self->_checkhdr; my $skip_after = 0; my $line_after = 0; my $cancel_skip = 0; if ( $style and my $t = $self->_getstyle($style) ) { return if $t->{ignore}; $self->_skip if $t->{skip_before}; $skip_after = $t->{skip_after}; $self->_line if $t->{line_before}; $line_after = $t->{line_after}; $cancel_skip = $t->{cancel_skip}; } $style = "*" unless defined($style); $self->_checkskip($cancel_skip); my @values; my @widths; my @indents; my $linebefore; my $lineafter; foreach my $col ( @{$self->_get_fields} ) { my $fname = $col->{name}; my $t = $style ? $self->_getstyle($style, $fname) : {}; next if $t->{ignore}; push(@values, defined($data->{$fname}) ? $data->{$fname} : ""); push(@widths, $col->{width}); if ($col->{truncate} ) { $values[-1] = substr($values[-1], 0, $widths[-1]); } # Examine style mods. my $indent = 0; my $wrapindent = 0; my $excess = 0; if ( $t ) { $indent = $t->{indent} || 0; $wrapindent = defined($t->{wrap_indent}) ? $t->{wrap_indent} : $indent; croak("Row $style, column $fname, ". "illegal value for indent property: $indent") if $indent < 0 || $indent >= $self->_get_fdata->{$fname}->{width}; croak("Row $style, column $fname, ". "illegal value for wrap_indent property: $wrapindent") if $wrapindent < 0 || $wrapindent >= $self->_get_fdata->{$fname}->{width}; if ( $t->{line_before} ) { $linebefore->{$fname} = ($t->{line_before} eq "1" ? "-" : $t->{line_before}) x $col->{width}; } if ( $t->{line_after} ) { $lineafter->{$fname} = ($t->{line_after} eq "1" ? "-" : $t->{line_after}) x $col->{width}; } if ( $t->{excess} ) { $widths[-1] += 2; } if ( $t->{truncate} || $col->{truncate} ) { $values[-1] = substr($values[-1], 0, $widths[-1] - $indent); } } push(@indents, [$indent, $wrapindent]); } if ( $linebefore ) { $linebefore->{_style} = ""; $self->add($linebefore); } my @lines; while ( 1 ) { my $more = 0; my @v; foreach my $i ( 0..$#widths ) { my ($ind, $wind) = @{$indents[$i]}; $ind = $wind if @lines; my $maxw = $widths[$i] - $ind; $ind = " " x $ind; if ( length($values[$i]) <= $maxw ) { push(@v, $ind.$values[$i]); $values[$i] = ""; } else { my $t = substr($values[$i], 0, $maxw); if ( substr($values[$i], $maxw, 1) eq " " ) { push(@v, $ind.$t); substr($values[$i], 0, length($t) + 1, ""); } elsif ( $t =~ /^(.*)([ ]+)/ ) { my $pre = $1; push(@v, $ind.$pre); substr($values[$i], 0, length($pre) + length($2), ""); } else { push(@v, $ind.$t); substr($values[$i], 0, $maxw, ""); } $more++; } } my $t = sprintf($self->{format}, @v); $t =~ s/ +$//; push(@lines, $t) if $t =~ /\S/; last unless $more; } if ( $self->{lines} < @lines ) { $self->_needhdr(1); $self->_checkhdr; } $self->_print(@lines); # Post: Lines for cells. if ( $lineafter ) { $lineafter->{_style} = ""; $self->add($lineafter); } # Post: Line for row. if ( $line_after ) { $self->_line; } # Post: Skip after this row. elsif ( $skip_after ) { $self->_skip; } } sub finish { my $self = shift; $self->_argcheck(0); $self->_checkskip(1); # cancel skips. $self->SUPER::finish(); } ################ Pseudo-Internal (used by Base class) ################ sub _std_heading { my ($self) = @_; # Print column names. my $t = sprintf($self->{format}, map { $_->{title} } grep { my $t = $self->_getstyle("_head", $_->{name}); ! $t->{ignore}; } @{$self->_get_fields}); # Add separator line. $t .= "-" x ($self->{width}); $t .= "\n"; # Remove trailing blanks. $t =~ s/ +$//gm; # Print it. $self->_print($t); $self->_needskip(0); } ################ Internal methods ################ sub _print { my ($self, @values) = @_; my $value = join("", @values); $self->SUPER::_print($value); $self->{lines} -= ($value =~ tr/\n//); } sub _pageskip { my ($self) = @_; $self->{lines} = $self->{page}; } sub _make_format { my ($self) = @_; my $width = 0; # new width my $format = ""; # new format foreach my $a ( @{$self->_get_fields} ) { my $t = $self->_getstyle("_head", $a->{name}); next if $t->{ignore}; # Never mind the trailing blanks -- we'll trim anyway. $width += $a->{width} + 2; if ( $a->{align} eq "<" ) { $format .= "%-". join(".", ($a->{width}+2) x 2) . "s"; } else { $format .= "%". join(".", ($a->{width}) x 2) . "s "; } } # Store format and width in object. $self->{format} = $format . "\n"; $self->{width} = $width - 2; # PBP: Return nothing sensible. return; } sub _checkskip { my ($self, $cancel) = @_; return if !$self->_does_needskip || $self->{lines} <= 0; $self->_print("\n") unless $cancel; $self->_needskip(0); } sub _needskip { my $self = shift; $self->{needskip } = shift; } sub _does_needskip { my $self = shift; $self->{needskip}; } sub _line { my ($self) = @_; $self->_checkhdr; $self->_checkskip(1); # cancel skips. $self->_print("-" x ($self->{width}), "\n"); } sub _skip { my ($self) = @_; $self->_checkhdr; $self->_needskip(1); } sub _center { my ($self, $text, $width) = @_; (" " x (($width - length($text))/2)) . $text; } sub _expand { my ($self, $text) = @_; $text =~ s/(.)/$1 /g; $text =~ s/ +$//; $text; } 1; Data-Report-1.001/lib/Data/Report.pm0000644000400000040000000005304213620061344014666 0ustar jvjv# Data::Reporter.pm -- Framework for flexible reporting # Author : Johan Vromans # Created On : Wed Dec 28 13:18:40 2005 # Last Modified By: Johan Vromans # Last Modified On: Sun Feb 9 20:52:04 2020 # Update Count : 271 # Status : Unknown, Use with caution! use strict; use warnings; package Data::Report; =head1 NAME Data::Report - Framework for flexible reporting =cut our $VERSION = "1.001"; =head1 SYNOPSIS use Data::Report; # Create a new reporter. my $rep = Data::Report::->create(type => "text"); # or "html", or "csv", ... # Define the layout. $rep->set_layout ([ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Description", width => 40, align => "<" }, { name => "deb", title => "Debet", width => 10, align => ">" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ]); # Start the reporter. $rep->start; # Add data, row by row. $rep->add({ acct => 1234, desc => "Received", deb => "242.33" }); $rep->add({ acct => 5678, desc => "Paid", crd => "699.45" }); $rep->add({ acct => 1259, desc => "Taxes", deb => "12.00", crd => "244.00" }); $rep->add({ desc => "TOTAL", deb => "254.33", crd => "943.45" }); # Finish the reporter. $rep->finish; =head1 DESCRIPTION Data::Report is a flexible, plugin-driven reporting framework. It makes it easy to define reports that can be produced in text, HTML and CSV. Textual ornaments like extra empty lines, dashed lines, and cell lines can be added in a way similar to HTML style sheets. The Data::Report framework consists of three parts: =over 4 =item The plugins Plugins implement a specific type of report. Standard plugins provided are C for textual reports, C for HTML reports, and C for CSV (comma-separated) files. Users can, and are encouraged, to develop their own plugins to handle different styles and types of reports. =item The base class The base class C implements the functionality common to all reporters, plus a number of utility functions the plugins can use. =item The factory The actual C module is a factory that creates a reporter for a given report type by selecting the appropriate plugin and returning an instance thereof. =back =cut use strict; use warnings; use Carp; =head1 BASIC METHODS Note that except for the C method, all other methods are actually handled by the plugins and their base class. =head2 create Reporter objects are created using the class method C. This method takes a hash (or hashref) of arguments to initialise the reporter object. The actual reporter object is implemented by one of the plugin modules, selected by the C argument. Standard plugins are provided for C, C and C report types. The default type is C. When looking for a plugin to support report type C, the C method will first try to load a module C where C is the invocant class. If this module cannot be loaded, it will fall back to C. Note that, unless subclassed, the current class will be C. All other initialisation arguments correspond to attribute setting methods provided by the plugins. For example, the hypothetical call my $rpt = Data::Report->create(foo => 1, bar => "Hello!"); is identical to: my $rpt = Data::Report->create; $rpt->set_foo(1); $rpt->set_bar("Hello!"); You can choose any combination at your convenience. =cut sub create { my $class = shift; my $args; if ( @_ == 1 && UNIVERSAL::isa($_[0], 'HASH') ) { $args = shift; } else { $args = { @_ }; } # 'type' attribute is mandatory. my $type = ucfirst(lc( $args->{type} // "" )); #croak("Missing \"type\" attribute") unless $type; $type = "Text" unless $type; # Try to load class specific plugin. my $plugin = $class . "::" . $type; $plugin =~ s/::::/::/g; # Strategy: load the class, and see if it exists. # A plugin does not necessary have to be external, if one of the # other classes did define the requested plugin we'll use that # one. # First, try the plugin in this invocant class. eval "use $plugin"; unless ( _loaded($plugin) ) { # Try to load generic plugin. $plugin = __PACKAGE__ . "::Plugin::" . $type; $plugin =~ s/::::/::/g; eval "use $plugin"; } croak("Unsupported type (Cannot load plug-in for \"$type\")\n$@") unless _loaded($plugin); # Return the plugin instance. # The constructor gets all args passed, including 'type'. $plugin->new($args); } sub _loaded { my $class = shift; no strict "refs"; %{$class . "::"} ? 1 : 0; } =head2 start This method indicates that all setup has been completed, and starts the reporter. Note that no output is generated until the C method is called. C takes no arguments. Although this method could be eliminated by automatically starting the reporter upon the first call to C, it turns out that an aplicit C makes the API much cleaner and makes it easier to catch mistakes. =head2 add This method adds a new entry to the report. It takes one single argument, a hash ref of column names and the corresponding values. Missing columns are left blank. In addition to the column names and values, you can add the special key C<_style> to designate a particular style for this entry. What that means depends on the plugin that implements this reporter. For example, the standard HTML reporter plugin prefixes the given style with C to form the class name for the row. The style name should be a simple name, containing letters, digits and underscores, starting with a letter. Example $rpt->add({ date => "2006-04-31", amount => 1000, descr => "First payment", _style => "plain" }); =head2 finish This method indicates that report generation is complete. After this, you can call C again to initiate a new report. C takes no arguments. =head2 close This is a convenience method. If the output stream was set up by the reporter itself (see C, below), the stream will be closed. Otherwise, this method will be a no-op. C takes no arguments. =head1 ATTRIBUTE HANDLING METHODS =head2 get_type The reporter type. =head2 set_layout This is the most important attribute, since it effectively defines the report layout. This method takes one argument, an array reference. Each element of the array is a hash reference that corresponds to one column in the report. The order of elements definines the order of the columns in the report, but see C below. The following keys are possible in the hash reference: =over 4 =item C The name of this column. The name should be a simple name, containing letters, digits and underscores, starting with a letter. The standard HTML reporter plugin uses the column name to form a class name for each cell by prefixing with C. Likewise, the classes for the table headings will be formed by prefixing the column names with C. See L, below. =item C The title of this column. This title is placed in the column heading. =item C<width> The width of this column. Relevant for textual reporters only. By default, if a value does not fit in the given width, it will be spread over multiple rows in a pseudo-elegant way. See also the C<truncate> key, below. =item C<align> The alignment of this column. This can be either C<< < >> for left-aligned columns, or C<< > >> to indicate a right-aligned column. =item C<truncate> If true, the values in this column will be truncated to fit the width of the column. Relevant for textual reporters only. =back =head2 set_style This method can be used to set an arbitrary style (a string) whose meaning depends on the implementing plugin. For example, a HTML plugin could use this as the name of the style sheet to use. The name should be a simple name, containing letters, digits and underscores, starting with a letter. =head2 get_style Returns the style, or C<default> if none. =head2 set_output Designates the destination for the report. The argument can be =over 4 =item a SCALAR reference All output will be appended to the designated scalar. =item an ARRAY reference All output lines will be pushed onto the array. =item a SCALAR A file will be created with the given name, and all output will be written to this file. To close the file, use the C<close> method described above. =item anything else Anything else will be considered to be a file handle, and treated as such. =back =head2 set_stylist The stylist is a powerful method to control the appearance of the report at the row and cell level. The basic idea is taken from HTML style sheets. By using a stylist, it is possible to add extra spaces and lines to rows and cells in a declarative way. When used, the stylist should be a reference to a possibly anonymous subroutine with three arguments: the reporter object, the style of a row (as specified with C<_style> in the C<add> method), and the name of a column as defined in the layout. For table headings, the row name C<_head> is used. The stylist routine will be repeatedly called by the reporter to obtain formatting properties for rows and cells. It should return either nothing, or a hash reference with properties. When called with only the C<row> argument, it should return the properties for this row. When called with row equal to "*" and a column name, it should return the properties for the given column. When called with a row and a column name, it should return the properties for the given row/column (cell). All appropriate properties are merged to form the final set of properties to apply. The following row properties are recognised. Between parentheses the backends that support them. =over 4 =item C<skip_before> (Text) Produce an empty line before printing the current row. =item C<skip_after> (Text) Produce an empty line after printing the current row, but only if other data follows. =item C<line_before> (Text) Draw a line of dashes before printing the current row. =item C<line_after> (Text) Draw a line of dashes after printing the current row. =item C<cancel_skip> (Text) Cancel the effect of a pending C<skip_after> =item C<ignore> (All) Ignore this row. Useful for CSV backends where only the raw data matters, and not the totals and such. =back The following cell properties are recognised. Between parentheses the backends that support them. =over 4 =item C<indent> (Text) Indent the contents of this cell with the given amount. =item C<wrap_indent> (Text) Indent wrapped contents of this cell with the given amount. =item C<truncate> (Text) If true, truncate the contents of this cell to fit the column width. =item C<line_before> (Text) Draw a line in the cell before printing the current row. The value of this property indicates the symbol to use to draw the line. If it is C<1>, dashes are used. =item C<line_after> (Text) Draw a line in the cell after printing the current row. The value of this property indicates the symbol to use to draw the line. If it is C<1>, dashes are used. =item C<raw_html> (Html) Do not escape special HTML characters, allowing pre-prepared HTML code to be placed in the output. Use with care. =item C<ignore> (All) Ignore this column. Note that to prevent surprising results, the column must be ignored in all applicable styles, including the special style C<"_head"> that controls the heading. =item C<class> (Html) Class name to be used for this cell. Default class name is "h_CNAME" for table headings and "c_CNAME" for table rows, where CNAME is the name of the column. =back Example: $rep->set_stylist(sub { my ($rep, $row, $col) = @_; unless ( $col ) { return { line_after => 1 } if $row eq "total"; return; } return { line_after => 1 } if $col eq "amount"; return; }); Each reporter provides a standard (dummy) stylist called C<_std_stylist>. Overriding this method is equivalent to using C<set_stylist>. =head2 get_stylist Returns the current stylist, if any. =head2 set_topheading Headings consist of two parts, the I<top heading>, and the I<standard heading>. Bij default, the top heading is empty, and the standard heading has the names of the columns with a separator line (depnendent on the plugin used). This method can be used to designate a subroutine that will provide the top heading of the report. Example: $rpt->set_topheading(sub { my $self = shift; $self->_print("Title line 1\n"); $self->_print("Title line 2\n"); $self->_print("\n"); }); Note the use of the reporter provided C<_print> method to produce output. When subclassing a reporter, a method C<_top_heading> can be defined to provide the top heading. This is equivalent to an explicit call to C<set_topheading>, but doesn't need to be repeatedly and explicitly executed for each new reporter. =head2 get_topheading Returns the current top heading routine, if any. =head2 set_heading This method can be used to designate a subroutine that provides the standard heading of the report. In normal cases using this method is not necessary, since setting the top heading will be sufficient. Each reporter plugin provides a standard heading, implemented in a method called C<_std_header>. This is the default value for the C<heading> attribute. A user-defined heading can use $self->SUPER::_std_header; to still get the original standard heading produced. Example: $rpt->set_heading(sub { my $self = shift; $self->_print("Title line 1\n"); $self->_print("Title line 2\n"); $self->_print("\n"); $self->SUPER::_std_heading; $self->_print("\n"); }); Note the use of the reporter provided C<_print> method to produce output. When subclassing a reporter, the method C<_std_heading> can be overridden to provide a customized top heading. This is equivalent to an explicit call to C<set_topheading>, but doesn't need to be repeatedly and explicitly executed for each new reporter. =head2 get_heading Returns the current standard heading routine, if any. =head2 set_fields This method can be used to define what columns (fields) should be included in the report and the order they should appear. It takes an array reference with the names of the desired columns. Example: $rpt->set_fields([qw(descr amount date)]); =head2 get_fields Returns the current set of selected columns. =head2 set_width This method defines the width for one or more columns. It takes a hash reference with column names and widths. The width may be an absolute number, a relative number (to increase/decrease the width, or a percentage. Example: $rpt->set_width({ amount => 10, desc => '80%' }); =head2 get_widths Returns a hash with all column names and widths. =head1 ADVANCED EXAMPLES This example subclasses Data::Report with an associated plugin for type C<text>. Note the use of overriding C<_top_heading> and C<_std_stylist> to provide special defaults for this reporter. package POC::Report; use base qw(Data::Report); package POC::Report::Text; use base qw(Data::Report::Plugin::Text); sub _top_heading { my $self = shift; $self->_print("Title line 1\n"); $self->_print("Title line 2\n"); $self->_print("\n"); } sub _std_stylist { my ($rep, $row, $col) = @_; if ( $col ) { return { line_after => "=" } if $row eq "special" && $col =~ /^(deb|crd)$/; } else { return { line_after => 1 } if $row eq "total"; } return; } It can be used as follows: my $rep = POC::Report::->create(type => "text"); $rep->set_layout ([ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "<" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ]); $rep->start; $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "special"}); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "total" }); $rep->finish; The output will look like: Title line 1 Title line 2 Acct Report Debet Credit ------------------------------------------------------------------------ one two three four one two three four one two three four ========== ========== one two three four ------------------------------------------------------------------------ This is a similar example for a HTML reporter: package POC::Report; use base qw(Data::Report); package POC::Report::Html; use base qw(Data::Report::Plugin::Html); sub start { my $self = shift; $self->{_title1} = shift; $self->{_title2} = shift; $self->{_title3} = shift; $self->SUPER::start; } sub _top_heading { my $self = shift; $self->_print("<html>\n", "<head>\n", "<title>", $self->_html($self->{_title1}), "\n", '', "\n", "\n", "\n", "

", $self->_html($self->{_title1}), "

\n", "

", $self->_html($self->{_title2}), "
\n", $self->_html($self->{_title3}), "

\n"); } sub finish { my $self = shift; $self->SUPER::finish; $self->_print("\n\n"); } Note that it defines an alternative C method, that is used to pass in additional parameters for title fields. The method C<_html> is a convenience method provided by the framework. It returns its argument with sensitive characters escaped by HTML entities. It can be used as follows: package main; my $rep = POC::Report::->create(type => "html"); $rep->set_layout ([ { name => "acct", title => "Acct", width => 6 }, { name => "desc", title => "Report", width => 40, align => "<" }, { name => "deb", title => "Debet", width => 10, align => "<" }, { name => "crd", title => "Credit", width => 10, align => ">" }, ]); $rep->start(qw(Title_One Title_Two Title_Three_Left&Right)); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "normal" }); $rep->add({ acct => "one", desc => "two", deb => "three", crd => "four", _style => "total" }); $rep->finish; The output will look like this: Title_One

Title_One

Title_Two
Title_Three_Left&Right

{align}), "class=\"$class\">", $self->_html($_->{title}), "
Acct Report Debet Credit
one two three four
one two three four
one two three four
one two three four
See also the examples in C. =head1 AUTHOR Johan Vromans, C<< >> =head1 BUGS I Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT Development of this module takes place on GitHub: L. After installing, you can find documentation for this module with the perldoc command. perldoc Data::Report Please report any bugs or feature requests using the issue tracker on GitHub. =head1 ACKNOWLEDGEMENTS =head1 COPYRIGHT & LICENSE Copyright 2006,2008,2020 Squirrel Consultancy, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut # End of Data::Report Data-Report-1.001/META.yml0000644000400000040000000000143613620061360012705 0ustar jvjv--- abstract: 'Framework for flexible reporting' author: - 'Johan Vromans ' build_requires: ExtUtils::MakeMaker: '0' Text::CSV: '1' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Data-Report no_index: directory: - t - inc package: - DB requires: ExtUtils::MakeMaker: '6.46' Test::More: '0' Text::CSV: '1' perl: '5.010001' resources: bugtracker: https://github.com/sciurius/perl-Data-Report/issues repository: https://github.com/sciurius/perl-Data-Report.git version: '1.001' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Data-Report-1.001/Changes0000644000400000040000000000413413620057533012734 0ustar jvjvRevision history for Data-Report 1.000 2020-02-09 After 12 years of full production, this deserves to come out of beta :). Fix some warnings. Import CVS into Git and move to GitHub. Switch to Makefile.PL building. 0.10 2008-08-18 Add column property 'class' for HTML plugin. Can be used to supply a different class from the default h_XXX and c_XXX. The special row for headings has been changed from "head" to "_head" to avoid conlicts with ordinary row styles. 0.09 2008-08-07 22:16 Add column property 'ignore'. Does what the name implies. This change was suggested by Mario Silva. Upgrade requirements for Text::CSV to 1.00. 0.08 2008-08-07 14:27 Allow handling of Latin texts with CSV plugin and Text::CSV_XS. This change was suggested by Mario Silva. 0.07 2008-08-03 16:26 Add 'raw_html' style mod for HTML plugin. When a cell has this property, the data will be placed in the cell unmodified. This makes it possible to place pre-prepared HTML code in the cell. This change was suggested by Cristina Nunes. 0.05 2006-06-08 15:46 Better SYNOPSIS + doc fixes. 0.04 2006-06-08 15:20 Under debian linux, Text::CSV seems to be a wrapper for Text::CSV_XS which caused test t/03csv02.t to fail. Under perl 5.6, output was written to a file '*main::STDOUT', since in older perls refering to a filehandle glob needs an additional \. 0.03 2006-05-22 22:03 Integrate API docs into Data::Report. Add get_type method. Add topheading attribute. Eliminates most needs for $rep->set_heading. Row attribute 'ignore'. Column attribute 'wrap_indent'. Handle alignment < > | in HTML. CSV plugin will use Text::CSV_XS or Text::CSV if installed. 0.02 2006-05-01 23:08 Small documentation fixes. Prevent DB from being attempted by the CPAN indexer. 0.01 2006-05-01 16:05 First version, derived from actual working code of a big application. I turned it into a generic CPAN module. During the process, some features may have become unstable, but that will be cured in time. Also, it is possible that revisions of the API will be necessary when new functionality is added. Data-Report-1.001/Makefile.PL0000644000400000040000000000221313620061325013401 0ustar jvjv#! perl use strict; use warnings; use ExtUtils::MakeMaker; my $master = 'lib/Data/Report.pm'; my $version = MM->parse_version($master); WriteMakefile( NAME => 'Data::Report', AUTHOR => 'Johan Vromans ', VERSION => $version, ABSTRACT_FROM => $master, LICENSE => 'perl_5', PL_FILES => {}, DIR => [], MIN_PERL_VERSION => '5.010001', PREREQ_PM => { 'ExtUtils::MakeMaker' => 6.46, # for META_MERGE, LICENSE 'Test::More' => 0, 'Text::CSV' => 1.00, }, TEST_REQUIRES => { 'Text::CSV' => 1.00, }, META_MERGE => { resources => { repository => { type => 'git', web => 'https://github.com/sciurius/perl-Data-Report', url => 'https://github.com/sciurius/perl-Data-Report.git', }, bugtracker => { web => "https://github.com/sciurius/perl-Data-Report/issues", }, }, 'meta-spec' => { version => '2', url => 'https://metacpan.org/pod/CPAN::Meta::Spec', }, recommends => { 'HTML::Entities' => 0, }, no_index => { package => [ qw(DB) ], }, } ); Data-Report-1.001/META.json0000644000400000040000000000272313620061360013055 0ustar jvjv{ "abstract" : "Framework for flexible reporting", "author" : [ "Johan Vromans " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Data-Report", "no_index" : { "directory" : [ "t", "inc" ], "package" : [ "DB" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "ExtUtils::MakeMaker" : "6.46", "Test::More" : "0", "Text::CSV" : "1", "perl" : "5.010001" } }, "test" : { "requires" : { "Text::CSV" : "1" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/sciurius/perl-Data-Report/issues" }, "repository" : { "type" : "git", "url" : "https://github.com/sciurius/perl-Data-Report.git", "web" : "https://github.com/sciurius/perl-Data-Report" } }, "version" : "1.001", "x_serialization_backend" : "JSON::PP version 2.97001" } Data-Report-1.001/MANIFEST0000644000400000040000000000107313620061360012562 0ustar jvjvMakefile.PL Changes lib/Data/Report.pm lib/Data/Report/Base.pm lib/Data/Report/Plugin/Csv.pm lib/Data/Report/Plugin/Html.pm lib/Data/Report/Plugin/Text.pm MANIFEST This list of files META.yml README t/00basic.t t/01text01.t t/01text02.t t/01text03.t t/01text04.t t/01text05.t t/01text06.t t/01text07.t t/02html01.t t/02html02.t t/02html03.t t/03csv01.t t/03csv02.t t/03csv03.t t/03csv04.t t/03csv05.t t/03csv06.t t/09poc01.t t/09poc02.t t/09poc03.t t/09poc04.t t/09poc05.t t/09poc06.t META.json Module JSON meta-data (added by MakeMaker)