How to use the debugger with Moose

While I know I'm in the minority, I use the Perl debugger quite a bit. In fact, I've hacked on perl5db.pl more than I can to admit and it's a mess. However, on a day-to-day basis, I use it constantly and have it bound to ,d in my vim setup. Unfortunately, I also write a lot of Moose code and that's when I invariably hit things like this:

Class::MOP::Method::Wrapped::CODE(0x62b0250)(/usr/local/lib/perl/5.10.1/Class/MOP/Method/Wrapped.pm:91):
91:             sub { $modifier_table->{cache}->(@_) },
auto(-1)  DB<2> v
88          };
89:         $_build_wrapped_method->($modifier_table);
90          return $class->SUPER::wrap(
91==>           sub { $modifier_table->{cache}->(@_) },
92              # get these from the original
93              # unless explicitly overridden
94:             package_name   => $params{package_name} || $code->package_name,
95              name           => $params{name}         || $code->name,
96              original_method => $code,
97

That's not code I've written; that's code that you get when you use Moose and it makes debugging much harder than it needs to be.

Today I decided to do something about that, but I was very pleased to see that Christian Walde already did it for me. Now debugging Moose is a breeze.

The first thing you do is install DB::Skip. This module uses a minimally invasive monkey-patch to the debugger to allow you to ignore packages or subroutines in the debugger. For some reason I couldn't install it directly with the cpan or cpanm clients, so I downloaded and tried to build it manually, but it hung on t/basic.t. I popped it open in vim, hit ,t (my binding for running the current test in verbose mode) and it passed just fine. Weird, but I didn't look into it further. I simply installed it and the altered my $HOME/.perldb file.

If you're not familiar with $HOME/.perldb, this file is documented in perldoc perldebug and let's you run code before the debugger and do all sorts of interesting customizations. For example, you could bind a key in your editor to insert $DB::single = 1; before the current line, set the DEBUGGING environment variable and then have this in your $HOME/.perldb file:

sub afterinit {
    push @DB::typeahead, "c" if $ENV{DEBUGGING};
}

That would cause your debugger to automatically continue until the first break point (in other words, run until it hits the $DB::single your editor just inserted).

Previously, my rc file looked like this:

sub DB::afterinit {
    no warnings 'once';

    # give me a window of lines instead of a single line
    push @DB::typeahead => "{{v"
      unless $DB::already_curly_curly_v++;
}

Now it looks like this:

my $skip;
BEGIN { $skip = '^(?:Moose|Eval::Closure|Class::MOP)' }
print STDERR <<"END";

Debugger skipping: /$skip/

See ~/.perldb if you don't like this behavior.

END

use DB::Skip pkgs => [ qr/$skip/ ];

sub DB::afterinit {
    no warnings 'once';

    # give me a window of lines instead of a single line
    push @DB::typeahead => "{{v"
      unless $DB::already_curly_curly_v++;
}

That DB::Skip setup automatically skips any packages in the following namespaces:

  • Eval::Sandbox
  • Moose
  • Class::MOP

Now when I try to debug my Moose classes, the debugger just shows me code that I wrote, not any of the Moose internals. While I'm sure I may find some other packages I'll want to add to my setup, this has tremendously sped up my code debugging. Thanks Mithaldu!

If you'd like to learn more about using the debugger, though it's brief, I do give an introduction to it in my book, Beginning Perl.

9 Comments

Thanks for sharing this tip.

I just finished refactoring a code-base away from MooseX::Method::Signatures, mostly to see if I can improve the performance, but partly because of my distaste for how the debugger interacts with Moose. And now this article comes out! :)

I'm really happy to see someone find a good use for the module! Also, thanks for the reminder. The hang on test has been around for a while and i never was sufficiently motivated to fix it, but tonight i sat down and fixed it with minimal effort. The problem was that i had included a testing module called Devel::Caller, which is a name already used on CPAN, which i was not aware of. Due to this clash it tested fine on my system, and didn't on others.

With the new release everyone should be able to install it normally. :)

Thanks for sharing this! I'm using lots of MooseX::Declare, so my debugging is even worse than with Moose alone

I'd also love that you share more vimrc to know what things can make you more productive in Perl

Thanks for this Ovid, very handy. I have also added the Attribute::Handlers to the packages to skip, as this all seems to be looked at first with my perl scripts.

My life is 473% better now, thanks Ovid!

Can you post the vim bindings you used for ",d"? I've been on a vim tear lately and want to see how you're doing it.

Awesome.

Would the same thing be possible for STDERR output?

When I encounter a bug while using Moose objects, it's sometimes a pain to find the one line that tells me where the problem comes from in my code. Any solution?

About Ovid

user-pic Freelance Perl/Testing/Agile consultant and trainer. See http://www.allaroundtheworld.fr/ for our services. If you have a problem with Perl, we will solve it for you. And don't forget to buy my book! http://www.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840/