diff options
Diffstat (limited to 'posts/2009-11-09-modules-i-like-devel-declare.org')
| -rw-r--r-- | posts/2009-11-09-modules-i-like-devel-declare.org | 265 |
1 files changed, 0 insertions, 265 deletions
diff --git a/posts/2009-11-09-modules-i-like-devel-declare.org b/posts/2009-11-09-modules-i-like-devel-declare.org deleted file mode 100644 index facdc81..0000000 --- a/posts/2009-11-09-modules-i-like-devel-declare.org +++ /dev/null @@ -1,265 +0,0 @@ -For [[http://linkfluence.net/][$work]], I've been working on a job queue -system, using Moose, Catalyst (for a REST API) and DBIx::Class to store -the jobs and some meta (yeah I know, there is not enough job queue -system already, the world really needs a new one ...). - -Basicaly, I've got a XXX::Worker class that all the workers extends. -This class provide methods for fetching job, add a new job, mark a job -as fail, retry, ... - -The main loop in the XXX::Worker class look like this: - -#+BEGIN_SRC perl - # $context is a hashref with some info the job or method may need - while (1) { - my @jobs = $self->fetch_jobs(); - foreach my $job (@jobs) { - my $method = $job->{funcname}; - $self->$method($context, $job); - } - $self->wait; - } -#+END_SRC - -and the worker look like this - -#+BEGIN_SRC perl - package MyWorker; - use Moose; - extends 'XXX::Worker'; - - sub foo { - my ($self, $context, $job) = @_; - - # do something - $self->job_success(); - } -#+END_SRC - -But as I'm using Moose, I want to add more sugar to the syntax, so -writing a new worker would be really more easy. - -Here comes -[[http://search.cpan.org/perldoc?Devel::Declare][Devel::Declare]]. - -The syntax I want for my worker is this one: - -#+BEGIN_SRC perl - work foo { - $self->logger->info("start to work on job"); - # do something with $job - }; - - work bar { - # do something with $job - }; - - success foo { - $self->logger->info("woot job success"); - }; - - fail bar { - $self->logger->info("ho noez this one failed"); - }; -#+END_SRC - -Where with =work= I write the code the writer will execute on a task, -=success=, a specific code that will be executed after a job is marked -as successfull, and =fail= for when the job fail. - -I will show how to add the =work= keyword. I start by writing a new -package: - -#+BEGIN_SRC perl - package XXX::Meta; - - use Moose; - use Moose::Exporter; - use Moose::Util::MetaRole; - - use Devel::Declare; - - use XXX::Meta::Class; - use XXX::Keyword::Work; - - Moose::Exporter->setup_import_methods(); - - sub init_meta { - my ($me, %options) = @_; - - my $for = $options{for_class}; - - XXX::Keyword::Work->install_methodhandler(into => $for,); - - Moose::Util::MetaRole::apply_metaclass_roles( - for_class => $for, - metaclass_roles => ['XXX::Meta::Class'], - ); - - } - - 1; -#+END_SRC - -The =init_meta= method is provided by Moose: (from the POD) - -#+BEGIN_QUOTE - The =init_meta= method sets up the metaclass object for the class - specified by =for_class=. This method injects a a meta accessor into - the class so you can get at this object. It also sets the class's - superclass to base\_class, with Moose::Object as the default. -#+END_QUOTE - -So I inject into the class that will use XXX::Meta a new metaclass, -XXX::Meta::Class. - -Let's take a look to XXX::Meta::Class: - -#+BEGIN_SRC perl - package XXX::Meta::Class; - - use Moose::Role; - use Moose::Meta::Class; - use MooseX::Types::Moose qw(Str ArrayRef ClassName Object); - - has work_metaclass => ( - is => 'ro', - isa => Object, - builder => '_build_metaclass', - lazy => 1, - ); - - has 'local_work' => ( - traits => ['Array'], - is => 'ro', - isa => ArrayRef [Str], - required => 1, - default => sub { [] }, - auto_deref => 1, - handles => {'_add_work' => 'push',} - ); - - sub _build_metaclass { - my $self = shift; - return Moose::Meta::Class->create_anon_class( - superclasses => [$self->method_metaclass], - cache => 1, - ); - } - - sub add_local_method { - my ($self, $method, $name, $code) = @_; - - my $method_name = $method . "_" . $name; - my $body = $self->work_metaclass->name->wrap( - $code, - original_body => $code, - name => $method_name, - package_name => $self->name, - ); - - my $method_add = "_add_" . $method; - $self->add_method($method_name, $body); - $self->$method_add($method_name); - } - - 1; -#+END_SRC - -Here I add to the =->meta= provided by Moose =local_work=, which is an -array that contains all my =work= methods. So each time I do something -like - -#+BEGIN_SRC perl - work foo {}; - - work bar {}; -#+END_SRC - -in my worker, I add this method to *->meta->local\_work*. - -And the class for our keyword work: - -#+BEGIN_SRC perl - package XXX::Keyword::Work; - - use strict; - use warnings; - - use Devel::Declare (); - use Sub::Name; - - use base 'Devel::Declare::Context::Simple'; - - sub install_methodhandler { - my $class = shift; - my %args = @_; - { - no strict 'refs'; - *{$args{into} . '::work'} = sub (&) { }; - } - - my $ctx = $class->new(%args); - Devel::Declare->setup_for( - $args{into}, - { work => { - const => sub { $ctx->parser(@_) } - }, - } - ); - } - - sub parser { - my $self = shift; - $self->init(@_); - - $self->skip_declarator; - my $name = $self->strip_name; - $self->strip_proto; - $self->strip_attrs; - - my $inject = $self->scope_injector_call(); - $self->inject_if_block( - $inject . " my (\$self, \$content, \$job) = \@_; "); - - my $pack = Devel::Declare::get_curstash_name; - Devel::Declare::shadow_sub( - "${pack}::work", - sub (&) { - my $work_method = shift; - $pack->meta->add_local_method('work', $name, $work_method); - } - ); - return; - } - - 1; -#+END_SRC - -The =install_methodhandler= add the =work= keyword, with a block of -code. This code is sent to the parser, that will add more sugar. With -the inject\_if\_block, I inject the following line - -#+BEGIN_SRC perl - my ($self, $context, $job) = @_; -#+END_SRC - -as this will always be my 3 arguments for a work method. - -Now, for each new worker, I write something like this: - -#+BEGIN_SRC perl - package MyWorker; - use Moose; - extends 'XXX::Worker'; - use XXX::Meta; - - work foo {}; -#+END_SRC - -The next step is too find the best way to reduce the first four lines to -two. - -(some of this code is ripped from other modules that use Devel::Declare. -The best way to learn what you can do with this module is to read code -from other modules that use it) |
