File Coverage

blib/lib/Catalyst/Plugin/PluginLoader.pm
Criterion Covered Total %
statement 66 74 89.1
branch 11 20 55.0
condition 4 8 50.0
subroutine 11 11 100.0
pod 0 1 0.0
total 92 114 80.7


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: