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 >
