Use Carp::REPL as an interactive Perl shell.

Wouldn’t it be great if you could stop your program right before it died so you could see what’s causing the problem? You could start the Perl debugger and step your way to the problem, or set up some break points, but that’s often too much work. The Carp::REPL module let’s you drop into a debugger just at the point you need.

Before you get too far, take a look at Devel::REPL, which Carp::REPL is based on. It’s a basic Read-Evaluate-Print Loop for Perl. You enter a line of Perl then the REPL evaluates it and prints the result.

You can start the REPL from the command line:

perl -MDevel::REPL -e 'Devel::REPL->new->run'

Devel::REPL also installs an re.pl that you can use, but it’s not too hard to write your own, especially if you’d like to remind yourself how to get out of the REPL:

use Devel::REPL;

print "Starting a Devel::REPL setting. Type exit to stop\n";

my $repl = Devel::REPL->new;
$repl->load_plugin($_) for qw(History LexEnv MultiLine::PPI);
$repl->run;

Run repl and try some Perl expressions. Notice that you get both the output from print or say as well as the result of the print or say (normally 1):

Starting a Devel::REPL setting. Type exit to stop
$ my $string = 'The Effective Perler'
The Effective Perler
$ say $string
The Effective Perler
1
$ substr( $string, 9, 4 )
tive
$ substr( $string, 14, 4 )   
Perl
$ $$
66461
$ $string =~ /Perl/
1
$ $string =~ /Ruby/
$ $string =~ /(P\S+)/
Perler
$ $string
The Effective Perler
$ localtime
16 32 2 16 4 110 0 135 1
$ time
1273995160
$ use List::Util qw(sum)
$ sum( 1 .. 1000 )
500500
$ my $sub = sub {
> my $x = shift;   
> print $x*2;
> }
CODE(0xa66990)
$ $sub->(4)
8
1 

That’s nice to try out some short Perl code and isolated expressions, but you’d like to be able to do that somewhere in the middle of a big program. That’s where Carp::REPL comes in. It installs a DIE handler that invokes Devel::REPL.

Here’s a small script that sometimes dies, and although Perl tells you why, pretend that it doesn’t:

#!/Users/brian/bin/perl5.10.1

use 5.010;

my( $arg1, $arg2 ) = @ARGV;

my $quotient = divide( $arg1, $arg2 );

say "quotient is $quotient";

sub divide { $_[0] / $_[1] }

Here’s a couple of runs:

$ perl divide 1 2
quotient is 0.5
$ perl divide 1 0
Illegal division by zero at divide.pl line 7.

To track down the error, load Carp::REPL from the command line and run the program. Instead of killing the program, the runtime error triggers an interactive shell so you can explore the problem:

$ perl -MCarp::REPL divide.pl 1 0
Illegal division by zero at divide.pl line 11.

Trace begun at divide.pl line 11
main::divide(1, 0) called at divide.pl line 7
$ 

Okay, so what now? You’re at line 7, but what is that? Look around with :l:

$ :l
  6: 
  7: my $quotient = divide( $arg1, $arg2 );
  8: 
  9: say "quotient is $quotient";
 10: 
*11: sub divide { $_[0] / $_[1] }

Once you see that line 11 is the division, and you need to handle that better. You can redefine divide (the result is the subroutine definition *main::divide) and try again using the same arguments:

$  *divide = sub { eval { $_[0] / $_[1] } // 'NaN' }
Subroutine main::divide redefined at (eval 266) line 21,  line 6.
*main::divide
$ divide( $arg1, $arg2 )
NaN

Now divide works! Since Carp::REPL comes in as your program is already die-ing, you don’t have a chance to pick up where you left off unless your code is already set up to recover from a die, such as with an eval block.

There’s a lot more that you can do with Carp::REPL. You can set a warn handler instead so you can drop into the REPL when your program emits a warning:

$ perl -MCarp::REPL=warn some_program

You can also debug your test files by dropping into the REPL when a test fails:

$ perl -Mblib -MCarp::REPL=test t/test.t

Besides the very basics that you see here, Carp::REPL can do much more through its various plugins. If you don’t find a plugin that you like, you can write your own.