Provided by: libdata-report-perl_1.001-2_all bug

NAME

       Data::Report - Framework for flexible reporting

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;

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:

       The plugins
           Plugins    implement    a    specific    type    of    report.    Standard   plugins   provided   are
           "Data::Report::Plugin::Text" for textual reports, "Data::Report::Plugin::Html" for HTML reports,  and
           "Data::Report::Plugin::Csv" for CSV (comma-separated) files.

           Users  can,  and are encouraged, to develop their own plugins to handle different styles and types of
           reports.

       The base class
           The base class "Data::Report::Base" implements the functionality common  to  all  reporters,  plus  a
           number of utility functions the plugins can use.

       The factory
           The  actual  "Data::Report"  module  is  a factory that creates a reporter for a given report type by
           selecting the appropriate plugin and returning an instance thereof.

BASIC METHODS

       Note that except for the "create" method, all other methods are actually handled by the plugins and their
       base class.

   create
       Reporter objects are created using the class method "create". 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 "type" argument.
       Standard plugins are provided for "text", "HTML" and "CSV" report types. The default type is "text".

       When looking for a plugin to support report type "foo", the "create" method will  first  try  to  load  a
       module  "My::Package::Foo" where "My::Package" is the invocant class. If this module cannot be loaded, it
       will fall back to "Data::Report::Plugin::Foo". Note that, unless subclassed, the current  class  will  be
       "Data::Report".

       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.

   start
       This method indicates that all setup has been completed, and starts the reporter. Note that no output  is
       generated until the "add" method is called.

       "start" takes no arguments.

       Although  this  method  could be eliminated by automatically starting the reporter upon the first call to
       "add", it turns out that an aplicit "start" makes the API much cleaner  and  makes  it  easier  to  catch
       mistakes.

   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  "_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 "r_" 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" });

   finish
       This  method  indicates  that  report  generation  is complete. After this, you can call "start" again to
       initiate a new report.

       "finish" takes no arguments.

   close
       This is a convenience method. If the output stream was set up by the reporter itself  (see  "set_output",
       below), the stream will be closed. Otherwise, this method will be a no-op.

       "close" takes no arguments.

ATTRIBUTE HANDLING METHODS

   get_type
       The reporter type.

   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 "set_fields" below.

       The following keys are possible in the hash reference:

       "name"
           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 "h_". See "ADVANCED EXAMPLES", below.

       "title"
           The title of this column. This title is placed in the column heading.

       "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 "truncate" key, below.

       "align"
           The  alignment  of this column. This can be either "<" for left-aligned columns, or ">" to indicate a
           right-aligned column.

       "truncate"
           If true, the values in this column will be truncated to fit the width of the  column.   Relevant  for
           textual reporters only.

   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.

   get_style
       Returns the style, or "default" if none.

   set_output
       Designates the destination for the report. The argument can be

       a SCALAR reference
           All output will be appended to the designated scalar.

       an ARRAY reference
           All output lines will be pushed onto the array.

       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 "close" method described above.

       anything else
           Anything else will be considered to be a file handle, and treated as such.

   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 "_style" in the "add" method), and the name  of  a
       column as defined in the layout. For table headings, the row name "_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 "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.

       "skip_before"
           (Text) Produce an empty line before printing the current row.

       "skip_after"
           (Text) Produce an empty line after printing the current row, but only if other data follows.

       "line_before"
           (Text) Draw a line of dashes before printing the current row.

       "line_after"
           (Text) Draw a line of dashes after printing the current row.

       "cancel_skip"
           (Text) Cancel the effect of a pending "skip_after"

       "ignore"
           (All) Ignore this row. Useful for CSV backends where only the raw data matters, and  not  the  totals
           and such.

       The following cell properties are recognised. Between parentheses the backends that support them.

       "indent"
           (Text) Indent the contents of this cell with the given amount.

       "wrap_indent"
           (Text) Indent wrapped contents of this cell with the given amount.

       "truncate"
           (Text) If true, truncate the contents of this cell to fit the column width.

       "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 1, dashes are used.

       "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 1, dashes are used.

       "raw_html"
           (Html)  Do  not  escape  special HTML characters, allowing pre-prepared HTML code to be placed in the
           output. Use with care.

       "ignore"
           (All) Ignore this column. Note that to prevent surprising results, the column must be ignored in  all
           applicable styles, including the special style "_head" that controls the heading.

       "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.

       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  "_std_stylist".  Overriding  this  method  is
       equivalent to using "set_stylist".

   get_stylist
       Returns the current stylist, if any.

   set_topheading
       Headings consist of two parts, the top heading, and the 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 "_print" method to produce output.

       When subclassing a reporter, a method "_top_heading" can be defined to provide the top heading.  This  is
       equivalent  to  an  explicit  call  to "set_topheading", but doesn't need to be repeatedly and explicitly
       executed for each new reporter.

   get_topheading
       Returns the current top heading routine, if any.

   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 "_std_header".  This  is
       the default value for the "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 "_print" method to produce output.

       When  subclassing  a  reporter,  the  method "_std_heading" can be overridden to provide a customized top
       heading. This is equivalent to an explicit call to "set_topheading", but doesn't need  to  be  repeatedly
       and explicitly executed for each new reporter.

   get_heading
       Returns the current standard heading routine, if any.

   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)]);

   get_fields
       Returns the current set of selected columns.

   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%' });

   get_widths
       Returns a hash with all column names and widths.

