Skip Menu |

This queue is for tickets about the Smart-Comments CPAN distribution.

Report information
The Basics
Id: 40109
Status: new
Priority: 0/
Queue: Smart-Comments

People
Owner: Nobody in particular
Requestors: BOLDRA [...] boldra.org
Cc: boldra [...] boldra.com
AdminCc:

Bug Information
Severity: Normal
Broken in: v1.0.3
Fixed in: (no value)



CC: boldra [...] boldra.com
Subject: for aliasing bug: patch and tests
Hi Damian, I admire your work, so when I found a bug in Smart::Comments, I wanted to impress you and send a fix. The bug can easily be seen with the following code: my @foo_ary = qw<a b c>; for my $foo ( @foo_ary ) { ### Crossing:===| done $foo = 'x'; } say "@foo"; Which prints "x x x" without Smart::Comments, but it prints "a b c" with it. The problem is that the for loop generated by the filter breaks Perls ability to create an alias to each value of the array (at least in 5.10). My patch fixes this, but only if the range of the for loop is a bare array. I started with something more ambitious, but gave up when I realised how hard it would be with ranges like "for ( $money-- )". So you probably need to add something to your doc too about these limitations, even if you don't use the patch. There's two new tests in the patch, "for_aliasing.t", which illuminates the bug, and "for_range_munging.t", which highlights the limitations of the patch. The patch should work from the Smart-Comments-v1.0.3 directory with "patch -Np1 <boldra_patch.diff" cheers Boldra
Subject: boldra_patch.diff
diff -Naur Smart-Comments-old/lib/Smart/Comments.pm Smart-Comments-v1.0.3/lib/Smart/Comments.pm --- Smart-Comments-old/lib/Smart/Comments.pm 2008-02-22 06:25:30.000000000 +0000 +++ Smart-Comments-v1.0.3/lib/Smart/Comments.pm 2008-10-16 19:14:01.313098300 +0000 @@ -175,13 +175,32 @@ sub _decode_for { my ($for, $range, $mesg) = @_; + #return "my \$not_first__$ID;" + # . "$for (my \@SmartComments__range__$ID = $range) { " + # . "Smart::Comments::_for_progress(" + # . "qq{$mesg}, \$not_first__$ID, \\\@SmartComments__range__$ID);"; # Give the loop a unique ID... $ID++; # Rewrite the loop with a progress bar as its first statement... - return "my \$not_first__$ID;$for (my \@SmartComments__range__$ID = $range) { Smart::Comments::_for_progress(qq{$mesg}, \$not_first__$ID, \\\@SmartComments__range__$ID);"; + + # Let loops with array ranges have access to aliases: + # (you deserve what you get if your array is tied!) + if( $range =~ m/^ \s+ \@ [\w:]+ \s+ $/xms ) { # eg @aaa + return "my \$not_first__$ID;" + . "$for ( $range ) { " + . "my \@SmartComments__range__$ID = $range; " + . "Smart::Comments::_for_progress" + . "(qq{$mesg}, \$not_first__$ID, \\\@SmartComments__range__$ID);"; + } else { + return "my \$not_first__$ID;" + . "$for ( my \@SmartComments__range__$ID = $range ) { " + . "Smart::Comments::_for_progress" + . "(qq{$mesg}, \$not_first__$ID, \\\@SmartComments__range__$ID);"; + } } + # Generate progress-bar code for a Perlish while loop... sub _decode_while { my ($while, $mesg) = @_; diff -Naur Smart-Comments-old/t/for_aliasing.t Smart-Comments-v1.0.3/t/for_aliasing.t --- Smart-Comments-old/t/for_aliasing.t 1970-01-01 00:00:00.000000000 +0000 +++ Smart-Comments-v1.0.3/t/for_aliasing.t 2008-10-16 19:21:15.461012500 +0000 @@ -0,0 +1,25 @@ +use Smart::Comments; +use Test::More tests => 2; + +close *STDERR; +my $STDERR = q{}; +open *STDERR, '>', \$STDERR; + +my @foo_ary = qw<a b c>; + +for my $foo ( @foo_ary ) { ### Crossing:===| done + $foo = 'x'; +} + +is_deeply( \@foo_ary, [ qw<x x x> ], 'loop aliased correctly' ); + + +TODO: { + my @bar_ary = qw<a b c>; + for my $foo ( ( @bar_ary ) ) { ### Crossing:===| done + $foo = 'x'; + } + local $TODO = "testing for a bare array is still very crude"; + is_deeply( \@bar_ary, [ qw<x x x> ], 'loop aliased correctly' ); +} + diff -Naur Smart-Comments-old/t/for_range_munging.t Smart-Comments-v1.0.3/t/for_range_munging.t --- Smart-Comments-old/t/for_range_munging.t 1970-01-01 00:00:00.000000000 +0000 +++ Smart-Comments-v1.0.3/t/for_range_munging.t 2008-10-16 18:43:21.115181700 +0000 @@ -0,0 +1,13 @@ +use Smart::Comments; +use Test::More tests => 1; + +close *STDERR; +my $STDERR = q{}; +open *STDERR, '>', \$STDERR; + + +my $a = 0; +for ( $a++ ) { ### Crossing:===| done + +} +is( $a, 1, 'range not munged' );