package Mojolicious::Plugins; use Mojo::Base -base; use Mojo::Util 'camelize'; has hooks => sub { {} }; has namespaces => sub { ['Mojolicious::Plugin'] }; # "Who would have thought Hell would really exist? # And that it would be in New Jersey?" sub add_hook { my ($self, $name, $cb) = @_; return $self unless $name && $cb; $self->hooks->{$name} ||= []; push @{$self->hooks->{$name}}, $cb; return $self; } # "Also you have a rectangular object in your colon. # That's a calculator. I ate it to gain its power." sub load_plugin { my ($self, $name) = @_; # Module if ($name =~ /^[A-Z]+/) { return $name->new if $self->_load($name) } # Search plugin by name else { # Class my $class = $name; camelize $class; # Try all namspaces for my $namespace (@{$self->namespaces}) { my $module = "${namespace}::$class"; return $module->new if $self->_load($module); } } # Not found die qq/Plugin "$name" missing, maybe you need to install it?\n/; } # "Let's see how crazy I am now, Nixon. The correct answer is very." sub register_plugin { my $self = shift; my $name = shift; my $app = shift; $self->load_plugin($name)->register($app, ref $_[0] ? $_[0] : {@_}); } sub run_hook { my $self = shift; return $self unless my $name = shift; return $self unless my $hooks = $self->hooks->{$name}; for my $hook (@$hooks) { $hook->(@_) } return $self; } # "Everybody's a jerk. You, me, this jerk." sub run_hook_reverse { my $self = shift; return $self unless my $name = shift; return $self unless my $hooks = $self->hooks->{$name}; for my $hook (reverse @$hooks) { $hook->(@_) } return $self; } sub _load { my ($self, $module) = @_; # Load if (my $e = Mojo::Loader->load($module)) { die $e if ref $e; return; } # Module is a plugin return unless $module->can('new') && $module->can('register'); return 1; } 1; __END__ =head1 NAME Mojolicious::Plugins - Plugins =head1 SYNOPSIS use Mojolicious::Plugins; =head1 DESCRIPTION L<Mojolicious::Plugins> is the plugin manager of L<Mojolicious>. In your application you will usually use it to load plugins. To implement your own plugins see L<Mojolicious::Plugin> and the C<add_hook> method below. =head1 ATTRIBUTES L<Mojolicious::Plugins> implements the following attributes. =head2 C<hooks> my $hooks = $plugins->hooks; $plugins = $plugins->hooks({foo => [sub {...}]}); Hash reference containing all hooks that have been registered by loaded plugins. =head2 C<namespaces> my $namespaces = $plugins->namespaces; $plugins = $plugins->namespaces(['Mojolicious::Plugin']); Namespaces to load plugins from. You can add more namespaces to load application specific plugins. =head1 METHODS L<Mojolicious::Plugins> inherits all methods from L<Mojo::Base> and implements the following new ones. =head2 C<add_hook> $plugins = $plugins->add_hook(event => sub {...}); Hook into an event. You can also add custom events by calling C<run_hook> and C<run_hook_reverse> from your application. =head2 C<load_plugin> my $plugin = $plugins->load_plugin('something'); my $plugin = $plugins->load_plugin('Foo::Bar'); Load a plugin from the configured namespaces or by full module name. =head2 C<register_plugin> $plugins->register_plugin('something', $app); $plugins->register_plugin('something', $app, foo => 23); $plugins->register_plugin('something', $app, {foo => 23}); $plugins->register_plugin('Foo::Bar', $app); $plugins->register_plugin('Foo::Bar', $app, foo => 23); $plugins->register_plugin('Foo::Bar', $app, {foo => 23}); Load a plugin from the configured namespaces or by full module name and run C<register>. Optional arguments are passed to register. =head2 C<run_hook> $plugins = $plugins->run_hook('foo'); $plugins = $plugins->run_hook(foo => 123); Runs a hook. =head2 C<run_hook_reverse> $plugins = $plugins->run_hook_reverse('foo'); $plugins = $plugins->run_hook_reverse(foo => 123); Runs a hook in reverse order. =head1 SEE ALSO L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. =cut