| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Catalyst::Plugin::PluginLoader; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 2609471 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 41 |  | 
| 4 | 1 |  |  | 1 |  | 8 | use warnings; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 37 |  | 
| 5 | 1 |  |  | 1 |  | 7 | use MRO::Compat (); | 
|  | 1 |  |  |  |  | 5 |  | 
|  | 1 |  |  |  |  | 25 |  | 
| 6 | 1 |  |  | 1 |  | 6 | use Catalyst::Utils (); | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 19 |  | 
| 7 | 1 |  |  | 1 |  | 6 | use Scalar::Util 'reftype'; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 83 |  | 
| 8 | 1 |  |  | 1 |  | 8 | use Moose::Util qw/find_meta apply_all_roles/; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 11 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 | 1 |  |  | 1 |  | 524 | use namespace::clean -except => 'meta'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 11 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | our $VERSION = '0.04'; | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | =head1 NAME | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | Catalyst::Plugin::PluginLoader - Load Catalyst Plugins from Config | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | <Plugin::PluginLoader> | 
| 21 |  |  |  |  |  |  | plugins Session | 
| 22 |  |  |  |  |  |  | plugins Session::Store::FastMmap | 
| 23 |  |  |  |  |  |  | plugins Session::State::Cookie | 
| 24 |  |  |  |  |  |  | </Plugin::PluginLoader> | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | use Catalyst qw/ConfigLoader PluginLoader/; | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | Allows you to load L<Catalyst> plugins from your app config file. | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | Plugin order is the same as if you put the plugins after PluginLoader in the | 
| 33 |  |  |  |  |  |  | C<use Catalyst> line. | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | Roles will be loaded as well, however C<around 'setup'> will not work yet. | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | This is a B<COLOSSAL HACK>, use at your own risk. | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | Please report bugs at L<http://rt.cpan.org/>. | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | =cut | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | sub setup { | 
| 44 | 1 |  |  | 1 | 0 | 286152 | my $class = shift; | 
| 45 |  |  |  |  |  |  |  | 
| 46 | 1 | 50 |  |  |  | 11 | if (my $plugins = $class->config->{'Plugin::PluginLoader'}{plugins}) { | 
| 47 | 1 |  |  |  |  | 106 | my %old_plugins = %{ $class->_plugins }; | 
|  | 1 |  |  |  |  | 9 |  | 
| 48 |  |  |  |  |  |  |  | 
| 49 | 1 | 50 |  |  |  | 23 | $plugins = [ $plugins ] unless ref $plugins; | 
| 50 |  |  |  |  |  |  |  | 
| 51 | 1 | 50 |  |  |  | 9 | Catalyst::Exception->throw( | 
| 52 |  |  |  |  |  |  | 'plugins must be an arrayref' | 
| 53 |  |  |  |  |  |  | ) if reftype $plugins ne 'ARRAY'; | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 3 | 100 |  |  |  | 14 | $plugins = [ map { | 
| 56 | 3 |  |  |  |  | 6 | s/\A\+// ? $_ : "Catalyst::Plugin::$_" | 
| 57 | 1 |  |  |  |  | 2 | } grep { !exists $old_plugins{$_} } @$plugins ]; | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 1 |  |  | 1 |  | 450 | my $isa = do { no strict 'refs'; \@{$class.'::ISA'}}; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 727 |  | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 10 |  | 
|  | 1 |  |  |  |  | 4 |  | 
| 60 |  |  |  |  |  |  |  | 
| 61 | 1 |  |  |  |  | 1 | my $isa_idx = 0; | 
| 62 | 1 |  |  |  |  | 16 | $isa_idx++ while $isa->[$isa_idx] ne __PACKAGE__; | 
| 63 |  |  |  |  |  |  |  | 
| 64 | 1 |  |  |  |  | 2 | for my $plugin (@$plugins) { | 
| 65 | 3 |  |  |  |  | 10 | Catalyst::Utils::ensure_class_loaded($plugin); | 
| 66 | 3 |  |  |  |  | 6861 | $class->_plugins->{$plugin} = 1; | 
| 67 |  |  |  |  |  |  |  | 
| 68 | 3 |  |  |  |  | 66 | my $meta = find_meta($plugin); | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 3 | 100 | 66 |  |  | 42 | if ($meta && blessed $meta && $meta->isa('Moose::Meta::Role')) { | 
|  |  |  | 66 |  |  |  |  | 
| 71 | 1 |  |  |  |  | 5 | apply_all_roles($class => $plugin); | 
| 72 |  |  |  |  |  |  | } else { | 
| 73 | 2 |  |  |  |  | 57 | splice @$isa, ++$isa_idx, 0, $plugin; | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 1 |  |  |  |  | 3384 | unshift @$isa, shift @$isa; # necessary to tell perl that @ISA changed | 
| 78 | 1 |  |  |  |  | 9 | mro::invalidate_all_method_caches(); | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 1 | 50 |  |  |  | 17 | if ($class->debug) { | 
| 81 | 0 |  | 0 |  |  | 0 | my @plugins = map { "$_  " . ( $_->VERSION || '' ) } @$plugins; | 
|  | 0 |  |  |  |  | 0 |  | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 0 | 0 |  |  |  | 0 | if (@plugins) { | 
| 84 | 0 |  |  |  |  | 0 | my $t = Text::SimpleTable->new(74); | 
| 85 | 0 |  |  |  |  | 0 | $t->row($_) for @plugins; | 
| 86 | 0 |  |  |  |  | 0 | $class->log->debug( "Loaded plugins from config:\n" . $t->draw . "\n" ); | 
| 87 |  |  |  |  |  |  | } | 
| 88 |  |  |  |  |  |  | } | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | { | 
| 91 |  |  |  |  |  |  | # ->next::method won't work anymore, we have to do it ourselves | 
| 92 | 1 |  |  |  |  | 7 | my @precedence_list = $class->meta->class_precedence_list; | 
|  | 1 |  |  |  |  | 11 |  | 
| 93 |  |  |  |  |  |  |  | 
| 94 | 1 |  |  |  |  | 382 | 1 while shift @precedence_list ne __PACKAGE__; | 
| 95 |  |  |  |  |  |  |  | 
| 96 | 1 |  |  |  |  | 4 | my $old_next_method = \&maybe::next::method; | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | my $next_method = sub { | 
| 99 | 4 | 50 |  | 4 |  | 1242 | if ((caller(1))[3] !~ /::setup\z/) { | 
| 100 | 0 |  |  |  |  | 0 | goto &$old_next_method; | 
| 101 |  |  |  |  |  |  | } | 
| 102 |  |  |  |  |  |  |  | 
| 103 | 4 |  |  |  |  | 6 | my $code; | 
| 104 | 4 |  |  |  |  | 10 | while (my $next_class = shift @precedence_list) { | 
| 105 | 4 |  |  |  |  | 48 | $code = $next_class->can('setup'); | 
| 106 | 4 | 50 |  |  |  | 14 | last if $code; | 
| 107 |  |  |  |  |  |  | } | 
| 108 | 4 | 50 |  |  |  | 8 | return unless $code; | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 4 |  |  |  |  | 20 | goto &$code; | 
| 111 | 1 |  |  |  |  | 7 | }; | 
| 112 |  |  |  |  |  |  |  | 
| 113 | 1 |  |  | 1 |  | 6 | no warnings 'redefine'; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 150 |  | 
| 114 | 1 |  |  |  |  | 3 | local *next::method           = $next_method; | 
| 115 | 1 |  |  |  |  | 3 | local *maybe::next::method    = $next_method; | 
| 116 |  |  |  |  |  |  |  | 
| 117 | 1 |  |  |  |  | 6 | return $class->next::method(@_); | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 | 0 |  |  |  |  |  | return $class->next::method(@_); | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | L<Catalyst>, L<Catalyst::Plugin::ConfigLoader>, | 
| 127 |  |  |  |  |  |  | L<Catalyst::Manual::ExtendingCatalyst> | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | =head1 TODO | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | Better tests. | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | =head1 AUTHOR | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | Ash Berlin, C<ash at cpan.org> | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | Rafael Kitover, C<rkitover at cpan.org> | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | This program is free software, you can redistribute it and/or modify it | 
| 142 |  |  |  |  |  |  | under the same terms as Perl itself. | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | =cut | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | 1; | 
| 147 |  |  |  |  |  |  | # vim:sw=2 sts=2: |