A role based plugin system with MooseX::Declare

Wed Sep 23 17:40:00 2009

Digg! submit to reddit Delicious RSS Feed Readers

I've been writing some code recently with multiple modes of operation - which means that while the core logic is basically the same, there's a lot of extra code for any given run. I considered just doing the standard "one class/role and a bunch of subclasses/consumers" approach but realised what I really wanted was something more like MooseX::Traits - but didn't like the way it handles trait names and really hate doing new_with_traits since I like to be able to pass around class names and constructor arguments separately. So after a bit of thought I came up with:

  {
    my %class_cache;

    method with_plugins (ClassName $class: @names) {
      ($class_cache{join(' ', @names)} ||= do { class {
         extends $class;
         with map "${class}::With$_", @names;
      } })->name;
    }
  }

The way I call this is to write:

  $class->with_plugins(@plugins)->new(\%args);

Which creates an anonymous subclass ( class { ) which inherits from the main class ( extends $class; ) and then for each plugin name like 'FrotzingCapability' applies the role 'My::Class::WithFrotzingCapability' ( with map "${class}::With$_", @names; ), caches the metaclass object under the plugin names ( $class_cache{join(' ', @names)} ||= ) and then returns the class name ( ->name ) so we can call ->new on it.

Not sure if this is worth a CPAN module, but I'll probably separate it out into a role in the codebase it lives in and see how it goes - but it's nice to be able to write such little code and get a rich composition system - and thanks to MooseX::Declare I'm able to use the same extended perl syntax used to declare the surrounding class rather than needing to use the MOP directly.

This is beautiful, and it makes me happy.

-- mst, out