#$Id: Changes 1217 2008-02-10 00:06:02Z jimk $
Revision history for Perl extension Data::Presenter

1.03 Sat Feb  9 19:57:22 AST 2008
    -Deleted some commented out code.  Added SVN Id tags.

1.02    Thu Dec 29 2005

    - Corrected documentation error in SYNOPSIS:  lack of calling object for
seen_one_column().

    - _validate_args():  Simplified error message:  What was formerly a carp
followed by a croak is now just a croak.  Also, deleted (for now, at
least) reference to the calling method, as this internal subroutine is called
by a variety of methods and subroutines.

    - Corrected bug in Data::Presenter::Combo::Union::_process_secneeded().
Previously, this auxiliary subroutine processed the elements of %{$secneededref}
without sorting them.  This ultimately meant that the data in the non-first
objects passed as arguments to Combo::Union->new() were being assigned into
records within the Combo::Union object in random order.  Since the keys of
that hash are numerical, sorting the keys in numerical order fixes the
problem.  sort_by_column() now DWIMs for Combo::Union objects.  This bug was
not picked up because all the writeformat-type tests in t/04.t were
essentially misspecified.  They also have been corrected.

    - Eliminated commented-out code in Combo::Intersect and Combo::Union.

1.01    Wed Dec 28 2005

    - Deleted erroneous call to 'use Test::DataPresenterSpecial' from
Data::Presenter::Combo::Union.

1.0     Sat Dec 24 2005

    - Version number incremented to 1.0 to alert users to major change of
interface.  writeformat-family of nine methods now takes list of key-value
pairs as arguments rather than simple list (which required keeping track of
order of arguments).  In Data::Presenter::[Package1] subclasses (those from
which objects are created), _init() now has $index assigned directly to
$data{index} rather than being element 0 of an array passed by reference to
$data{index}.  Extensive additional testing.  Use of Devel::Cover for coverage
analysis was used to trim unreachable code and bring all statement, condition
and subroutine coverage up to 100% and to bring all branch coverage except
open() and close() calls up as well.

0.69    Wed Nov 30 2005
    - Partial overhaul including extensive additions to test coverage and
documentation, but as yet no change in functionality.  Because a bug
(incorrect sorting when requesting sorting in descending order) was found,
this version was not uploaded to CPAN.  Instead, it was tarballed so that I
would have a reference point for the next version.  Because of severity of
bug, v0.68 was withdrawn from CPAN.

0.68    Sat Oct 23 2004
	- Corrected substandard code at +1005 Presenter.pm to avoid error "Bizarre copy of array" error when running tests under Devel::Cover

0.67    Sat Oct 23 2004
	- Corrected substandard code at +322 Presenter.pm to avoid error "Bizarre copy of hash in leave" error when running tests under Devel::Cover

0.66    Wed Jun  9 2004
	- POD correction only:  Corrected error in POD for Data::Presenter::Sample Medinsure which resulted in bad POD-to-HTML translation and bad display on search.cpan.org

0.65    Wed Jun  2 2004
	- Corrected Intersect.pm and Union.pm to avoid "Bizarre array assignment" error when installing under Perl 5.8.4 on Darwin.

0.64	Sun Oct  5 2003
	- Added method get_keys_seen();

0.63	Sun Aug 24 2003
	- Added method seen_one_column();

0.62	Sun Apr 13 2003
	- Corrected errors in documentation.

0.61	Sat Apr 12 2003
	- First upload to CPAN.

0.60	Sat Apr 12 2003
	- Begin preparation for public distribution.

Revision history of Data::Presenter prior to public distribution:

Data::Presenter versions 0.3 through 0.39 incorporate the following
corrections and improvements over version 0.2 which was released 10/28/2001.

=over 4

=item *

Introduced C<$index> as one of the variables specified in I<fields.XXX.data>,
imported into the main package and used as metadata inside the
Data::Presenter object.  This eliminates some hard-coding inside subroutines
C<_init()> and C<_extract_rows()> inside Data::Presenter::[subclass] packages. 
It also necessitated a revision of C<_build_sort_formula()>, a large part of
which was extricated into the separate subroutine C<_formula_engine()>.  This
for the first time permitted on index keys which were not entirely numerical.
 So now one can sort on, say, product serial numbers such as C<'24TY-789'>.