ADVANCED EXAMPLES

       This example subclasses Data::Report with  an  associated  plugin  for  type  "text".  Note  the  use  of
       overriding "_top_heading" and "_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}), "</title>\n",
                           '<link rel="stylesheet" href="css/', $self->get_style, '.css">', "\n",
                           "</head>\n",
                           "<body>\n",
                           "<p class=\"title\">", $self->_html($self->{_title1}), "</p>\n",
                           "<p class=\"subtitle\">", $self->_html($self->{_title2}), "<br>\n",
                           $self->_html($self->{_title3}), "</p>\n");
         }

         sub finish {
             my $self = shift;
             $self->SUPER::finish;
             $self->_print("</body>\n</html>\n");
         }

       Note  that  it  defines  an alternative "start" method, that is used to pass in additional parameters for
       title fields.

       The method "_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:

         <html>
         <head>
         <title>Title_One</title>
         <link rel="stylesheet" href="css/default.css">
         </head>
         <body>
         <p class="title">Title_One</p>
         <p class="subtitle">Title_Two<br>
         Title_Three_Left&amp;Right</p>
         <table class="main">
         <tr class="head">
         <th align="left" class="h_acct">Acct</th>
         <th align="left" class="h_desc">Report</th>
         <th align="right" class="h_deb">Debet</th>
         <th align="right" class="h_crd">Credit</th>
         </tr>
         <tr class="r_normal">
         <td align="left" class="c_acct">one</td>
         <td align="left" class="c_desc">two</td>
         <td align="right" class="c_deb">three</td>
         <td align="right" class="c_crd">four</td>
         </tr>
         <tr class="r_normal">
         <td align="left" class="c_acct">one</td>
         <td align="left" class="c_desc">two</td>
         <td align="right" class="c_deb">three</td>
         <td align="right" class="c_crd">four</td>
         </tr>
         <tr class="r_normal">
         <td align="left" class="c_acct">one</td>
         <td align="left" class="c_desc">two</td>
         <td align="right" class="c_deb">three</td>
         <td align="right" class="c_crd">four</td>
         </tr>
         <tr class="r_total">
         <td align="left" class="c_acct">one</td>
         <td align="left" class="c_desc">two</td>
         <td align="right" class="c_deb">three</td>
         <td align="right" class="c_crd">four</td>
         </tr>
         </table>
         </body>
         </html>

       See also the examples in "t/09poc*.t".

AUTHOR

       Johan Vromans, "<jvromans at squirrel.nl>"

BUGS

       Disclaimer:  This  module  is derived from actual working code, that I turned 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.

       Please  report  any  bugs  or  feature  requests  to "bug-data-report at rt.cpan.org", or through the web
       interface at <http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Data-Report>.  I will be notified, and  then
       you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

       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.

ACKNOWLEDGEMENTS

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.

perl v5.36.0                                       2022-10-14                                  Data::Report(3pm)