princepawn has asked for the wisdom of the Perl Monks concerning the following question:

I have written a module which takes advantage of Text::Autoformat and Date::Business to generate status reports for my boss (and my boss' boss.) So, the odd thing about program execution is that I actually print all strings (call them debug strings) which are appended to the final string as the program runs. In looking at the debug output, please note that even though my debug string plainly and clearly states that it is adding the following string to the final string: depth: 2 adding: ((        1. General If you actually look at the generated text. This item comes out bulleted as: 3. General instead of 1. General as advertised.

Text created while program is running

depth: 1 adding: (( 1. Accomplishments in the past week * Solved the sample bugfix test question posed by Jeb. * Installed Visio from floppies. * Created a flow diagram of the Obsolete Bugfix Checkin use ca +se * Hand-wrote proposed addition to initial pull-down so that i +t was completely manifest to the user how to edit the text of a b +ugfix checkin * Developed a "final common pathway" flow for re-submitting b +ugfix checkins that would be hooked into at two places in the ori +ginal program flow --- the beginning from the new menu choice and + when the entered bug # was already obsoleted * Presented this design and upon reflection decided that the man-hours for implementation could not justify such an elab +orate implementation * Opted to simply move the entry of obsolescence to a new scr +een and parameterize it based on whether or not the bug was already obsoleted. * Successfully went end-to-end after removing the "Reason for Obsolescence" text from PreDeleteForm.dhtml and added it to +my new ObsoleteText.pm/.dhtml files. )) depth: 2 adding: (( 1. General * Allow the editing of the text of already-obsoleted bug r +eports. * Automate generation of this report * Convert/print timesheet * Develop a deeper understanding of how the Web applicatio +n framework actually works. Such an understanding is necessary if I +want to write good error-checking and handling routines. Concomitant with the understanding, I am developing a tr +ee of pod documentation for referral by me and other developers. * Implement error-checking in the newly developed Obsolete +Text.pm. )) depth: 2 adding: (( 2. Vacations * None )) depth: 2 adding: (( 3. Classes * None )) depth: 1 adding: (( 2. Plans for the next week 1. General * Allow the editing of the text of already-obsoleted bug r +eports. * Automate generation of this report * Convert/print timesheet * Develop a deeper understanding of how the Web applicatio +n framework actually works. Such an understanding is necessary if I +want to write good error-checking and handling routines. Concomitant with the understanding, I am developing a tr +ee of pod documentation for referral by me and other developers. * Implement error-checking in the newly developed Obsolete +Text.pm. 2. Vacations * None 3. Classes * None )) depth: 1 adding: (( 3. Outstanding issues * Bcc'ed mail ends up in my INBOX. Would rather it be automati +cally filed somewhere * Netscape doesn't remember email addresses that it should. * AruchkinForm.pm: how does the decode() function work? $driver_path_map = ARUDB::cache( "select decode(release_id, 999, '107', 1250, '107', release_major_version || release_minor_version) +, release_id from aru_releases where obsolete <> 'Y' or obsolete is null"); * Not sure how updates are done to the database. ))

Actual output text

(at odds with what it said it was creating) Note under main bullet 2 That "General" is bulleted with a 3 even though the debug text promises it will output with a 1.

Status report for the week ending 02-09-2001 1. Accomplishments in the past week * Solved the sample bugfix test question posed by Jeb. * Installed Visio from floppies. * Created a flow diagram of the Obsolete Bugfix Checkin use ca +se * Hand-wrote proposed addition to initial pull-down so that i +t was completely manifest to the user how to edit the text of + a bugfix checkin * Developed a "final common pathway" flow for re-submitting bugfix checkins that would be hooked into at two places in the original program flow --- the beginning from the new me +nu choice and when the entered bug # was already obsoleted * Presented this design and upon reflection decided that the man-hours for implementation could not justify such an elaborate implementation * Opted to simply move the entry of obsolescence to a new screen and parameterize it based on whether or not the bug was already obsoleted. * Successfully went end-to-end after removing the "Reason for Obsolescence" text from PreDeleteForm.dhtml and added it to my new ObsoleteText.pm/.dhtml files. 2. Plans for the next week 3. General * Allow the editing of the text of already-obsoleted bug reports. * Automate generation of this report * Convert/print timesheet * Develop a deeper understanding of how the Web applicatio +n framework actually works. Such an understanding is necessary if I want to write good error-checking and handling routines. Concomitant with the understanding, I am developing a tr +ee of pod documentation for referral by me and other developers. * Implement error-checking in the newly developed ObsoleteText.pm. 2. Vacations * None 3. Classes * None 3. Outstanding issues * Bcc'ed mail ends up in my INBOX. Would rather it be automatically filed somewhere * Netscape doesn't remember email addresses that it should. * AruchkinForm.pm: how does the decode() function work? $driver_path_map = ARUDB::cache( "select decode(release_id +, 999, '107', 1250, '107', release_major_version || release_minor_version), release_id from aru_releases where obsolete <> 'Y' or obsolete is null"); * Not sure how updates are done to the database.

Agenda.pm

package Text::Autoformat::Agenda; require 5.005_62; use strict; use warnings; require Exporter; our @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not expo +rt # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. # This allows declaration use Text::Autoformat::Agenda ':all'; # If you do not need this, moving things directly into @EXPORT or @EXP +ORT_OK # will save memory. our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( ); our $VERSION = '0.01'; our $incr; our $depth; # Preloaded methods go here. sub new { my $class = shift; my %config = @_; my $self = bless \%config, $class; } sub tab { " " x (@_ ? $depth+$_[0] : $depth) } sub verbose_add_content { printf "depth: %d adding: ((%s))\n", $depth, $_[1]; $_[0] .= $_[1] } sub proc_array { my $self = shift; my $content; ++$depth; local $incr; while (@_) { my ($key,$val) = splice @_, 0, 2; if (!ref($val)) { ++$incr; my $F="$self->{Dir}/$val"; open F, $F or die "Couldnt open $F: $!"; my $_content; while (<F>) { $_content .= sprintf "%s%s", tab(1), $_; } my $bullet = sprintf "%s%s. %s\n%s", tab, $incr, $key, $_content; verbose_add_content($content,$bullet); # $content .= $bullet; } else { my $bullet = sprintf "%s%s. %s\n%s", tab, ++$incr, $key, $self->proc_array(@$val); verbose_add_content($content,$bullet); # $content .= $bullet ; } } --$depth; $content; } sub content { my $self = shift; my $body = $self->proc_array(@{$self->{Agenda}}); "$self->{Title}\n\n$body"; } 1; __END__ # Below is stub documentation for your module. You better edit it! =head1 NAME Text::Autoformat::Agenda - Automated agenda creation from flat files =head1 SYNOPSIS use Text::Autoformat::Agenda; # requires Text::Autoformat use Date::Business # not required. just useful for my agendas my $d = new Date::Business(FORCE => 'next'); my ($year,$month,$day) = ($d->image =~ /(.{4})(.{2})(.{2})/); my $pretty_date = "$month-$day-$year"; my $agenda = Text::Autoformat::Agenda->new ( Dir => '/home/tmbranno/status', Title => "Status report for the week ending $pretty_date", Agenda => [ "Accomplishments in the past week" => 'accomplishments.txt', "Plans for the next week" => [ General => 'plans.txt', Vacations => 'vacations.txt', Classes => 'classes.txt' ], "Outstanding issues" => 'issues.txt' ] ); print $agenda->content; =head1 DESCRIPTION Stub documentation for Text::Autoformat::Agenda, created by h2xs. It l +ooks like the author of the extension was negligent enough to leave the stub unedited. Blah blah blah. =head2 EXPORT None by default. =head1 AUTHOR A. U. Thor, a.u.thor@a.galaxy.far.far.away =head1 SEE ALSO perl(1). =cut

test.pl

# Before `make install' is performed this script should be runnable wi +th # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on f +ailure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) BEGIN { $| = 1; print "1..1\n"; } END {print "not ok 1\n" unless $loaded;} use Text::Autoformat::Agenda; $loaded = 1; print "ok 1\n"; ######################### End of black magic. # Insert your test code below (better if it prints "ok 13" # (correspondingly "not ok 13") depending on the success of chunk 13 # of the test code): use Text::Autoformat; use Text::Autoformat::Agenda; # requires Text::Autoformat use Date::Business; # not required. just useful for my agendas my $d = new Date::Business(FORCE => 'next'); my ($year,$month,$day) = ($d->image =~ /(.{4})(.{2})(.{2})/); my $pretty_date = "$month-$day-$year"; my $agenda = Text::Autoformat::Agenda->new ( Dir => '/home/tmbranno/status', Title => "Status report for the week ending $pretty_date", Agenda => [ "Accomplishments in the past week" => 'accomplishments.txt', "Plans for the next week" => [ General => 'plans.txt', Vacations => 'vacations.txt', Classes => 'classes.txt' ], "Outstanding issues" => 'issues.txt' ] ); print autoformat $agenda->content, { all=>1 };

perl commandline to run (edit to taste)

PERL_DL_NONLAZY=1 /arudev/bin/perl -Iblib/arch -Iblib/lib -I/arudev/li +b/perl5/5.6.0/sun4-solaris -I/arudev/lib/perl5/5.6.0 test.pl

Replies are listed 'Best First'.
Re: Recursive string building: stepwise and final strings differ
by footpad (Abbot) on Feb 12, 2001 at 23:19 UTC
    Welcome back. Hope you enjoyed retirement.

    Um, would you mind updating your node to fix the unbalanced <H1> tag?

    In viewing the source for your rendered node, I found this:

    <H1>perl commandline to run< (edit to taste)/h1>

    I, for one, would be very grateful.

    Also, you may find <H4> tags make things a little easier to read than <H1> tags. Just a friendly suggestion.

    --f

    Update:  As tye just reminded me via CB, you probably won't be able to update the node, which is a pity, but understandable. Not to be too nosy, but you did preview this carefully, didn't you?

Re: Recursive string building: stepwise and final strings differ
by extremely (Priest) on Feb 12, 2001 at 22:10 UTC
    Man you boorked the html bad princpawn. =P Your problem relates to $incr which you local $incr;. Thus the code that is called to an outside sub sees the "outer" $incr thanks to the our.

    I'd think about changing that code to either my $incr; or keeping a stack of @incr and using $incr[++$depth]=0; and $incr[$depth] whereever you have been using just $incr.

    Does that make sense?

    --
    $you = new YOU;
    honk() if $you->love(perl)

      I got rid of the our and changed the local to my. But the code still outputs the same results. The problem with your explanation is that there is no access of $incr outside of the sub proc_array And if you check comp.lang.perl.moderated, you will see that I have an equivalent formulation of the problem there done without local() and instead keeping a stack. It's just a very hard thing to figure out.
        Ok, next attempt, take the ++ out of this line,
        my $bullet = sprintf "%s%s. %s\n%s", tab, ++$incr, $key, $self->proc_array(@$val);
        and see if it was causing the value of $incr to "pass thru".

        --
        $you = new YOU;
        honk() if $you->love(perl)

Re: Recursive string building: stepwise and final strings differ
by chipmunk (Parson) on Feb 12, 2001 at 22:44 UTC
    Here's the sub that prints the debug message and appends the content:
    sub verbose_add_content { printf "depth: %d adding: ((%s))\n", $depth, $_[1]; $_[0] .= $_[1] }
    As we can see, it prints $_[1] and appends $_[1]. Of course, the value of $_[1] should be exactly the same each time (barring a weird use of tied scalars).

    So, my best guess is that something else is going on. Is it possible that the script you're editing and the script you're running are two different files? I've made that mistake a few times.

    If the bug doesn't reveal itself soon, you may want to package up all the files involved, put them on the web, and post a link, so that other monks can download it and run the same test you're using.