Wednesday 25. March, 2009
While grown-up languages like Java has mechanisms to let you throw Exception objects, and to catch them in different places and do interesting things with them, most Perl code just dies with a error message of some sort (If you’re lucky, it’s even helpful, and reporting the mistake you did inside your own code, rather than going belly up inside the module itself.
This is usually good enough for most people. Using a block eval, you can catch the error and deal with it, even doing a regular expression against it to handle different errors. Still, some people have been writing CPAN modules to add this functionality to the language. Unfortunately, up until now these attempts has mostly fallen into two categories; ‘cludgy addon’, and ’source filter powered’.
With some determination, and thanks to recent industrial power tools like Variable::Magic and B::Hooks::EndOfScope Ash Berlin has been able to put together a first class try / catch mechanism without using source filters. Check out the TryCatch synopsis from CPAN:
sub foo {
try {
die SomeClass->new(code=>404) if $notfound;
return "return value from foo";
}
catch (Some::Class $e where { $_->code > 100 } ) {
}
}
As you see, you can specify types of objects to handle, and this mechanism supports receiving Moose type constraints, including complex MooseX::Types constructs like ‘Dict[code => Int]'. It's also quite useful that you can return out of the function from inside a try block, unlike an eval, with just returns from the eval block.
If you want to try it yourself, just do $ cpan TryCatch and start playing. The docs are a bit sparse at the moment, but it's easy enough to figure out. Expect the docs to be improved quite soon.
I believe modules like this and MooseX::Declare represent a new trend in Perl 5, where CPAN authors extend the syntax of Perl itself using Perl. It'll be interesting to see what turns up in this space in the coming months. I found Ricardo's musings on the subject to be of particular interest.
Saturday 7. February, 2009
The Frozen Perl conference is going on in Minneapolis this weekend. For those of us who missed it, I think these slides by Shawn M. Moore are worth checking out. A good introduction to Moose, and the best Method Modifier examples I’ve seen.
Wednesday 4. February, 2009
Thanks to the Perl Foundation, who sponsored Dave Rolsky’s work to write a Moose manual. There is now no good excuse for not knowing what the Moose offers :) Check it out at search.cpan.org
Sunday 1. February, 2009
Joose, the javascript meta object system inspired by Moose recently released version 2.0 of their framework adding support for offical support for types/sub types as well as coercisons. There are also a bunch of other changes, read on at the original announcement. You can also check out the project homepage.
Friday 30. January, 2009
I recently needed to create a persistent daemon to do some maintenance tasks for iusethis. Turns out that building these with the postmodern object system Moose is really easy.
For those of you not in the know, Moose has the concept of ‘Roles’, stolen from the Perl 6 project. Roles work kind of like a mix-in that you can add to your class to make it super powerful :) (For the extra curious, you can read more details about Roles in Perl6 here).
In order to get my daemon running, I just created a Class like this:
package iusethis::Daemon;
use Moose;
with MooseX::Daemonize;
after 'start' => sub {
my $self=shift;
return unless $self->is_daemon();
while(1) { $self->do_menial_tasks(); sleep($until_lunch); }
1;
Some notes about the code above
- You can see how the role is added using the ‘with’ keyword.
- In Moose, the ‘after’ modifier means that our code will hook up to the ‘after’ method provided by a superclass or Role and run after that method.
- The return is because the code forks, to avoid it from running in both the child and the parent.
I also created a simple script to initialize it (scripts/daemon.pl in my case):
#!/usr/bin/perl -w
use strict;
use iusethis::Daemon;
my $daemon = iusethis::Daemon->new_with_options();
my ($command) = @{$daemon->extra_argv};
$daemon->$command if $daemon->can($command);
warn($daemon->status_message); exit($daemon->exit_code);
And just like that we have a fully operational persistant server process. You could stuff this thing into /etc/init.d/ if you like, and it will respond to all the expected things like start, stop, restart status. the Daemonize role also supports MooseX::GetOpt. It is enabled by running new_with_options like we did in the class above. This which means your deamon already responds to a common set of command line switches. Run it with -h to see this output:
usage: daemon.pl [-f] [long options...]
--pidbase
--progname
--stop_timeout
--basedir
--pidfile
-f --foreground
From the ‘pidbase’ argument, you might have guessed that your fledgling daemon stores the process id in a file just like all the grown up daemons do, in order to be able to check if it’s still alive. By default, it will store this file in /var/run/, and pidbase is useful for specifying a different path, for instance if you need to run your daemon on a system where you don’t have root privileges. the -f flag is also useful for debugging your daemon, as it will keep the process running in the foreground, rather than detaching it.
Running in the foreground is nice when you are writing your daemon, but once you have it running, it’s nice to have some log output to see what it’s been up to lately. I decide to use MooseX::LogDispatch, which is a Moose role which makes it trivial to integrate Log::Dispatch into your daemon. This is what I added to my class to get it running:
with qw/MooseX::LogDispatch::Levels/;
has log_dispatch_conf => (
is => 'ro',
isa => 'HashRef',
lazy => 1,
required => 1,
default => sub {
my $self = shift;
{
class => 'Log::Dispatch::File',
min_level => 'debug',
mode => 'append',
filename => "/var/log/daemon.log",
format => '[%d] [%p] %m%n',
}
},
);
For a more trivial case, you could have just passed in the file name to log to, but I wanted to tweak the log format. (You can read more about the format here). This style also allows you to easily adjust the verbosity of your logging. Since this default is lazily evaluated, you could create separate setters for parts of the format and override them on the command line, thanks to MooseX::GetOpt. Once this is set up, all you need to do is use the appropriate level like this
$self->info('Arne sucks at squash');
and an appropriate message is created in your log file:
[Thu Jan 29 23:50:09 2009] [info] Arne sucks at squash.
And that’s all you need. I hope this article was useful in showing how you can create your own hellspawn. Enjoy, and use responsibly. :)