passing tests again
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Action.pm
CommitLineData
fbcc39ad 1package Catalyst::Action;
2
b2ddf6d7 3=head1 NAME
4
5Catalyst::Action - Catalyst Action
6
7=head1 SYNOPSIS
8
804fb55d 9 <form action="[%c.uri_for(c.action)%]">
85d9fce6 10
009b5b23 11 $c->forward( $action->private_path );
12
b2ddf6d7 13=head1 DESCRIPTION
14
43c58153 15This class represents a Catalyst Action. You can access the object for the
b2ddf6d7 16currently dispatched action via $c->action. See the L<Catalyst::Dispatcher>
17for more information on how actions are dispatched. Actions are defined in
18L<Catalyst::Controller> subclasses.
19
20=cut
21
059c085b 22use Moose;
05b47f2e 23use Scalar::Util 'looks_like_number';
6d62355b 24use Moose::Util::TypeConstraints ();
241edc9b 25with 'MooseX::Emulate::Class::Accessor::Fast';
05b47f2e 26use namespace::clean -except => 'meta';
241edc9b 27
5fb12dbb 28has class => (is => 'rw');
29has namespace => (is => 'rw');
30has 'reverse' => (is => 'rw');
31has attributes => (is => 'rw');
32has name => (is => 'rw');
33has code => (is => 'rw');
009b5b23 34has private_path => (
35 reader => 'private_path',
36 isa => 'Str',
37 lazy => 1,
38 required => 1,
39 default => sub { '/'.shift->reverse },
40);
059c085b 41
81436df9 42has number_of_args => (
43 is=>'ro',
44 init_arg=>undef,
45 isa=>'Int|Undef',
46 required=>1,
47 lazy=>1,
48 builder=>'_build_number_of_args');
49
50 sub _build_number_of_args {
51 my $self = shift;
52 return 0 unless exists $self->attributes->{Args};
53 if(!defined($self->attributes->{Args}[0])) {
54 # When its 'Args' that internal cue for 'unlimited'
55 return undef;
56 } elsif(looks_like_number($self->attributes->{Args}[0])) {
57 # 'old school' numberd args (is allowed to be undef as well)
58 return $self->attributes->{Args}[0];
59 } else {
60 # new hotness named arg constraints
61 return $self->number_of_args_constraints;
62 }
63 }
64
6d62355b 65has args_constraints => (
66 is=>'ro',
81436df9 67 init_arg=>undef,
6d62355b 68 traits=>['Array'],
69 isa=>'ArrayRef',
70 required=>1,
71 lazy=>1,
72 builder=>'_build_args_constraints',
73 handles => {
74 has_args_constraints => 'count',
81436df9 75 number_of_args_constraints => 'count',
6d62355b 76 });
77
78 sub _build_args_constraints {
79 my $self = shift;
80 my @arg_protos = @{$self->attributes->{Args}||[]};
81
82 return [] unless scalar(@arg_protos);
83 # If there is only one arg and it looks like a number
84 # we assume its 'classic' and the number is the number of
85 # constraints.
86 my @args = ();
87 if(
88 scalar(@arg_protos) == 1 &&
89 looks_like_number($arg_protos[0])
90 ) {
81436df9 91 return \@args;
6d62355b 92 } else {
93 @args = map { Moose::Util::TypeConstraints::find_or_parse_type_constraint($_) || die "$_ is not a constraint!" } @arg_protos;
94 }
95
96 return \@args;
97 }
98
2055d9ad 99use overload (
100
101 # Stringify to reverse for debug output etc.
102 q{""} => sub { shift->{reverse} },
103
104 # Codulate to execute to invoke the encapsulated action coderef
105 '&{}' => sub { my $self = shift; sub { $self->execute(@_); }; },
106
107 # Make general $stuff still work
108 fallback => 1,
109
110);
111
059c085b 112no warnings 'recursion';
113
b2ddf6d7 114sub dispatch { # Execute ourselves against a context
115 my ( $self, $c ) = @_;
049f82e2 116 return $c->execute( $self->class, $self );
b2ddf6d7 117}
fbcc39ad 118
b2ddf6d7 119sub execute {
120 my $self = shift;
059c085b 121 $self->code->(@_);
b2ddf6d7 122}
fbcc39ad 123
b2ddf6d7 124sub match {
60034b8c 125 my ( $self, $c ) = @_;
81436df9 126 #would it be unreasonable to store the number of arguments
127 #the action has as its own attribute?
128 #it would basically eliminate the code below. ehhh. small fish
129 return 1 unless exists $self->attributes->{Args};
130 my $args = $self->attributes->{Args}[0];
131 return 1 unless defined($args) && length($args);
132
133 if($self->has_args_constraints) {
6d62355b 134 for my $i($#{ $c->req->args }) {
135 $self->args_constraints->[$i]->check($c->req->args->[$i]) || return 0;
136 }
137 return 1;
138 } else {
81436df9 139 return scalar( @{ $c->req->args } ) == $args;
6d62355b 140 }
760d121e 141}
142
60034b8c 143sub match_captures { 1 }
fbcc39ad 144
05b47f2e 145sub compare {
146 my ($a1, $a2) = @_;
81436df9 147
148 # Wen there is no declared Args for Local and Path (and Default??) we
149 # say that means any number of args... If Args exists however we use
150 # the number of args as determined by inspecting the value of it.
151
152 my $a1_args = exists($a1->attributes->{Args}) ? $a1->number_of_args : ~0;
153 my $a2_args = exists($a2->attributes->{Args}) ? $a2->number_of_args : ~0;
154
155 # If we did have an Args but it was undefined value (:Args() or :Args), that
156 # is the cue for 'as many args as you like also...
157 #
158 $_ = defined($_) ? $_ : ~0
159 for $a1_args, $a2_args;
cbe555e8 160
161 return $a1_args <=> $a2_args;
05b47f2e 162}
163
0cff119a 164sub number_of_captures {
165 my ( $self ) = @_;
166
167 return 0 unless exists $self->attributes->{CaptureArgs};
168 return $self->attributes->{CaptureArgs}[0] || 0;
169}
170
342d2169 171sub scheme {
172 return exists $_[0]->attributes->{Scheme} ? $_[0]->attributes->{Scheme}[0] : undef;
173}
174
ffca3e96 175sub list_extra_info {
176 my $self = shift;
177 return {
178 Args => $self->attributes->{Args}[0],
179 CaptureArgs => $self->number_of_captures,
180 }
181}
3c0da3ec 182
e5ecd5bc 183__PACKAGE__->meta->make_immutable;
184
b2ddf6d7 1851;
fbcc39ad 186
b2ddf6d7 187__END__
4ab87e27 188
fbcc39ad 189=head1 METHODS
190
b5ecfcf0 191=head2 attributes
fbcc39ad 192
4ab87e27 193The sub attributes that are set for this action, like Local, Path, Private
b2ddf6d7 194and so on. This determines how the action is dispatched to.
4ab87e27 195
b5ecfcf0 196=head2 class
b96f127f 197
4d38cb07 198Returns the name of the component where this action is defined.
f9818250 199Derived by calling the L<catalyst_component_name|Catalyst::Component/catalyst_component_name>
fb0c5b21 200method on each component.
4ab87e27 201
b5ecfcf0 202=head2 code
11bd4e3e 203
b2ddf6d7 204Returns a code reference to this action.
4ab87e27 205
b8f669f3 206=head2 dispatch( $c )
4ab87e27 207
18a9655c 208Dispatch this action against a context.
fbcc39ad 209
b8f669f3 210=head2 execute( $controller, $c, @args )
211
212Execute this action's coderef against a given controller with a given
213context and arguments
214
649fd1fa 215=head2 match( $c )
4ab87e27 216
649fd1fa 217Check Args attribute, and makes sure number of args matches the setting.
b2ddf6d7 218Always returns true if Args is omitted.
4082e678 219
760d121e 220=head2 match_captures ($c, $captures)
221
222Can be implemented by action class and action role authors. If the method
223exists, then it will be called with the request context and an array reference
224of the captures for this action.
225
226Returning true from this method causes the chain match to continue, returning
227makes the chain not match (and alternate, less preferred chains will be attempted).
228
229
91955398 230=head2 compare
231
cbe555e8 232Compares 2 actions based on the value of the C<Args> attribute, with no C<Args>
233having the highest precedence.
91955398 234
b5ecfcf0 235=head2 namespace
fbcc39ad 236
4ab87e27 237Returns the private namespace this action lives in.
238
b5ecfcf0 239=head2 reverse
6b239949 240
4ab87e27 241Returns the private path for this action.
242
009b5b23 243=head2 private_path
244
245Returns absolute private path for this action. Unlike C<reverse>, the
246C<private_path> of an action is always suitable for passing to C<forward>.
247
b5ecfcf0 248=head2 name
fbcc39ad 249
18a9655c 250Returns the sub name of this action.
4ab87e27 251
0cff119a 252=head2 number_of_args
253
254Returns the number of args this action expects. This is 0 if the action doesn't take any arguments and undef if it will take any number of arguments.
255
256=head2 number_of_captures
257
258Returns the number of captures this action expects for L<Chained|Catalyst::DispatchType::Chained> actions.
259
3c0da3ec 260=head2 list_extra_info
261
ffca3e96 262A HashRef of key-values that an action can provide to a debugging screen
3c0da3ec 263
342d2169 264=head2 scheme
265
266Any defined scheme for the action
267
059c085b 268=head2 meta
269
18a9655c 270Provided by Moose.
059c085b 271
2f381252 272=head1 AUTHORS
fbcc39ad 273
2f381252 274Catalyst Contributors, see Catalyst.pm
fbcc39ad 275
276=head1 COPYRIGHT
277
536bee89 278This library is free software. You can redistribute it and/or modify it under
fbcc39ad 279the same terms as Perl itself.
280
85d9fce6 281=cut
81436df9 282
283