File Coverage

blib/lib/Catalyst/Controller/ActionRole.pm
Criterion Covered Total %
statement 50 51 98.0
branch 3 4 75.0
condition n/a
subroutine 16 25 64.0
pod 1 2 50.0
total 70 82 85.3


line stmt bran cond sub pod time code
1             package Catalyst::Controller::ActionRole;
2             BEGIN {
3 5     5   10375168 $Catalyst::Controller::ActionRole::AUTHORITY = 'cpan:ETHER';
4             }
5             # git description: v0.15-6-g43eca1d
6             $Catalyst::Controller::ActionRole::VERSION = '0.16';
7             # ABSTRACT: Apply roles to action instances (DEPRECATED)
8              
9 5     5   52 use Moose;
  5         9  
  5         43  
10 5     5   32911 use Class::Load qw(load_class load_first_existing_class);
  5         13  
  5         345  
11 5     5   28 use Catalyst::Utils;
  5         9  
  5         124  
12 5     5   26 use Moose::Meta::Class;
  5         8  
  5         160  
13 5     5   24 use String::RewritePrefix 0.004;
  5         168  
  5         47  
14 5     5   735 use MooseX::Types::Moose qw/ArrayRef Str RoleName/;
  5         8  
  5         85  
15 5     5   32015 use List::Util qw(first);
  5         11  
  5         354  
16              
17 5     5   27 use namespace::clean -except => 'meta';
  5         9  
  5         51  
