Thanks, guys

You've really helped clarify my approach

2010/4/11 Robin Smidsrød <[email protected]>

> On 08.04.2010 11:46, Dan Horne wrote:
> > I have a question regarding the best method for implementing application
> > plugins - i.e. if there is an idiomatic way to do this in Moose. Here's a
> > high level description of what I'm trying to achieve:
>
>
>
> >
> >    1. When the application starts, it finds all modules in a "plugins"
> >    directory.
>
> Create a package called MyRegistry with a load_registry() class method
> that loads all the classes enumerated by Module::Pluggable.
>
> # Create function that list type handler classes
> use Module::Pluggable
>    sub_name    => 'type_handlers',
>    search_path => [ 'MyApp::Plugins' ],
>    only        => qr!^MyApp::Plugins::\w+$!,
>    except      => 'MyApp::Plugins::Plugin',  # Abstract base class for
> plugins, if needed (or the interface role module)
> ;
>
> # Load information from all handlers
> sub load_registry {
>    use Class::MOP ();
>    Class::MOP::load_class($_) for type_handlers();
> }
>
> >    2. We loop through each module in turn:
> >       1. We call a register method, which registers the plugin (this
> method
> >       returns the plugin name). This becomes the key in the "plugins"
> hash
>
> use Sub::Exporter -setup => {
>    exports => [qw( register_type )],
>    groups  => {
>        default => [qw( register_type )],
>    },
> };
>
> sub register_type {
>    my ($str) = @_;
>    confess("Not a valid value") unless defined $str and length $str > 0;
>    __PACKAGE__->type_registry->{$str} = scalar caller();
> }
>
> use MooseX::ClassAttribute;
> class_has 'type_registry' => (
>    is      => 'ro',
>    isa     => 'HashRef[Str]',
>    default => sub { +{} },
> );
>
> >       2. We then call a the plugin "functionality" method (I don't have a
> >       good name off the top of my head), which returns an anonymous
> > sub containing
> >       the plugin functionality, (or perhaps a callback method name)
>
> This is your factory method...
>
> sub new_from_type {
>    my ($class, $type, @params) = @_;
>    confess("new_from_object() is a class method") unless
> defined($class) and not ref($class);
>
>    # Load registry unless already loaded.
>    my $registry = 'MyApp::PluginRegistry';
>    Class::MOP::load_class($registry);
>    $registry->load_registry();  # Runtime init registry
>
>    # Resolve handler class
>    my $handler_class = $registry->type_registry->{ $type };
>    unless ( $handler_class ) {
>        confess(
>            "Could not resolve handler class for type '"
>          . $type
>          . "'"
>        );
>    }
>
>    # Instantiate and return handler
>    return $handler_class->new( @params );
> }
>
> >    3. Now, whenever the plugin is called by name, the supplied
> >    "functionality"method is invoked
>
> I guess you can extend the register_type() method to also apply a role
> to the caller() class that possibly includes some requires() calls or
> explicitly check if the caller() does the required role (or extends the
> base class, depending on your point of view).
>
> -- Robin
>

Reply via email to