SPUG: multi-line substition, all at once.

Joshua ben Jore twists at gmail.com
Mon Jun 29 08:29:18 PDT 2009


=email

On Thu, Jun 25, 2009 at 4:25 AM, Jacinta
Richardson<jarich at perltraining.com.au> wrote:

I found I liked your approach quite a bit so I've written this email
as a program for you. Starting off, I'm using your suggestion to be
explicit about my heredoc quoting. What follows is an example of using
single-quoting so I know there's no interpolation.

=cut

use strict;
use warnings;
use Test::More tests => 1;

my $code=<<'__CODE__';
...
 :    sub hello {
 :        say "Hello World!";
 :    }
...
__CODE__




=email

The core regexp is rather simple. I found it nicer to put it into its
own variable so I could go back later and test that it was working
correctly with Test::Regexp. The base regexp just finds a series of
lines starting with some spaces and a colon. The modification work is
delegated to an s{$RX}{ code }e expression. Now that the pattern is
separate, I can pay more attention to each in its own idiom.

=cut

my $RX = qr/(?mx) # allow whitespace and comments, ^ matches some line beginning
  # Capture...
  (
    (?: # A series...
      ^\ +:[^\n]*\n # of colon marked lines
    )+
  )
/;




=email

I'll also use Jacinta's no_colon to remove the leading colon markers.

=cut

sub no_colon {
  my ( $code ) = @_;
  $code =~ s/^ +://mg;
  return $code;
}




=email

I added one more function for adding the [code] tags. The point being,
while I was doing all this mucking around, I might as well make the
eventual expression as readable as possible.

=cut

sub code_tag {
  my ( $code ) = @_;
  "[code]$code\[/$code]";
}




=email

All the work happens in a very small space now and I hope is more
readable. In particular, I learned to use {} bracing for expressions
I'm going to use with /e because then it looks more like normal code
bracing. It's a small hint to the reader to expect code.

=cut

$code =~ s{$RX}{
  code_tag(
    no_colon(
      $1 ));
}e;




=email

Lastly, since I was going to this effort, I wrote a test to check that
I was doing what I expected.

=cut

is( $code, <<'__EXPECTED__' );
...
[code]    sub hello {
        say "Hello World!";
    }
[/code]
...
__EXPECTED__




=email

Cheers,
Josh

=cut


More information about the spug-list mailing list