18              
19             extends 'Catalyst::Controller';
20              
21             #pod =head1 SYNOPSIS
22             #pod
23             #pod package MyApp::Controller::Foo;
24             #pod
25             #pod use Moose;
26             #pod use namespace::autoclean;
27             #pod
28             #pod BEGIN { extends 'Catalyst::Controller::ActionRole' }
29             #pod
30             #pod sub bar : Local Does('Moo') { ... }
31             #pod
32             #pod =head1 DESCRIPTION
33             #pod
34             #pod This module allows to apply L<Moose::Role>s to the C<Catalyst::Action>s for
35             #pod different controller methods.
36             #pod
37             #pod For that a C<Does> attribute is provided. That attribute takes an argument,
38             #pod that determines the role, which is going to be applied. If that argument is
39             #pod prefixed with C<+>, it is assumed to be the full name of the role. If it's
40             #pod prefixed with C<~>, the name of your application followed by
41             #pod C<::ActionRole::> is prepended. If it isn't prefixed with C<+> or C<~>,
42             #pod the role name will be searched for in C<@INC> according to the rules for
43             #pod L<role prefix searching|/ROLE PREFIX SEARCHING>.
44             #pod
45             #pod It's possible to apply roles to B<all> actions of a controller without
46             #pod specifying the C<Does> keyword in every action definition:
47             #pod
48             #pod package MyApp::Controller::Bar
49             #pod
50             #pod use Moose;
51             #pod use namespace::autoclean;
52             #pod
53             #pod BEGIN { extends 'Catalyst::Controller::ActionRole' }
54             #pod
55             #pod __PACKAGE__->config(
56             #pod action_roles => ['Foo', '~Bar'],
57             #pod );
58             #pod
59             #pod # Has Catalyst::ActionRole::Foo and MyApp::ActionRole::Bar applied.
60             #pod #
61             #pod # If MyApp::ActionRole::Foo exists and is loadable, it will take
62             #pod # precedence over Catalyst::ActionRole::Foo.
63             #pod #
64             #pod # If MyApp::ActionRole::Bar exists and is loadable, it will be loaded,
65             #pod # but even if it doesn't exist Catalyst::ActionRole::Bar will not be loaded.
66             #pod sub moo : Local { ... }
67             #pod
68             #pod Additionally, roles can be applied to selected actions without specifying
69             #pod C<Does> using L<Catalyst::Controller/action> and configured with
70             #pod L<Catalyst::Controller/action_args>:
71             #pod
72             #pod package MyApp::Controller::Baz;
73             #pod
74             #pod use Moose;
75             #pod use namespace::autoclean;
76             #pod
77             #pod BEGIN { extends 'Catalyst::Controller::ActionRole' }
78             #pod
79             #pod __PACKAGE__->config(
80             #pod action_roles => [qw( Foo )],
81             #pod action => {
82             #pod some_action => { Does => [qw( ~Bar )] },
83             #pod another_action => { Does => [qw( +MyActionRole::Baz )] },
84             #pod },
85             #pod action_args => {
86             #pod another_action => { customarg => 'arg1' },
87             #pod }
88             #pod );
89             #pod
90             #pod # has Catalyst::ActionRole::Foo and MyApp::ActionRole::Bar applied
91             #pod sub some_action : Local { ... }
92             #pod
93             #pod # has Catalyst::ActionRole::Foo and MyActionRole::Baz applied
94             #pod # and associated action class would get additional arguments passed
95             #pod sub another_action : Local { ... }
96             #pod
97             #pod =head1 ROLE PREFIX SEARCHING
98             #pod
99             #pod Roles specified with no prefix are looked up under a set of role prefixes. The
100             #pod first prefix is always C<MyApp::ActionRole::> (with C<MyApp> replaced as
101             #pod appropriate for your application); the following prefixes are taken from the
102             #pod C<_action_role_prefix> attribute.
103             #pod
104             #pod =attr _action_role_prefix
105             #pod
106             #pod This class attribute stores an array reference of role prefixes to search for
107             #pod role names in if they aren't prefixed with C<+> or C<~>. It defaults to
108             #pod C<[ 'Catalyst::ActionRole::' ]>. See L</role prefix searching>.
109             #pod
110             #pod =cut
111              
112             __PACKAGE__->mk_classdata(qw/_action_role_prefix/);
113             __PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
114              
115             #pod =attr _action_roles
116             #pod
117             #pod This attribute stores an array reference of role names that will be applied to
118             #pod every action of this controller. It can be set by passing a C<action_roles>
119             #pod argument to the constructor. The same expansions as for C<Does> will be
120             #pod performed.
121             #pod
122             #pod =cut
123              
124             has _action_role_args => (
125             traits => [qw(Array)],
126             isa => ArrayRef[Str],
127             init_arg => 'action_roles',
128             default => sub { [] },
129             handles => {
130             _action_role_args => 'elements',
131             },
132             );
133              
134             has _action_roles => (
135             traits => [qw(Array)],
136             isa => ArrayRef[RoleName],
137             init_arg => undef,
138             lazy_build => 1,
139             handles => {
140             _action_roles => 'elements',
141             },
142             );
143              
144             sub _build__action_roles {
145 25     25   39 my $self = shift;
146 25         1344 my @roles = $self->_expand_role_shortname($self->_action_role_args);
147 25         1280 load_class($_) for @roles;
148 25         28073 return \@roles;
149             }
150              
151             sub BUILD {
152 25     25 0 295 my $self = shift;
153             # force this to run at object creation time
154 25         1299 $self->_action_roles;
155             }
156              
157             around create_action => sub {
158             my ($orig, $self, %args) = @_;
159              
160             return $self->$orig(%args)
161             if $args{name} =~ /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/;
162              
163             my @roles = $self->gather_action_roles(%args);
164             return $self->$orig(%args) unless @roles;
165              
166             load_class($_) for @roles;
167              
168             my $action_class = $self->_build_action_subclass(
169             $self->action_class(%args), @roles,
170             );
171              
172             my $action_args = $self->config->{action_args};
173             my %extra_args = (
174             %{ $action_args->{'*'} || {} },
175             %{ $action_args->{ $args{name} } || {} },
176             );
177              
178             return $action_class->new({ %extra_args, %args });
179             };
180              
181             #pod =method gather_action_roles(\%action_args)
182             #pod
183             #pod Gathers the list of roles to apply to an action with the given C<%action_args>.
184             #pod
185             #pod =cut
186              
187             sub gather_action_roles {
188 61     61 1 67589 my ($self, %args) = @_;
189              
190             return (
191 61 100       479 $self->_action_roles,
192 61         3378 @{ $args{attributes}->{Does} || [] },
193             );
194             }
195             sub _build_action_subclass {
196 53     53   10702 my ($self, $action_class, @roles) = @_;
197              
198 53         381 my $meta = Moose::Meta::Class->initialize($action_class)->create_anon_class(
199             superclasses => [$action_class],
200             roles => \@roles,
201             cache => 1,
202             );
203 53     0   221267 $meta->add_method(meta => sub { $meta });
  0     0   0  
        0      
        0      
        0      
        0      
        0      
        0      
        0      
204              
205 53         2959 return $meta->name;
206             }
207              
208             sub _expand_role_shortname {
209 86     86   193 my ($self, @shortnames) = @_;
210 86         3103 my $app = $self->_application;
211              
212 86 50       981 my $prefix = $self->can('_action_role_prefix')
213             ? $self->_action_role_prefix
214             : ['Catalyst::ActionRole::'];
215              
216 86         4237 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
217              
218             return String::RewritePrefix->rewrite(
219             {
220             '' => sub {
221 98         398 my $loaded = load_first_existing_class(
222 49     49   2806 map { "$_$_[0]" } @prefixes
223             );
224 89         1512 return first { $loaded =~ /^$_/ }
225 49         173691 sort { length $b <=> length $a } @prefixes;
  49         272  
226             },
227 86         1307 '~' => $prefixes[0],
228             '+' => '',
229             },
230             @shortnames,
231             );
232             }
233              
234             sub _parse_Does_attr {
235 61     61   105438 my ($self, $app, $name, $value) = @_;
236 61         209 return Does => $self->_expand_role_shortname($value);
237             }
238              
239             #pod =begin Pod::Coverage
240             #pod
241             #pod BUILD
242             #pod
243             #pod =end Pod::Coverage
244             #pod
245             #pod =head1 DEPRECATION NOTICE
246             #pod
247             #pod As of version C<5.90013>, L<Catalyst> has merged this functionality into the
248             #pod core L<Catalyst::Controller>. You should no longer use it for new development
249             #pod and we'd recommend switching to the core controller as soon as practical.
250             #pod
251             #pod =cut
252              
253             1;
254              
255             __END__
256              
257             =pod
258              
259             =encoding UTF-8
260              
261             =head1 NAME
262              
263             Catalyst::Controller::ActionRole - Apply roles to action instances (DEPRECATED)
264              
265             =head1 VERSION
266              
267             version 0.16
268              
269             =head1 SYNOPSIS
270              
271             package MyApp::Controller::Foo;
272              
273             use Moose;
274             use namespace::autoclean;
275              
276             BEGIN { extends 'Catalyst::Controller::ActionRole' }
277              
278             sub bar : Local Does('Moo') { ... }
279              
280             =head1 DESCRIPTION
281              
282             This module allows to apply L<Moose::Role>s to the C<Catalyst::Action>s for
283             different controller methods.
284              
285             For that a C<Does> attribute is provided. That attribute takes an argument,
286             that determines the role, which is going to be applied. If that argument is
287             prefixed with C<+>, it is assumed to be the full name of the role. If it's
288             prefixed with C<~>, the name of your application followed by
289             C<::ActionRole::> is prepended. If it isn't prefixed with C<+> or C<~>,
290             the role name will be searched for in C<@INC> according to the rules for
291             L<role prefix searching|/ROLE PREFIX SEARCHING>.
292              
293             It's possible to apply roles to B<all> actions of a controller without
294             specifying the C<Does> keyword in every action definition:
295              
296             package MyApp::Controller::Bar
297              
298             use Moose;
299             use namespace::autoclean;
300              
301             BEGIN { extends 'Catalyst::Controller::ActionRole' }
302              
303             __PACKAGE__->config(
304             action_roles => ['Foo', '~Bar'],
305             );
306              
307             # Has Catalyst::ActionRole::Foo and MyApp::ActionRole::Bar applied.
308             #
309             # If MyApp::ActionRole::Foo exists and is loadable, it will take
310             # precedence over Catalyst::ActionRole::Foo.
311             #
312             # If MyApp::ActionRole::Bar exists and is loadable, it will be loaded,
313             # but even if it doesn't exist Catalyst::ActionRole::Bar will not be loaded.
314             sub moo : Local { ... }
315              
316             Additionally, roles can be applied to selected actions without specifying
317             C<Does> using L<Catalyst::Controller/action> and configured with
318             L<Catalyst::Controller/action_args>:
319              
320             package MyApp::Controller::Baz;
321              
322             use Moose;
323             use namespace::autoclean;
324              
325             BEGIN { extends 'Catalyst::Controller::ActionRole' }
326              
327             __PACKAGE__->config(
328             action_roles => [qw( Foo )],
329             action => {
330             some_action => { Does => [qw( ~Bar )] },
331             another_action => { Does => [qw( +MyActionRole::Baz )] },
332             },
333             action_args => {
334             another_action => { customarg => 'arg1' },
335             }
336             );
337              
338             # has Catalyst::ActionRole::Foo and MyApp::ActionRole::Bar applied
339             sub some_action : Local { ... }
340              
341             # has Catalyst::ActionRole::Foo and MyActionRole::Baz applied
342             # and associated action class would get additional arguments passed
343             sub another_action : Local { ... }
344              
345             =head1 ATTRIBUTES
346              
347             =head2 _action_role_prefix
348              
349             This class attribute stores an array reference of role prefixes to search for
350             role names in if they aren't prefixed with C<+> or C<~>. It defaults to
351             C<[ 'Catalyst::ActionRole::' ]>. See L</role prefix searching>.
352              
353             =head2 _action_roles
354              
355             This attribute stores an array reference of role names that will be applied to
356             every action of this controller. It can be set by passing a C<action_roles>
357             argument to the constructor. The same expansions as for C<Does> will be
358             performed.
359              
360             =head1 METHODS
361              
362             =head2 gather_action_roles(\%action_args)
363              
364             Gathers the list of roles to apply to an action with the given C<%action_args>.
365              
366             =head1 ROLE PREFIX SEARCHING
367              
368             Roles specified with no prefix are looked up under a set of role prefixes. The
369             first prefix is always C<MyApp::ActionRole::> (with C<MyApp> replaced as
370             appropriate for your application); the following prefixes are taken from the
371             C<_action_role_prefix> attribute.
372              
373             =for Pod::Coverage BUILD
374              
375             =head1 DEPRECATION NOTICE
376              
377             As of version C<5.90013>, L<Catalyst> has merged this functionality into the
378             core L<Catalyst::Controller>. You should no longer use it for new development
379             and we'd recommend switching to the core controller as soon as practical.
380              
381             =head1 AUTHOR
382              
383             Florian Ragwitz <rafl@debian.org>
384              
385             =head1 CONTRIBUTORS
386              
387             =over 4
388              
389             =item *
390              
391             Alex J. G. BurzyÅ„ski <ajgb@ajgb.net>
392              
393             =item *
394              
395             Hans Dieter Pearcey <hdp@weftsoar.net>
396              
397             =item *
398              
399             Jason Kohles <email@jasonkohles.com>
400              
401             =item *
402              
403             John Napiorkowski <jjnapiork@cpan.org>
404              
405             =item *
406              
407             Karen Etheridge <ether@cpan.org>
408              
409             =item *
410              
411             NAKAGAWA Masaki <masaki.nakagawa@gmail.com>
412              
413             =item *
414              
415             Tomas Doran <bobtfish@bobtfish.net>
416              
417             =item *
418              
419             William King <william.king@quentustech.com>
420              
421             =back
422              
423             =head1 COPYRIGHT AND LICENSE
424              
425             This software is copyright (c) 2009 by Florian Ragwitz.
426              
427             This is free software; you can redistribute it and/or modify it under
428             the same terms as the Perl 5 programming language system itself.
429              
430             =cut