4

私はMooseの初心者です。複数のプラグインをロードするオブジェクトを作成する必要があります。構造は次のようになります。

  • 主なオブジェクト -> いくつかの一般的な機能
  • プラグイン -> メイン オブジェクトの拡張機能

プラグインは、サーバー上の別のフォルダーにあります。メイン オブジェクトは、プラグインをロードして初期化し、オブジェクトをそれ自体に保存する必要があります。各プラグインの戻り値は、メイン オブジェクトを通過する必要があります。メイン オブジェクトは、呼び出し元の JSON 構造のすべての戻り値を変換する必要があるためです。

私は次のように呼びます:

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

これが私のコード例です:

メイン オブジェクト:

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;

ディレクトリ "/usr/local/apache/sites/.../Plugins" 内のプラグイン MainExtention:

package MainExtention;
use Moose;

has 'title' => (
    is          => 'rw',
    isa         => 'Str',
    default     => 'Default',
);

sub get_title {
    return 'MainExtention Title';
}

1;

これは次のように機能します。

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

しかし、これは私が持っているものではありません:)プラグインから直接ではなく、メインオブジェクトからプラグインの戻り値を取得します。誰にもアイデアはありますか?2 番目の質問: プラグインをロードする簡単な方法はありますか? どのように?

4

1 に答える 1

1

プラグインをロードするには、 Module::Pluggableを使用することをお勧めします。これは、ディレクトリから一連のパッケージをロードし、必要に応じてそれらをインスタンス化する (またはインスタンス化しない) ことができます。

メイン オブジェクトでプラグインをラップする必要がある場合は、必要なことを行うためにメイン オブジェクトでメソッドを定義するだけです。

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;
}

次に、コード:

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

Moose を使用している場合は、すべてのプラグインにroleを実装することをお勧めします。これにより、プラグインが適切に実装されているかどうかを確認できます。

于 2012-08-15T17:33:53.747 に答える