package Mojolicious::Plugins; use Mojo::Base 'Mojo::EventEmitter'; use Mojo::Util 'camelize'; has namespaces => sub { ['Mojolicious::Plugin'] }; # "Also you have a rectangular object in your colon. # That's a calculator. I ate it to gain its power." sub emit_hook { my $self = shift; $_->(@_) for @{$self->subscribers(shift)}; return $self; } sub emit_chain { my ($self, $name, @args) = @_; my $wrapper; for my $cb (reverse @{$self->subscribers($name)}) { my $next = $wrapper; $wrapper = sub { $cb->($next, @args) }; } $wrapper->(); return $self; } # "Everybody's a jerk. You, me, this jerk." sub emit_hook_reverse { my $self = shift; $_->(@_) for reverse @{$self->subscribers(shift)}; return $self; } sub load_plugin { my ($self, $name) = @_; # Try all namspaces my $class = $name =~ /^[a-z]/ ? camelize($name) : $name; for my $namespace (@{$self->namespaces}) { my $module = "${namespace}::$class"; return $module->new if $self->_load($module); } # Full module name return $name->new if $self->_load($name); # Not found die qq{Plugin "$name" missing, maybe you need to install it?\n}; } sub register_plugin { shift->load_plugin(shift)->register(shift, ref $_[0] ? $_[0] : {@_}); } # "Hey, I don't see you planning for your old age. # I got plans. I'm gonna turn my on/off switch to off." sub _load { my ($self, $module) = @_; # Load if (my $e = Mojo::Loader->new->load($module)) { ref $e ? die $e : return } # Module is a plugin return $module->isa('Mojolicious::Plugin') ? 1 : undef; } 1; =head1 NAME Mojolicious::Plugins - Plugin manager =head1 SYNOPSIS use Mojolicious::Plugins; my $plugins = Mojolicious::Plugin->new; $plugins->load_plugin('Config'); =head1 DESCRIPTION L is the plugin manager of L. =head1 ATTRIBUTES L implements the following attributes. =head2 C my $namespaces = $plugins->namespaces; $plugins = $plugins->namespaces(['Mojolicious::Plugin']); Namespaces to load plugins from, defaults to L. # Add another namespace to load plugins from push @{$plugins->namespaces}, 'MyApp::Plugin'; =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 C $plugins = $plugins->emit_chain('foo'); $plugins = $plugins->emit_chain(foo => 123); Emit events as chained hooks. =head2 C $plugins = $plugins->emit_hook('foo'); $plugins = $plugins->emit_hook(foo => 123); Emit events as hooks. =head2 C $plugins = $plugins->emit_hook_reverse('foo'); $plugins = $plugins->emit_hook_reverse(foo => 123); Emit events as hooks in reverse order. =head2 C my $plugin = $plugins->load_plugin('some_thing'); my $plugin = $plugins->load_plugin('SomeThing'); my $plugin = $plugins->load_plugin('MyApp::Plugin::SomeThing'); Load a plugin from the configured namespaces or by full module name. =head2 C $plugins->register_plugin('some_thing', $app); $plugins->register_plugin('some_thing', $app, foo => 23); $plugins->register_plugin('some_thing', $app, {foo => 23}); $plugins->register_plugin('SomeThing', $app); $plugins->register_plugin('SomeThing', $app, foo => 23); $plugins->register_plugin('SomeThing', $app, {foo => 23}); $plugins->register_plugin('MyApp::Plugin::SomeThing', $app); $plugins->register_plugin('MyApp::Plugin::SomeThing', $app, foo => 23); $plugins->register_plugin('MyApp::Plugin::SomeThing', $app, {foo => 23}); Load a plugin from the configured namespaces or by full module name and run C, optional arguments are passed through. =head1 SEE ALSO L, L, L. =cut