Hack #55. Show Source Code on Errors
Don't guess which line is the problemâsee it!
Debugging errors and warning messages isn't often fun. Instead, it can be tedious. Often even finding the problem takes too long.
Perl can reveal the line number of warnings and errors (with warn
and die
and the warnings
pragma in effect); why can't it show the source code of the affected line?
The Hack
The code to do this is pretty easy, if unsubtle:
package SourceCarp; use strict; use warnings; sub import { my ($class, %args) = @_; $SIG{__DIE__} = sub { report( shift, 2 ); exit } if $args{fatal}; $SIG{__WARN__} = \\&report if $args{warnings}; } sub report { my ($message, $level) = @_; $level ||= 1; my ($filename, $line) = ( caller( $level - 1 ) )[1, 2]; warn $message, show_source( $filename, $line ); } sub show_source { my ($filename, $line) = @_; return '' unless open( my $fh, $filename ); my $start = $line - 2; my $end = $line + 2; local $.; my @text; while (<$fh>) { next unless $. >= $start; last if $. > $end; my $highlight = $. =â= $line ? '*' : ' '; push @text, sprintf( "%s%04d: %s", $highlight, $., $_ ); } return join( '', @text, "\\n" ); } 1;
The magic here is in three places. report(â)
looks at the call stack leading to its current position, extracting the name of the file and the line number of the calling code. It's possible to call this function directly with a message to display (and an optional level of calls to ignore).
show_source(â)
simply reads the named file and returns ...
Get Perl Hacks now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.