=item *

Established a package global hash C<%reserved> within I<Data::Presenter.pm>
and C<%reserved_partial> within I<Data::Presenter::Combo::Intersect.pm> and
I<Data::Presenter::Combo::Union.pm>.  These are hashes of words such as
'fields', 'parameters', 'index' and 'options' which are reserved for current
or future use as keys in the hash blessed into the Data::Presenter object. 
These keys generally have to be excluded when preparing Data::Presenter
selection, sorting and output methods.  The coding for this exclusion is must
easier if one can write:

    unless $reserved{$i} {
    # do something
    }

in contrast to the earlier:

    unless ($i eq 'fields' || $i eq 'parameters') {
    # do something
    }

=item * C<_format_picture_line()> and C<writeHTML()> now format numerical columns
flush-right.

=item *

A bug was fixed in C<_build_sort_formula()> that was causing 'HERNANDEZ' to
precede 'HERNAN' in alphabetical sorts.  This was caused by the internal use
of C<'|'> as the delimiter between array entries.  C<'|'> has a higher ASCII
position than any alphabetical or numerical character.  Hence 'HERNANDEZ|'
has a lower sorting value position than 'HERNAN|'.  This has been corrected
by substituting C<'!'> as the delimiter, since C<'!'> has a lower ASCII value
than any alphabetical or numerical character.  One side effect is that the
character C<'!'> may not appear in data being input into Data::Presenter
objects.

=item *

Clarified error messages in C<_validate_fields()> and C<_analyze_relation()>.

=item *

Up through v0.31, if the operator were to call C<writeformat()>,
C<writeformat_plus_header()> or any combination thereof I<more than once> in a
particular Perl script I<and if> in so doing the operator used any of the
entries in C<@fields> I<more than once> as an element in
C<@columns_selected>, then a warning would have been printed to STDERR
stating:

    Variable "[$some_variable]" is not imported at
    (eval 2 [or higher number]) line [some_line_number].

To illustrate using the previously discussed examples:

    @columns_selected = ('lastname', 'firstname', 'datebirth', 'cno');
    $sorted_data = $dp1->sort_by_column(\@columns_selected);
    $outputfile = 'format01.txt';
    $dp1->writeformat($sorted_data, \@columns_selected, $outputfile);

    @columns_selected =
    ('lastname', 'firstname', 'dateadmission', 'cno');
    $sorted_data = $dp1->sort_by_column(\@columns_selected);
    $outputfile = 'format01.txt';
    $dp1->writeformat($sorted_data, \@columns_selected, $outputfile);

would have generated warnings resembling these:

    Variable "$lastname" is not imported at (eval 2) line 10.
    Variable "$firstname" is not imported at (eval 2) line 10.
    Variable "$cno" is not imported at (eval 2) line 10.

The author had run the program on live data many times and these warnings
were never indicators of any incorrect output.  This warning message is
discussed in C<perldoc perldiag> and on page 975 of L<Camel|"REFERENCES"> at
'Variable ''%s'' is not imported%s'.  That discussion implies that this
warning would not have appeared if C<use strict> were not in effect. 
However, the author tested this by calling C<no strict> before
C<writeformat()> and returning to C<use strict> therefafter.  The warnings
continued to be thrown.

The author then ventured to post the problematic code on comp.lang.perl.misc
and had his hand properly slapped for improper use of symbolic references. 
In the course of the slapping, the slapper, Mark-Jason Dominus, suggested
using the Perl C<formline> function and format accumulator variable C<$^A> --
which internally power Perl formats -- instead of formats I<per se>.  At the
same time, MJD discovered a bug in Perl 5.6 which was enabling the author to
get valid data out of C<writeformat()> despite improper use of symbolic
references.  MJD subsequently reported to the author that the bug was
patched, but since C<formline> was working well and throwing no warning
messages, he left well enough alone.  This turned out to be providential, as
the C<$^A> was later to play a key role in the creation of
C<writeformat_with_reprocessing()>.

