From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

#!/usr/bin/perl
use strict;
use Scalar::Util qw/refaddr/;
my $targ = "foo";
my $defer = eval { String::Defer->new(\$targ) };
my ($other, $targ2, $copy); # these needs to be declared before setup()
ok defined $defer, "new accepts a scalar ref";
is_defer $defer, "new returns a String::Defer"
or BAIL_OUT "can't even create an object!";
try_forcing $defer, "foo", "new object";
is_defer $defer, "forcing doesn't affect the object";
$targ = "bar";
is $defer->force, "bar", "forcing is deferred";
is "$defer", "bar", "stringify is deferred";
sub setup {
($targ, my $want) = @_;
$targ2 = uc $targ;
$want =~ s/%/$targ/g;
$want =~ s/#/$targ2/g;
$want;
}
sub check {
my ($what, $pat, $eval) = @_;
my $want = setup "foo", $pat;
my $str = $eval->();
unless (ok defined $str, "$what succeeds") {
diag "\$\@: $@";
return;
}
is_defer $str, "$what returns an object"
or return;
try_forcing $str, $want, $what;
$want = setup "bar", $pat;
try_forcing $str, $want, "deferred $what";
}
sub check_expr {
my ($what) = @_;
check @_, sub { eval $what };
$targ = "baz";
is "$defer", "baz", "$what doesn't affect the original";
}
check_expr @$_ for (
['$defer->concat("B")', "%B" ],
['$defer->concat("A", 1)', "A%" ],
['$defer->concat("B")->concat("A", 1)', "A%B" ],
['$defer . "B"', "%B" ],
['"A" . $defer', "A%" ],
['"A" . $defer . "B"', "A%B" ],
['"$defer B"', "% B" ],
['"A $defer"', "A %" ],
['"A $defer B"', "A % B" ],
);
$other = String::Defer->new(\$targ2);
check_expr @$_ for (
['$defer->concat($other)', "%#" ],
['$defer->concat($other, 1)', "#%" ],
['$defer->concat("A")->concat($other)', "%A#" ],
['$defer . $other', "%#" ],
['$defer . "A" . $other', "%A#" ],
['"A" . $defer . $other', "A%#" ],
['$defer . $other . "A"', "%#A" ],
['"${defer}$other"', "%#" ],
['"$defer A $other"', "% A #" ],
['"A ${defer}$other"', "A %#" ],
['"${defer}$other A"', "%# A" ],
['"A $defer B $other C"', "A % B # C" ],
);
for (
['"A"', "%A" ],
['"A" . "B"', "%AB" ],
['$other', "%#" ],
['$copy', "%%" ],
['$defer', "%%" ],
) {
my ($what, $pat) = @$_;
my $copy = $defer;
my $addr = refaddr $defer;
$what = "\$copy .= $what";
check $what, $pat, sub { eval $what; $copy };
is refaddr $defer, $addr, "$what leaves original unchanged";
isnt refaddr $copy, $addr, "$what creates a new \$copy";
$targ = "baz";
is "$defer", "baz", "$what leaves original unaffected";
}
done_testing;