DBG
view release on metacpan or search on metacpan
my $data = shift;
return unless defined $data;
if ( $HEADER && !$stamped ) {
my @msg = (
'>> DEBUGGING SESSION START: ',
DateTime->now, ' ; PID: ', $$, ' <<', "\n\n"
);
print $fh @msg if $fh;
print STDERR @msg;
$stamped = 1;
}
$data =~ s/\s++$//;
$data .= "\n";
print $fh $data if $fh;
print STDERR $data;
}
BEGIN {
if ( length $fn ) {
$fh = FileHandle->new(">> $fn") or die $!;
binmode $fh, ':utf8';
binmode *STDERR, ':utf8';
$fh->autoflush(1);
}
}
END {
if ( $HEADER && $stamped ) {
my $msg = join '', "\n", '** DEBUGGING SESSION END: ', DateTime->now,
' ; PID: ', $$, ' **';
_tee($msg);
}
$fh->close if $fh;
}
{ # DateTime with optional label payload
package DBG::ts;
$DBG::ts::VERSION = '0.004';
use parent 'DateTime';
use Scalar::Util qw(refaddr);
our %messages;
sub text {
my ( $self, $text ) = @_;
my $addr = refaddr $self;
my $old = $messages{$addr};
$messages{$addr} = $text if defined $text;
return $old;
}
sub DESTROY {
my $self = shift;
delete $messages{ refaddr $self };
$self->SUPER::DESTROY if $self->can("SUPER::DESTROY");
}
}
sub ts(;$) {
my $ts = DBG::ts->now;
$ts->text(shift);
return $ts;
}
sub rt($$) {
return unless $ON;
for (@_) {
die 'DBG::ts expected'
unless blessed($_) && $_->isa('DBG::ts');
}
my ( $t1, $t2 ) = @_;
my $i = natatime 2, ( $t2 - $t1 )->deltas;
my $reported;
my $text = $t1->text;
my $prefix = '';
if ( defined $text ) {
_tee("timestamp $text");
$prefix = "\t";
}
while ( my ( $unit, $amt ) = $i->() ) {
next unless $amt;
$reported = 1;
$unit =~ s/s$// if $amt == 1;
_tee("$prefix$amt $unit");
}
_tee("${prefix}negligible time elapsed") unless $reported;
return $t2;
}
sub trc() {
return unless $ON;
_tee 'TRACE';
my $i = 0;
my @stack;
while ( my @frame = caller($i) ) {
push @stack, [ $i++, $frame[3], $frame[1], $frame[2] ];
}
my $fmt = '%' . length( $stack[-1][0] ) . 'd) %s (%s:%d)';
for $i ( 1 .. $#stack ) {
_tee sprintf $fmt, ( @{ $stack[$i] } )[ 0 .. 1 ],
( @{ $stack[ $i - 1 ] } )[ 2 .. 3 ];
}
_tee 'END TRACE';
}
sub dmp($) {
return unless $ON;
my $ref = shift;
local $Data::Dumper::Indent = 1;
local $Data::Dumper::Sortkeys = 1;
local $Data::Dumper::Quotekeys = 0;
local $Data::Dumper::Terse = 1;
my $code = Dumper $ref;
_dmp($code);
}
sub _dmp {
my $code = shift;
my ( $ds, $stderr_string );
local @ARGV; # prevents Perl::Tidy craziness
my $error = Perl::Tidy::perltidy(
source => \$code,
destination => \$ds,
_cycles( $_, $hash, $indent + 1, $addr ) for @$ref;
}
}
}
sub prp($$) {
my ( $msg, $var ) = @_;
$msg =~ s/\??\s*$/? /;
_tee( $msg . ( $var ? 'yes' : 'no' ) );
}
sub cnm($;$) {
my ( $code, $quiet ) = @_;
return unless ref $code;
my $gv = _code_name($code);
my $name = '';
if ( my $st = $gv->STASH ) {
$name = $st->NAME . '::';
}
my $n = $gv->NAME;
if ($n) {
$name .= $n;
if ( $n eq '__ANON__' ) {
$name .= ' defined at ' . $gv->FILE . ':' . $gv->LINE;
}
}
_tee($name) unless $quiet;
return $name;
}
sub _code_name {
my $code = shift;
return unless my $cv = svref_2object($code);
return
unless $cv->isa('B::CV')
and my $gv = $cv->GV;
return $gv;
}
sub pkg($$;$) {
my ( $obj, $method, $file ) = @_;
return _tee('first parameter must be an object') unless blessed $obj;
return _tee('method not defined') unless defined $method;
my $m = $obj->can($method);
return _tee( "did not find method $method in " . ref $obj ) unless $m;
my $gv = _code_name($m);
return _tee("could not find $method") unless $gv;
if ( !$file ) {
_tee( sprintf 'package: %s; file: %s; line: %s',
$gv->STASH->NAME, $gv->FILE, $gv->LINE );
}
else {
_tee( $gv->STASH->NAME );
}
}
sub sz($;$) {
state $ts = eval { require Devel::Size };
if ($ts) {
my $msg = Devel::Size::total_size( pop @_ );
$msg = pop(@_) . ' ' . $msg if @_;
_tee($msg);
}
else {
_tee('sz requires Devel::Size');
}
}
sub mtd($;$) {
my ( $obj, $verbose ) = @_;
if ( my $class = ref $obj ) {
my $meta = Class::MOP::Class->initialize($class);
_tee("Class: $class");
if ($verbose) {
my $longest = 0;
for ( $meta->get_all_methods ) {
my $l = length $_->name;
$longest = $l if $l > $longest;
}
my $format = '%-' . $longest . 's : %s %s';
for my $method ( sort { $a->name cmp $b->name }
$meta->get_all_methods )
{
my $code = $obj->can( $method->name );
my $gv = _code_name($code);
if ( $gv->LINE ) {
_tee( sprintf $format, $method->name, $gv->FILE,
$gv->LINE );
}
else {
_tee( $method->fully_qualified_name );
}
}
}
else {
dmp(
[
sort map { $_->fully_qualified_name }
$meta->get_all_methods
]
);
}
}
else {
_tee "NOT AN OBJECT: $obj";
}
}
sub inh($) {
my $class = shift;
_tee('inh needs a class') && return unless length( $class // '' );
$class = ref($class) || $class;
my $hash = { $class => 1 };
_fetch_classes( $class, $hash );
my @classes = sort keys %$hash;
( run in 3.163 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )