How to use Perl Moose with plugins for the main object?

I am new to Muse. I have to create an object that should load several plugins. The structure looks like this:

  • Main object -> some common functions
  • Plugins → extensions for the main object

Plugins are located in a separate folder on the server. The main object is to load plugins, initialize them and store the object by itself. Each plugin return value must go through the main object. Because the main object must convert every return value in the JSON structure for the caller.

I would call something like this:

my $main_obj = Main->new(); $main_obj->plugin('MainExtention')->get_title(); 

Here is my sample code:

The main object:

 package Main; use Moose; has 'plugins' => ( is => 'rw', ); has 'title' => ( is => 'rw', isa => 'Str', reader => '_get_title', ); # load plugins sub _load_modules { my $self = shift; my $path = "/usr/local/apache/sites/.../Plugins"; push(@INC, $path); my @modules = _find_modules_to_load($path); eval { my $plugins = {}; foreach my $module ( sort @modules) { (my $file = $module) =~ s|::|/|g; (my $modname = $module) =~ s/.*?(\w+$)/$1/; require $file . '.pm'; my $obj = $module->new(); $plugins->{$modname} = $obj; 1; } $self->plugins($plugins); } or do { my $error = $@ ; warn "Error loading modules: $error" if $error; }; } # read plugins sub _find_modules_to_load { my ($dir) = @_; my @files = glob("$dir/*.pm"); my $namespace = $dir; $namespace =~ s/\//::/g; # Get the leaf name and add the System::Module namespace to it my @modules = map { s/.*\/(.*).pm//g; "${namespace}::$1"; } @files; return @modules; } sub BUILD { my $self = shift; $self->_load_modules(); } sub get_title { return 'main title' } 1; __PACKAGE__->meta->make_immutable; 

MainExtention plugin in the directory "/usr/local/apache/sites/.../Plugins":

 package MainExtention; use Moose; has 'title' => ( is => 'rw', isa => 'Str', default => 'Default', ); sub get_title { return 'MainExtention Title'; } 1; 

This works as follows:

 my $main = Main->new(); my $plugins = $main->plugins(); print $plugins->{'MainExtention'}->get_title(); 

But this is not what I will have :) I will get the plugin return directly from the plugin, but from the main object. Does anyone have an idea? Second question: is there an easier way to download plugins? How?

+4
source share
1 answer

To load plugins, I would recommend using Module :: Pluggable , which can load a bunch of packages from a directory and instantiate (or not) as needed.

If you need the main object to wrap the plugin, just define a method on the main object to do everything you need:

 package Main; use Moose; # Adds a plugins() method to Main that returns a list of all loaded plugin packages use Module::Pluggable search_dirs => [ "/usr/local/apache/sites/.../Plugins" ]; # Used to store the plugins after ->new is called on each package has loaded_plugins => ( is => 'rw', isa => 'HashRef[Object]', lazy_build => 1, traits => [ 'Hash' ], handles => { _plugin => 'get' }, ); # Constructor for loaded_plugins, implied by lazy_build => 1 sub _build_loaded_plugins { my ($self) = @_; my %loaded_plugins; for my $plugin ($self->plugins) { $loaded_plugins{$plugin} = $plugin->new; } return \%loaded_plugins; } # Method for getting the processed title from any plugin sub get_plugin_title { my ($self, $name) = @_; my $plugin = $self->_plugin($name); my $title = $plugin->get_title; # process the title according to whatever Main needs to do... ... return $title; } 

Then your code:

 my $main = Main->new(); print $main->get_plugin_title('MainExtension'); 

If you use Moose, I can also offer to make all your role plugins, which will help you find out if the plugin has been implemented correctly.

+1
source

All Articles