File Coverage

blib/lib/Catalyst/ActionRole/MethodSignatureDependencyInjection.pm
Criterion Covered Total %
statement 122 218 55.9
branch 53 108 49.0
condition 5 11 45.4
subroutine 24 44 54.5
pod 1 3 33.3
total 205 384 53.3


line stmt bran cond sub pod time code
1             package Catalyst::ActionRole::MethodSignatureDependencyInjection;
2              
3 3     3   1147951 use Moose::Role;
  3         10  
  3         41  
4 3     3   16396 use Carp;
  3         7  
  3         9747  
5              
6             our $VERSION = '0.018';
7              
8             has use_prototype => (
9             is=>'ro',
10             required=>1,
11             lazy=>1,
12             builder=>'_build_prototype');
13              
14             sub _build_at {
15 0     0   0 my ($self) = @_;
16 0 0       0 my ($attr) = @{$self->attributes->{UsePrototype}||[0]};
  0         0  
17 0         0 return $attr;
18             }
19              
20             has execute_args_template => (
21             is=>'ro',
22             required=>1,
23             lazy=>1,
24             builder=>'_build_execute_args_template');
25              
26             sub _build_execute_args_template {
27 1     1   5 my ($self) = @_;
28 1 50       3 my ($attr) = @{$self->attributes->{ExecuteArgsTemplate}||['']};
  1         54  
29 1         402 return $attr;
30             }
31              
32             has prototype => (
33             is=>'ro',
34             required=>1,
35             lazy=>1,
36             builder=>'_build_prototype');
37              
38             sub _build_prototype {
39 21     21   36 my ($self) = @_;
40 21 50       76 if($INC{'Function/Parameters.pm'}) {
41             return join ',',
42 0 0       0 map {$_->type? $_->type->class : $_->name}
  0         0  
43             Function::Parameters::info($self->code)->positional_required;
44             } else {
45 21         636 return prototype($self->code);
46             }
47             }
48              
49             has template => (
50             is=>'ro',
51             required=>1,
52             lazy=>1,
53             builder=>'_build_template');
54              
55             sub _build_template {
56 11     11   26 my ($self) = @_;
57 11 100       669 return $self->use_prototype ?
58             $self->prototype : $self->execute_args_template;
59             }
60              
61             sub parse_injection_spec_section {
62 41     41 0 64 my ($self) = @_;
63              
64             # These Regexps could be better to allow more whitespace.
65 41         343 my $p = qr/[^,]+/;
66 41         256 my $p2 = qr/$p<.+?>$p/x;
67              
68 41         392 $_[1]=~/\s*($p2|$p)\s*/gxc;
69              
70 41         243 return $1;
71             }
72              
73             has dependency_builder => (
74             is=>'ro',
75             required=>1,
76             isa=>'ArrayRef',
77             lazy=>1,
78             builder=>'_dependency_builder');
79              
80             sub _dependency_builder {
81 11     11   23 my $self = shift;
82 11         580 my $template = $self->template;
83 11         50 my @parsed = $self->_parse_dependencies($template);
84              
85 11         672 return \@parsed;
86             }
87              
88             sub _parse_dependencies {
89 11     11   22 my ($self, $template) = @_;
90 11         30 my @what = ();
91 11         28 for($template) {
92             PARSE: {
93 11 50       21 last PARSE unless length;
  11         34  
94 11         18 do {
95 41   50     121 push @what, $self->parse_injection_spec_section($_)
96             || die "trouble parsing action $self template '$template'";
97 41 100       201 last PARSE if (pos == length);
98             } until (pos == length);
99             }
100             }
101              
102 11         85 return @what;
103             }
104              
105             has prepared_dependencies => (
106             is=>'ro',
107             required=>1,
108             isa=>'ArrayRef',
109             lazy=>1,
110             builder=>'_build_prepared_dependencies');
111              
112 36     36 0 209 sub not_required { return bless \(my $cb = shift), __PACKAGE__.'::not_required'; }
113 5     5 1 29 sub required { return bless \(my $cb = shift), __PACKAGE__.'required'; }
114              
115             sub _prepare_dependencies {
116 11     11   37 my ($self, @what) = @_;
117 11         20 my $arg_count = 0;
118 11         20 my $capture_count = 0;
119 11         28 my @dependencies = ();
120 11         51 while(my $what = shift @what) {
121 41 100   36   932 my $method = $what =~m/required/ ? sub {required(shift) } : sub { not_required(shift) };
  5         14  
  36         97  
122 41 100   4   127 do { push @dependencies, $method->(sub { shift }); next } if lc($what) eq '$ctx';
  4         26  
  4         13  
  4         26  
123 37 100   2   92 do { push @dependencies, $method->(sub { shift }); next } if lc($what) eq '$c';
  4         16  
  2         6  
  4         18  
124 33 50   0   76 do { push @dependencies, $method->(sub { shift->state }); next } if lc($what) eq '$state';
  0         0  
  0         0  
  0         0  
125 33 100   2   87 do { push @dependencies, $method->(sub { shift->req }); next } if lc($what) eq '$req';
  2         16  
  2         10  
  2         11  
126 31 50   0   85 do { push @dependencies, $method->(sub { shift->req }); next } if lc($what) eq '$request';
  0         0  
  0         0  
  0         0  
127 31 50   0   75 do { push @dependencies, $method->(sub { shift->req->env }); next } if lc($what) eq '$env';
  0         0  
  0         0  
  0         0  
128              
129 31 100   6   79 do { push @dependencies, $method->(sub { shift->res }); next } if lc($what) eq '$res';
  6         42  
  6         55  
  6         29  
130 25 50   0   68 do { push @dependencies, $method->(sub { shift->res }); next } if lc($what) eq '$response';
  0         0  
  0         0  
  0         0  
131              
132 25 50   0   58 do { push @dependencies, $method->(sub { shift->req->args}); next } if lc($what) eq '$args';
  0         0  
  0         0  
  0         0  
133 25 50   2   73 do { push @dependencies, $method->(sub { shift->req->body_data||+{} }); next } if lc($what) eq '$bodydata';
  2 100       13  
  2         9  
  2         16  
134 23 100   2   57 do { push @dependencies, $method->(sub { shift->req->body_parameters}); next } if lc($what) eq '$bodyparams';
  2         12  
  2         28  
  2         11  
135 21 100   2   53 do { push @dependencies, $method->(sub { shift->req->query_parameters}); next } if lc($what) eq '$queryparams';
  2         12  
  2         11  
  2         10  
136              
137             #This will blow stuff up unless its the last...
138 19 50   0   49 do { push @dependencies, $method->(sub { @{shift->req->args}}) ; next } if lc($what) eq '@args';
  0         0  
  0         0  
  0         0  
  0         0  
139 19 50   0   48 do { push @dependencies, $method->(sub { %{shift->req->body_parameters}}); next } if lc($what) eq '%bodyparams';
  0         0  
  0         0  
  0         0  
  0         0  
140 19 0   0   42 do { push @dependencies, $method->(sub { %{shift->req->body_data||+{}}}); next } if lc($what) eq '%bodydata';
  0 50       0  
  0         0  
  0         0  
  0         0  
141              
142 19 50   0   44 do { push @dependencies, $method->(sub { %{shift->req->query_parameters}}); next } if lc($what) eq '%queryparams';
  0         0  
  0         0  
  0         0  
  0         0  
143 19 0   0   58 do { push @dependencies, $method->(sub { %{shift->req->body_data||+{}}}); next } if lc($what) eq '%body';
  0 50       0  
  0         0  
  0         0  
  0         0  
144 19 50   0   43 do { push @dependencies, $method->(sub { %{shift->req->query_parameters}}); next } if lc($what) eq '%query';
  0         0  
  0         0  
  0         0  
  0         0  
145              
146             # Default view and model
147             # For now default model / view can't be parameterized.
148 19 100 100 2   154 do { push @dependencies, $method->(sub { shift->model}) ; next } if($what =~/^Model/ && $what!~/^Model\:/);
  2         9  
  2         14  
  2         9  
149 17 50 33 0   59 do { push @dependencies, $method->(sub { shift->view}) ; next } if($what =~/^View/ && $what!~/^View\:/);
  0         0  
  0         0  
  0         0  
150            
151 17 100       93 if(defined(my $arg_index = ($what =~/^\$?Arg(\d+).*$/i)[0])) {
152 1     1   7 push @dependencies, $method->(sub { shift->req->args->[$arg_index] });
  1         4  
153 1         1 $arg_count = undef;
154 1         6 next;
155             }
156              
157 16 50       48 if($what=~/^\$?Args\s/) {
158 0     0   0 push @dependencies, $method->(sub { @{shift->req->args}}); # need to die if this is not the last..
  0         0  
  0         0  
159 0         0 next;
160             }
161              
162 16 100       66 if($what =~/^\$?Arg\s?.*/i) {
163             # count arg
164 2 50       8 confess "You can't mix numbered args and unnumbered args in the same signature" unless defined $arg_count;
165 2         5 my $local = $arg_count;
166 2     2   18 push @dependencies, $method->(sub { shift->req->args->[$local]}) ;
  2         11  
167 2         64 $arg_count++;
168 2         14 next;
169             }
170              
171 14 50       42 if($what =~/^\$?Capture\s?.*/i) {
172             # count arg
173 0         0 my $local = $capture_count;
174 0 0       0 confess "You can't mix numbered captures and unnumbered captures in the same signature" unless defined $arg_count;
175 0     0   0 push @dependencies, $method->(sub { my ($c, @args) = @_; return $args[$local] });
  0         0  
  0         0  
176 0         0 $capture_count++;
177             next
178 0         0 }
179              
180 14 50       47 if(defined(my $capture_index = ($what =~/^\$?Capture(\d+).*$/i)[0])) {
181             # If they are asking for captures, we look at @args.. sorry
182 0         0 my $local = $capture_index;
183 0     0   0 push @dependencies, $method->(sub { my ($c, @args) = @_; $args[$local] });
  0         0  
  0         0  
184 0         0 next;
185             }
186              
187 14 50       49 if($what=~/^Model\:\:/i) {
188             # Its a model. Could be:
189             # -- Model::Foo
190             # -- Model::Foo $foo
191             # -- Model::Foo $foo isa Int
192             # -- Model::Foo $foo isa Int required
193             # -- Model::Foo<$params>
194             # -- Model::Foo<$params> $foo
195             # -- Model::Foo<$params> $foo isa Int
196             # -- Model::Foo<$params> $foo isa Int required
197             # For where $params is any sort of parsable spec (Arg, Arg $id, Arg $id isa Int, ...)
198            
199             # first get the model name
200 14         25 my @inner_deps = ();
201 14         48 my ($model) = ($what=~m/^Model\:\:([\w\:]+)/i);
202              
203 14 50       36 die "Can't seem to extract a model name from '$what'!" unless $model;
204              
205 14         29 my ($rest) = ($what =~/<([^>]+)/);
206              
207             # Is the model parameterized??
208 14 50       147 if(defined($rest)) {
209 0         0 @inner_deps = $self->_prepare_dependencies($self->_parse_dependencies($rest));
210             }
211              
212 14 50       33 push @dependencies, @inner_deps if @inner_deps;
213             push @dependencies, $method->(sub {
214 12     12   27 my ($c, @args) = @_;
215              
216             # Make sure the $model is a component we already know about.
217             die "'$model' is not a defined component (parsed out of '$what'"
218 12 50       48 unless $c->components->{ ref($c).'::Model::'.$model };
219              
220 12         360 my ($ret, @rest) = $c->model($model, map { $$_->($c, @args) } @inner_deps);
  0         0  
221 12 50       622 warn "$model returns more than one arg" if @rest;
222 12         36 return $ret;
223 14         83 });
224 14         68 next;
225             }
226              
227 0 0       0 if($what=~/^View\:\:/i) {
228 0         0 my @inner_deps = ();
229 0         0 my ($view) = ($what=~m/^View\:\:([\w\:]+)/i);
230              
231 0 0       0 die "Can't seem to extract a view name from '$what'!" unless $view;
232              
233 0         0 my ($rest) = ($what =~/<([^>]+)/);
234              
235 0 0       0 if(defined($rest)) {
236 0         0 @inner_deps = $self->_prepare_dependencies($self->_parse_dependencies($rest));
237             }
238              
239 0 0       0 push @dependencies, @inner_deps if @inner_deps;
240             push @dependencies, $method->(sub {
241 0     0   0 my ($c, @args) = @_;
242              
243             die "'$view' is not a defined component (parsed out of '$what'"
244 0 0       0 unless $c->components->{ ref($c).'::View::'.$view };
245              
246 0         0 my ($ret, @rest) = $c->view($view, map { $$_->($c, @args) } @inner_deps);
  0         0  
247 0 0       0 warn "$view returns more than one arg" if @rest;
248 0         0 return $ret;
249 0         0 });
250 0         0 next;
251             }
252              
253 0 0 0     0 if(my $controller = ($what =~/^Controller\:\:(.+?)\s+.+$/)[0] || ($what =~/^Controller\:\:(.+)\s+.+$/)[0]) {
254             push @dependencies, $method->(sub {
255 0     0   0 my $c = shift;
256              
257             # Make sure the $controller is a component we already know about.
258             die "$controller is not a defined component"
259 0 0       0 unless $c->components->{ ref($c).'::Controller::'.$controller };
260              
261 0         0 my ($ret, @rest) = $c->controller($controller);
262 0 0       0 warn "$controller returns more than one arg" if @rest;
263 0         0 return $ret;
264 0         0 });
265 0         0 next;
266             }
267              
268 0         0 die "Found undefined Token in action $self signature '${\$self->template}' => '$what'";
  0         0  
269             }
270              
271 11 50       42 unless(scalar @dependencies) {
272             @dependencies = (
273 0     0   0 not_required(sub { return $_[0] }),
274 0     0   0 not_required(sub { return @{$_[0]->req->args} }),
  0         0  
  0         0  
275             );
276             }
277              
278 11         1417 return @dependencies;
279             }
280              
281             sub _build_prepared_dependencies {
282 11     11   22 my ($self) = @_;
283 11         25 my @what = @{$self->dependency_builder};
  11         617  
284 11         53 return [ $self->_prepare_dependencies(@what) ];
285             }
286              
287             around ['match', 'match_captures'] => sub {
288             my ($orig, $self, $ctx, $args) = @_;
289             return 0 unless $self->$orig($ctx, $args);
290              
291             # For chain captures, we find @args, but not for args...
292             # So we have to normalize.
293            
294             my @args = scalar(@{$args||[]}) ? @{$args||[]} : @{$ctx->req->args||[]};
295              
296             my @resolved = ();
297             foreach my $dependency (@{ $self->prepared_dependencies }) {
298             my $required = $dependency=~m/not_required/ ? 0:1;
299             if($required) {
300             my $ret = $$dependency->($ctx, @args);
301             unless(defined $ret) {
302             return 0;
303             } else {
304             push @resolved, $ret;
305             }
306             } else {
307             push @resolved, $dependency;
308             }
309             }
310              
311             $ctx->stash->{__method_signature_dependencies_keys}->{"$self"} = \@resolved;
312             return 1;
313             };
314              
315             around 'execute', sub {
316             my ($orig, $self, $controller, $ctx, @args) = @_;
317             my $stash_key = $self .'__method_signature_dependencies';
318             my @dependencies = map { $_=~m/not_required/ ? $$_->($ctx, @args) : $_ }
319             @{$ctx->stash->{__method_signature_dependencies_keys}->{"$self"}};
320              
321             return $self->$orig($controller, @dependencies);
322             };
323              
324             1;
325              
326             =head1 NAME
327              
328             Catalyst::ActionRole::MethodSignatureDependencyInjection - Experimental Action Signature Dependency Injection
329              
330             =head1 SYNOPSIS
331              
332             Attribute syntax:
333              
334             package MyApp::Controller
335             use base 'Catalyst::Controller';
336              
337             sub test_model :Local :Does(MethodSignatureDependencyInjection)
338             ExecuteArgsTemplate($c, $Req, $Res, $BodyData, $BodyParams, $QueryParams, Model::A, Model::B)
339             {
340             my ($self, $c, $Req, $Res, $Data, $Params, $Query, $A, $B) = @_;
341             }
342              
343             Prototype syntax
344              
345             package MyApp::Controller
346             use base 'Catalyst::Controller';
347              
348             no warnings::illegalproto;
349              
350             sub test_model($c, $Req, $Res, $BodyData, $BodyParams, $QueryParams, Model::A required, Model::B)
351             :Local :Does(MethodSignatureDependencyInjection) UsePrototype(1)
352             {
353             my ($self, $c, $Req, $Res, $Data, $Params, $Query, $A, $B) = @_;
354             }
355              
356             With required model injection:
357              
358             package MyApp::Controller
359             use base 'Catalyst::Controller';
360              
361             no warnings::illegalproto;
362              
363             sub chainroot :Chained(/) PathPrefix CaptureArgs(0) { }
364              
365             sub no_null_chain_1( $c, Model::ReturnsNull, Model::ReturnsTrue)
366             :Chained(chainroot) PathPart('no_null_chain')
367             :Does(MethodSignatureDependencyInjection) UsePrototype(1)
368             {
369             my ($self, $c) = @_;
370             return $c->res->body('no_null_chain_1');
371             }
372              
373             sub no_null_chain_2( $c, Model::ReturnsNull required, Model::ReturnsTrue required)
374             :Chained(chainroot) PathPart('no_null_chain')
375             :Does(MethodSignatureDependencyInjection) UsePrototype(1)
376             {
377             my ($self, $c) = @_;
378             return $c->res->body('no_null_chain_2');
379             }
380              
381              
382             =head1 WARNING
383              
384             Lets you declare required action dependencies via the a subroutine attribute
385             and additionally via the prototype (if you dare)
386              
387             This is a weakly documented, early access prototype. The author reserves the
388             right to totally change everything and potentially disavow all knowledge of it.
389             Only report bugs if you are capable of offering a patch and discussion.
390              
391             B<UPDATE> This module is starting to stablize, and I'd be interested in seeing
392             people use it and getting back to me on it. But I do recommend using it only
393             if you feel like its code you understand.
394              
395             Please note if any of the declared dependencies return undef, that will cause
396             the action to not match. This could probably be better warning wise...
397              
398             =head1 DESCRIPTION
399              
400             L<Catalyst> when dispatching a request to an action calls the L<Action::Class>
401             execute method with the following arguments ($self, $c, @args). This you likely
402             already know (if you are a L<Catalyst> programmer).
403              
404             This action role lets you describe an alternative 'template' to be used for
405             what arguments go to the execute method. This way instead of @args you can
406             get a model, or a view, or something else. The goal of this action role is
407             to make your action bodies more concise and clear and to have your actions
408             declare what they want.
409              
410             Additionally, when we build these arguments, we also check their values and
411             require them to be true during the match/match_captures phase. This means
412             you can actually use this to control how an action is matched.
413              
414             There are two ways to use this action role. The default way is to describe
415             your execute template using the 'ExecuteArgsTemplate' attribute. The
416             second is to enable UsePrototype (via the UsePrototype(1) attribute) and
417             then you can declare your argument template via the method prototype. You
418             will of course need to use 'no warnings::illegalproto' for this to work.
419             The intention here is to work toward something that would play nice with
420             a system for method signatures like L<Kavorka>.
421              
422             If this sounds really verbose it is. This distribution is likely going to
423             be part of something larger that offers more sugar and less work, just it was
424             clearly also something that could be broken out and hacked pn separately.
425             If you use this you might for example set this action role in a base controller
426             such that all your controllers get it (one example usage).
427              
428             Please note that you must still access your arguments via C<@_>, this is not
429             a method signature framework. You can take a look at L<Catalyst::ActionSignatures>
430             for a system that bundles this all up more neatly.
431              
432             =head1 DEPENDENCY INJECTION
433              
434             You define your execute arguments as a positioned list (for now). The system
435             recognizes the following 'built ins' (you always get $self automatically).
436              
437             B<NOTE> These arguments are matched using a case insensitive regular expression
438             so generally whereever you see $arg you can also use $Arg or $ARG.
439              
440             =head2 $c
441              
442             =head2 $ctx
443              
444             The current context. You are encouraged to more clearly name your action
445             dependencies, but its here if you need it.
446              
447             =head2 $req
448              
449             =head2 $request
450              
451             The current L<Catalyst::Request>
452              
453             =head2 $res
454              
455             =head2 $request
456              
457             The current L<Catalyst::Response>
458              
459             =head2 $args
460              
461             An arrayref of the current args
462              
463             =head2 args
464             =head2 @args
465              
466             An array of the current args. Only makes sense if this is the last specified
467             argument.
468              
469             =head2 $arg0 .. $argN
470              
471             =head2 arg0 ... argN
472              
473             One of the indexed args, where $args0 => $args[0];
474              
475             =head2 arg
476              
477             =head2 $arg
478              
479             If you use 'arg' without a numbered index, we assume an index based on the number
480             of such 'un-numbered' args in your signature. For example:
481              
482             ExecuteArgsTemplate(Arg, Arg)
483              
484             Would match two arguments $arg->[0] and $args->[1]. You cannot use both numbered
485             and un-numbered args in the same signature.
486              
487             B<NOTE>This also works with the 'Args' special 'zero or more' match. So for
488             example:
489              
490             sub argsargs($res, Args @ids) :Local {
491             $res->body(join ',', @ids);
492             }
493              
494             Is the same as:
495              
496             sub argsargs($res, Args @ids) :Local Args {
497             $res->body(join ',', @ids);
498             }
499              
500             =head2 $captures
501              
502             An arrayref of the current CaptureArgs (used in Chained actions).
503              
504             =head2 @captures
505              
506             An array of the current CaptureArgs. Only makes sense if this is the last specified
507             argument.
508              
509             =head2 $capture0 .. $captureN
510              
511             =head2 capture0 ... captureN
512              
513             One of the indexed Capture Args, where $capture0 => $capture0[0];
514              
515             =head2 capture
516              
517             If you use 'capture' without a numbered index, we assume an index based on the number
518             of such 'un-numbered' args in your signature. For example:
519              
520             ExecuteArgsTemplate(Capture, Capture)
521              
522             Would match two arguments $capture->[0] and $capture->[1]. You cannot use both numbered
523             and un-numbered capture args in the same signature.
524              
525             =head2 $bodyData
526              
527             =head2 $bodydata
528              
529             $c->req->body_data
530              
531             =head2 $bodyParams
532              
533             =head2 $bodyparams
534              
535             $c->req->body_parameters
536              
537             =head2 $QueryParams
538              
539             =head2 $queryparams
540              
541             $c->req->query_parameters
542              
543             =head2 %query
544              
545             A hash of the information in $c->req->query_parameters. Must be the last argument in the
546             signature.
547              
548             =head2 %body
549              
550             A hash of the information in $c->req->body_data. Must be the last argument in the
551             signature.
552              
553             =head1 Accessing Components
554              
555             You can request a L<Catalyst> component (a model, view or controller). You
556             do this via [Model||View||Controller]::$component_name. For example if you
557             have a model that you'd normally access like this:
558              
559             $c->model("Schema::User");
560              
561             You would say "Model::Schema::User". For example:
562              
563             ExecuteArgsTemplate(Model::Schema::User)
564              
565             Or via the prototype
566              
567             sub myaction(Model::Schema::User) ...
568              
569             You can also pass arguments to your models. For example:
570              
571             ExecuteArgsTemplate(Model::UserForm<Model::User>)
572              
573             same as $c->model('UserForm', $c->model('User'));
574              
575             =head1 Default Components
576              
577             You may specify the current view or model by just using the declaration 'Model'
578             or 'View'. For example:
579              
580             package MyApp;
581             use Catalyst;
582            
583             # We assume MyApp::Model::Default
584             MyApp->config(default_model=>'Default');
585             MyApp->setup;
586              
587              
588             sub default_model($res,Model) :Local
589             :Does(MethodSignatureDependencyInjection) UsePrototype(1)
590             {
591             my ($self, $res, $model) = @_;
592             $res->body($model); # isa Model::Default
593             }
594              
595             sub chainroot :Chained(/) PathPrefix CaptureArgs(0) {
596             my ($self, $ctx) = @_;
597             $ctx->stash(current_model_instance => 100);
598             }
599              
600             sub default_again($res,Model required) :Chained(chainroot)
601             :Does(MethodSignatureDependencyInjection) UsePrototype(1)
602             {
603             my ($self, $res, $model) = @_;
604             return $res->body($model); # is 100
605             }
606              
607             Can be useful to help make controllers less tightly bound.
608              
609             =head1 Component Modifiers
610              
611             =head2 required
612              
613             Used to declare a component injection (Model, View or Controller) is 'required'. This means
614             it must return something that Perl thinks of as true (for now we exclude both undef and 0 since
615             I think that is less surprising and the use cases where a model validately return 0 seems
616             small). When a component is required, we resolve it during the match/match_captures phase of
617             dispatch and the action will fail to match should the component fail the required condition.
618             Useful if you use models as a we to determine if an action should run or no.
619              
620             B<NOTE> Since 'required' components get resolved during the match/match_captures phase, this
621             means that certain parts of the context have not been completed. For example $c->action will
622             be null (since we have not yet determined a matching action or not). If your model does
623             ACCEPT_CONTEXT and need $c->action, it cannot be required. I think this is the main thing
624             undefined with context at this phase but other bits may emerge so test carefully.
625              
626             =head1 Integration with Catalyst::ActionSignatures
627              
628             This action role will work with L<Catalyst::ActionSignatures> automatically and
629             all features are present.
630              
631             =head1 Integration with Function::Parameters
632              
633             For those of you that would like to push the limits even harder, we have
634             experimental support for L<Function::Parameters>. You may use like in the
635             following example.
636              
637             package MyApp::Controller::Root;
638              
639             use base 'Catalyst::Controller';
640              
641             use Function::Parameters({
642             method => {defaults => 'method'},
643             action => {
644             attributes => ':method :Does(MethodSignatureDependencyInjection) UsePrototype(1)',
645             shift => '$self',
646             check_argument_types => 0,
647             strict => 0,
648             default_arguments => 1,
649             }});
650              
651             action test_model($c, $res, Model::A $A, Model::Z $Z)
652             :Local
653             {
654             # ...
655             $res->body(...);
656             }
657              
658             method test($a) {
659             return $a;
660             }
661              
662             Please note that currently you cannot use the 'parameterized' syntax for component
663             injection (no Model::A<Model::Z> support).
664              
665             =head1 SEE ALSO
666              
667             L<Catalyst::Action>, L<Catalyst>, L<warnings::illegalproto>,
668             L<Catalyst::ActionSignatures>
669              
670             =head1 AUTHOR
671            
672             John Napiorkowski L<email:jjnapiork@cpan.org>
673            
674             =head1 COPYRIGHT & LICENSE
675            
676             Copyright 2015, John Napiorkowski L<email:jjnapiork@cpan.org>
677            
678             This library is free software; you can redistribute it and/or modify it under
679             the same terms as Perl itself.
680              
681             =cut