=item *

In v0.33 two errors in the specification of C<%ne> within
C<_analyze_relation()> were corrected.

=item *

Output method C<print_with_delimiter()> was added in v0.34 to permit the
operator to select the delimiter characters used when printing to file.  This
method is designed to be used in situations where the operator intends to
further manipulate the data with a word processor function such as 'Convert
text to tabs'.

=item *

Method C<get_keys()> was added in v0.35 to permit operator to get an
ASCII-betically sorted list of the indices of the data records currently
stored in the Data::Presenter::[Package1] object.

=item *

In v0.36 code which was common to both C<print_to_screen()> and
C<print_to_file()> was abstracted and placed in an internal subroutine called
C<_print_engine>.

=item * C<writeformat_with_reprocessing()> was introduced in v0.38.  This format uses
uses CPAN module List::Compare.  In order to extend the applicability of
C<_validate_args> to cover C<writeformat_with_reprocessing()>, it was modified
so as to receive an additional argument, a reference to package variable
C<%fp>.  As C<_format_argument_line()> is no longer used within <writeformat()>
or C<writeformat_plus_header()>, it was deleted.  The superfluous and
potentially confusing C<<LINK>> tag is removed from C<writeHTML()>.

=item *

Prior to v0.39 _format_picture_line() was being called with each iteration of
the 'foreach' loop over the output records.  As this was unnecessary, it was
pulled out of that loop.  The requirement that the title line in
C<writeformat_plus_header()> and C<writeHTML()> be preceded by the words
''Selected fields from:  '' has been dropped.

=item *

v0.40:  In preparation for an eventual release to CPAN, the module was
renamed Data::Presenter.

=item *

v0.41:  Running Data::Presenter on Perl 5.8 for the first time, received
warnings in full_report() and print_with_sep().  Fixed sigils.

=item *

v0.42:  In many of the format-related subroutines, I was passing C<@args> as
an array.  Changed this so that I was passing by reference, which meant that
in certain cases I could eliminate C<@args> as a variable inside a
subroutine.  (However, in other cases it was retained inside the subroutine
for clarity.)

=item *

v0.43 (1/22/03):  Corrected a typo in C<_analyze_relation()> which was causing
incorrect results when C<$relation = '>='>.

=item *

v0.44 (2/9/03):  Tightened up coding in C<get_data_count()>,
C<print_data_count()> and C<_count_engine()>.

=item *

v0.45 thru v0.47 (2/19-21/03):  Introduced and refined C<writeformat_deluxe()>
to permit both a format header and dynamic reprocessing of fields (columns). 
As this shared repeated code with C<writeformat_with_reprocessing()>,
extracted redundant code and placed it in C<_prepare_to_reprocess()> and
C<_prepare_substring_data_and_picline()>.  Also, spotted an error in
C<writeformat_with_reprocessing()>:  C<$lc> a 2nd time where I should have
called C<$lc1>.

=item *

v0.48 (2/22/03):  Combined C<_prepare_to_reprocess()> and
C<_prepare_substring_data_and_picline()> into C<_prepare_to_reprocess()>.

=item *

v0.49 (2/22/03):  Used C<map {$_ =E<gt> 1} LIST> to populate hashes such as
C<%reserved> rather than assigning C<=E<gt> 1> for each individual key.

=item *

v0.50 (2/23/03):  Corrected C<writeHTML()> to use
C<_format_argument_line_top2> and C<_format_hyphen_line_2>.

=item *

v0.51 (2/24/03):  Made changes in C<writeformat_with_reprocessing()>,
C<writeformat_deluxe()>, C<_prepare_to_reprocess()>,
C<Data::Presenter::_Assorted::_reprocessor()> and
C<Data::Presenter::_Assorted::reprocess_timeslot()> to accommodate correct
output of times for those groups that start later in the timeslot, I<e.g.>, a
10:45 start for certain Ward 10 and 11 groups in the second timeslot of the
day.

=item *

