Indented Here-Docs in Perl

I just used an indented here-doc in a Perl program! This feature has been around since Perl 5.26 (released 2017-05-30T19:42:51), but I haven't needed it until now. What fun!

Here is my solution to the Bottle Song puzzle on exercism.

package BottleSong;

use v5.40;

use Exporter qw(import);
our @EXPORT_OK = qw(sing);

my @numbers = qw(no one two three four five six seven eight nine ten);

sub sing ( $bottles, $verses ) {
    return join "\n", map { verse($bottles - $_) } 0..$verses - 1;
}

sub verse($number) {
    my $cap = ucfirst $numbers[$number];
    my $cap_sp = $number == 1 ? 'bottle' : 'bottles';
    
    my $prev = $numbers[$number - 1];
    my $prev_sp = $prev eq 'one' ? 'bottle' : 'bottles';
    
    my $lines =<<~"END_LINES";
    $cap green $cap_sp hanging on the wall,
    $cap green $cap_sp hanging on the wall,
    And if one green bottle should accidentally fall,
    There'll be $prev green $prev_sp hanging on the wall.
    END_LINES

    return $lines;
}

1;

I think that here-doc looks lovely! Well, whatever Hugo is using for syntax highlighting doesn't seem to understand Perl very well, but it looks great in my $EDITOR!

./emacs.png

Before Perl 5.26, we would have had to write it without indentation like this

    my $lines =<<"END_LINES";
$cap green $cap_sp hanging on the wall,
$cap green $cap_sp hanging on the wall,
And if one green bottle should accidentally fall,
There'll be $prev green $prev_sp hanging on the wall.
END_LINES

or else do some shenanigans like this

    (my $lines =<<"    END_LINES") =~ s/^ {4}//gm;
    $cap green $cap_sp hanging on the wall,
    $cap green $cap_sp hanging on the wall,
    And if one green bottle should accidentally fall,
    There'll be $prev green $prev_sp hanging on the wall.
    END_LINES

Basically, the =<<~ operator in newer Perls does those shenanigans for us. Hooray!