Skip to main content
replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

I agree with @amon@amon's answer for the most part. In addition, I propose an alternative implementation to eliminate this kind of duplicated logic:

I agree with @amon's answer for the most part. In addition, I propose an alternative implementation to eliminate this kind of duplicated logic:

I agree with @amon's answer for the most part. In addition, I propose an alternative implementation to eliminate this kind of duplicated logic:

Source Link
janos
  • 111.7k
  • 15
  • 152
  • 391

I agree with @amon's answer for the most part. In addition, I propose an alternative implementation to eliminate this kind of duplicated logic:

if ($alignment eq SOME_ALIGNMENT) {
    for my $line (@lines) {
        my $padding = $max_length - length $line;
        $line = PADDED_LINE
    }
}

You can eliminate this duplication by putting the different alignment formatting functions into a map:

sub align_left {
    my ($line, $padding) = @_;
    return $line . " " x $padding;
}

sub align_right {
    my ($line, $padding) = @_;
    return (" " x $padding) . $line;
}

sub align_center {
    my ($line, $padding) = @_;
    # we divide the $padding into two halves: $left and $right.
    # But what if $padding is an odd number?
    # Let's put the smaller padding $left.
    my $left = int($padding / 2);
    my $right = $padding - $left;
    return (" " x $left) . $line . (" " x $right);
}

my %align_fn = (
    left => \&align_left,
    right => \&align_right,
    center => \&align_center,
);

This will simplify the main function a bit:

sub align {
    my ($text_to_align, $alignment) = @_;
    my $fn = $align_fn{$alignment} || do {
        # this happens if an invalid $aligment was passed as argument.
        # Let's throw an error. We could use `die`, but that doesn't tell
        # an user of our function where *he* made an error. Instead, we use
        # the Carp module:
        require Carp;
        Carp::croak("Alignment must be one of left, right, center.");
    };

    my @lines = split /\n/, $text_to_align;

    # Trim whitespace, and find the longest line.
    # This is an OK use-case for the $_ variable.
    my $max_length = 0;
    for (@lines) {
        # I prefer \A and \z over ^ and $ because they always match at
        # string beginning and end, and are never influenced by /m.
        s{\A\s+}{};
        s{\s+\z}{};
        $max_length = length if length > $max_length;
    }

    # Perform the alignment, depending on the alignment type.
    # The alignment is performed in-place.
    for my $line (@lines) {
        my $padding = $max_length - length $line;
        $line = $fn->($line, $padding);
    }

    # join the lines back together again, and return
    return join "\n", @lines;
}