My last post discussed figuring out how part of Catalyst worked. I had to put debug code in to a library and watch it run. How do you do tht?
It’s actually pretty easy, but it wasn’t obvious, at least to me. It is on the debugging page of the Catalyst tutorial, but I missed it the first dozen times I read the page.
As a note, if you haven’t gone all the way through the tutorial yet, it really is the best place to start. It tries to touch most of Catalyst and gets a lot of things right. It is extremely dense, and you’ll have to go over it a lot before you see everything on the pages. Or at least I did. For instance, I just noticed the Task::Catalyst::Tutorial module, which will install the tutorial and all the dependencies in one go.
Back to debugging Catalyst.
Catalyst is written as a large collection of modules. Even your Catalyst app is actually a module that is used by the server application.
The server application is the myapp_server.pl or one of the other scripts in the scripts directory. These are provided by the catalyst.pl. None of my programs have needed to change them at all.
Your code, like the rest of Catalyst, is libraries.
The server program sticks “lib” in @INC so all the modules you have written as part of your application are read. It puts that early in @INC so that your programs are loaded before other library paths.
You can use this to debug the Catalyst libraries as well.
Find the library module you want to edit. My most recent example was ConfigLoader. The full name of that module is Catalyst::Plugin::ConfigLoader. It should be in Catalyst/Plugin/ConfigLoader.pm, either in your local library path (such as ~/perl) or in the system library path (something awful like /usr/lib/perl5/site_perl/<version number>/), depending on where you installed it.
In your Catalyst application’s lib directory, create that same hierarchy, and copy .pm file there. Instead of finding the one in the system path, it’ll find the one in myapp/lib/Catalyst/… first.
The example above was copied from /usr/lib/perl5/site_perl/5.8.8/Catalyst/Plugin/ConfigLoader.pm to ~/projects/MyApp/lib/Catalyst/Plugin/ConfigLoader.pm. Then I scribbled a bunch of “print STDERR” statements in my copy so I could see what it was doing.
In my last post, I mentioned how the Catalyst documentation uses MyApp as the sample name for your application. My note up there is actually literally correct, because I created a new, empty Catalyst app to test with. I called it MyApp. I erased it when I was done. It’s a handy technique to simplify testing.
To recap, you can copy any part of Catlyst from the place it is installed to myapp/lib, maintaining the directory structure, and the one in the application will be loaded before the one in the library paths. You can then use and edit that file as much as you like, without messing with the installed copy.
This is a great technique and one I use all the time – one note though, “print STDERR” isn’t nearly as fun as ‘warn’, and potentially Carp’s louder versions with stack traces will be even easier.
The other thing to remember is that Catalyst plugins are mixed in to the application class itself, so your $self within a plugin is actually the per-request $c.
I’d love to see a write up of these techniques on the wiki if you’re feeling wonderful and generous … :)
Of course I then managed to forget the other really useful trick – either use CatalystX::REPL to break on exceptions or (my usual approach, which I often use to debug DBIC schemas and similar) –
require Devel::REPL;
$Devel::REPL::DefaultScratchPad::ctx = $self;
Devel::REPL->new->run;
and presto, you get a repl prompt with a $ctx in scope that you can poke at.