v0.52 (3/3/03):  Began working on subroutines which, like the
C<writeformat...()> family of subroutines, will dynamically output data from
selected fields (columns) in the database, but with the fields separated by
an operator-supplied delimiter.  (The delimiter will frequently be C<\t> to
take advantage of word processing program features which convert
tab-delimited copy to tables.)    So far I have created C<writedelimited()> and
C<writedelimited_plus_header()> and, for internal use within the latter,
C<_format_argument_line_top3>.  Also, eliminated C<my $LR =
$lc-E<gt>is_LsubsetR;> from C<_prepare_to_reprocess>, as C<$LR> is not used
anywhere.

=item *

v0.53 & v0.54 (3/6/03):  Continued work on the C<writedelimited...()> family
of subroutines, adding C<writedelimited_with_reprocessing()> and other
subroutines needed in the C<Data::Presenter::[package1]()> invoking subclass. 
In a manner similar to C<writeformat_with_reprocessing()>,
C<writedelimited_with_reprocessing()> enables the operator to do
'just-in-time' reprocessing of the data elements which will be joined by
C<$delimiter> in output.

=item *

v0.55 (3/6/03):  Continued work on the C<writedelimited...()> family of
subroutines, adding C<writedelimited_deluxe()>.  In a manner similar to
C<writeformat_deluxe()>, C<writedelimited_deluxe()> enables the operator to
provide column headers and do 'just-in-time' reprocessing of the data
elements which will be joined by <$delimiter> in output.  Unlike
C<writeformat_deluxe()>, however, C<writedelimited_deluxe()> is meant to
provide input to a word processing program's 'convert text to table' feature,
in which case a title line would be superfluous.  Hence
C<writedelimited_deluxe()> does not take C<$title_raw> as an argument.

=item *

v0.56 (3/7/03):  Provided documentation for C<writedelimited...()> family of
subroutines.

=item *

v0.57 (3/15/03):  Corrected error in header of C<writeHTML()>.  Included a
carp warning in C<new()> to warn the operator if, after initialization, the
Data::Presenter::[package1] object contains zero elements (other than
metadata).  Similarly modified C<_count_engine()> to return 0 in same
situation.

=item *

v0.58 (3/26/03):  Clarified the error message in C<_validate_args()> to
indicate which arguments passed to C<sort_by_column()> are invalid.

=item *

v0.60 (4/6/03):  Preparation for distribution to CPAN.

=item *

v0.61 (4/12/03):  Corrected failure to list F<Data::Presenter::Combo> in
MANIFEST.

=item *

v0.63 (8/24/03):  Created C<seen_one_column()>.

=item *

v0.64 (10/5/03):  Created C<get_keys_seen()>.

=item *

v0.65 (6/2/04):  Corrected 1 line of code in each of Intersect.pm and
Union.pm which was generating error "Bizarre copy of array" when testing
under Perl 5.8.4 on Darwin.

=item *

v0.66 (6/9/04):  POD correction only:  Corrected error in POD for
Data::Presenter::Sample Medinsure which resulted in bad POD-to-HTML
translation and bad display on search.cpan.org

=item *

v0.67 (10/23/04):  Corrected substandard code at +322 Presenter.pm to avoid
error "Bizarre copy of hash in leave" error when running tests under
Devel::Cover

=item *

v0.68 (10/23/04): Corrected substandard code at +1005 Presenter.pm to avoid
error "Bizarre copy of array" error when running tests under Devel::Cover

=back

Possible future lines of development include:

=over 4

=item * C<writeHTML()> could be rewritten or supplemented by a method which writes a
true HTML table.

=item *

And if we were really I<au courant>, we'd have a C<writeXML()> method!

=item *

The hashes defined within C<_analyze_relation()> which offer the operator
flexibility in defining C<$relation> could be expanded to include expressions
in any human language using the ASCII character set.

=item *

Develop a Perl::TK GUI to make it easier for operators to build and run
Data::Presenter scripts.

=item *

Add an additional, optional element to the arrays on the value side of
C<%parameters>:  the name of a subroutine used by the administrator to
massage the data entering through a given field.  It is not clear yet how
this would work with a Data::Presenter::Combo object.

=back