new match and match captutres for http methods, plus tests, docs
[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';
241edc9b 24with 'MooseX::Emulate::Class::Accessor::Fast';
05b47f2e 25use namespace::clean -except => 'meta';
241edc9b 26
5fb12dbb 27has class => (is => 'rw');
28has namespace => (is => 'rw');
29has 'reverse' => (is => 'rw');
30has attributes => (is => 'rw');
31has name => (is => 'rw');
32has code => (is => 'rw');
009b5b23 33has private_path => (
34 reader => 'private_path',
35 isa => 'Str',
36 lazy => 1,
37 required => 1,
38 default => sub { '/'.shift->reverse },
39);
059c085b 40
2055d9ad 41use overload (
42
43 # Stringify to reverse for debug output etc.
44 q{""} => sub { shift->{reverse} },
45
46 # Codulate to execute to invoke the encapsulated action coderef
47 '&{}' => sub { my $self = shift; sub { $self->execute(@_); }; },
48
49 # Make general $stuff still work
50 fallback => 1,
51
52);
53
54
55
059c085b 56no warnings 'recursion';
57
b2ddf6d7 58sub dispatch { # Execute ourselves against a context
59 my ( $self, $c ) = @_;
049f82e2 60 return $c->execute( $self->class, $self );
b2ddf6d7 61}
fbcc39ad 62
b2ddf6d7 63sub execute {
64 my $self = shift;
059c085b 65 $self->code->(@_);
b2ddf6d7 66}
fbcc39ad 67
760d121e 68sub match_captures {
69 my ( $self, $c, $captures ) = @_;
70 ## It would seem that now that we can match captures, we could remove a lot
71 ## of the capture_args to args mapping all around. I gave it a go, but was
72 ## not trival, contact jnap on irc for what I tried if you want to try.
73 ## return $self->_match_has_expected_capture_args($captures) &&
74 return $self->_match_has_expected_http_method($c->req->method);
75}
76
b2ddf6d7 77sub match {
760d121e 78 my ( $self, $c ) = @_;
79 return $self->_match_has_expected_args($c->req->args) &&
80 $self->_match_has_expected_http_method($c->req->method);
81}
82
83sub _match_has_expected_args {
84 my ($self, $req_args) = @_;
85 return 1 unless exists $self->attributes->{Args};
86 my $args = $self->attributes->{Args}[0];
87 return 1 unless defined($args) && length($args);
88 return scalar( @{$req_args} ) == $args;
89}
90
91sub _match_has_expected_capture_args {
92 my ($self, $req_args) = @_;
93 return 1 unless exists $self->attributes->{CaptureArgs};
94 my $args = $self->attributes->{CaptureArgs}[0];
95 return 1 unless defined($args) && length($args);
96 return scalar( @{$req_args} ) == $args;
97}
98
99sub _match_has_expected_http_method {
100 my ($self, $method) = @_;
101 my @methods = @{ $self->attributes->{Method} || [] };
102 if(scalar @methods) {
103 my $result = scalar(grep { lc($_) eq lc($method) } @methods) ? 1:0;
104 return $result;
105 } else {
106 ## No HTTP Methods to check
107 return 1;
108 }
b2ddf6d7 109}
fbcc39ad 110
05b47f2e 111sub compare {
112 my ($a1, $a2) = @_;
113
cbe555e8 114 my ($a1_args) = @{ $a1->attributes->{Args} || [] };
115 my ($a2_args) = @{ $a2->attributes->{Args} || [] };
116
18a9655c 117 $_ = looks_like_number($_) ? $_ : ~0
cbe555e8 118 for $a1_args, $a2_args;
119
120 return $a1_args <=> $a2_args;
05b47f2e 121}
122
0cff119a 123sub number_of_args {
124 my ( $self ) = @_;
125 return 0 unless exists $self->attributes->{Args};
126 return $self->attributes->{Args}[0];
127}
128
129sub number_of_captures {
130 my ( $self ) = @_;
131
132 return 0 unless exists $self->attributes->{CaptureArgs};
133 return $self->attributes->{CaptureArgs}[0] || 0;
134}
135
e5ecd5bc 136__PACKAGE__->meta->make_immutable;
137
b2ddf6d7 1381;
fbcc39ad 139
b2ddf6d7 140__END__
4ab87e27 141
fbcc39ad 142=head1 METHODS
143
b5ecfcf0 144=head2 attributes
fbcc39ad 145
4ab87e27 146The sub attributes that are set for this action, like Local, Path, Private
b2ddf6d7 147and so on. This determines how the action is dispatched to.
4ab87e27 148
b5ecfcf0 149=head2 class
b96f127f 150
4d38cb07 151Returns the name of the component where this action is defined.
8f6cebb2 152Derived by calling the L<Catalyst::Component/catalyst_component_name|catalyst_component_name>
fb0c5b21 153method on each component.
4ab87e27 154
b5ecfcf0 155=head2 code
11bd4e3e 156
b2ddf6d7 157Returns a code reference to this action.
4ab87e27 158
b8f669f3 159=head2 dispatch( $c )
4ab87e27 160
18a9655c 161Dispatch this action against a context.
fbcc39ad 162
b8f669f3 163=head2 execute( $controller, $c, @args )
164
165Execute this action's coderef against a given controller with a given
166context and arguments
167
649fd1fa 168=head2 match( $c )
4ab87e27 169
649fd1fa 170Check Args attribute, and makes sure number of args matches the setting.
b2ddf6d7 171Always returns true if Args is omitted.
4082e678 172
760d121e 173=head2 match_captures ($c, $captures)
174
175Can be implemented by action class and action role authors. If the method
176exists, then it will be called with the request context and an array reference
177of the captures for this action.
178
179Returning true from this method causes the chain match to continue, returning
180makes the chain not match (and alternate, less preferred chains will be attempted).
181
182
91955398 183=head2 compare
184
cbe555e8 185Compares 2 actions based on the value of the C<Args> attribute, with no C<Args>
186having the highest precedence.
91955398 187
b5ecfcf0 188=head2 namespace
fbcc39ad 189
4ab87e27 190Returns the private namespace this action lives in.
191
b5ecfcf0 192=head2 reverse
6b239949 193
4ab87e27 194Returns the private path for this action.
195
009b5b23 196=head2 private_path
197
198Returns absolute private path for this action. Unlike C<reverse>, the
199C<private_path> of an action is always suitable for passing to C<forward>.
200
b5ecfcf0 201=head2 name
fbcc39ad 202
18a9655c 203Returns the sub name of this action.
4ab87e27 204
0cff119a 205=head2 number_of_args
206
207Returns 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.
208
209=head2 number_of_captures
210
211Returns the number of captures this action expects for L<Chained|Catalyst::DispatchType::Chained> actions.
212
059c085b 213=head2 meta
214
18a9655c 215Provided by Moose.
059c085b 216
2f381252 217=head1 AUTHORS
fbcc39ad 218
2f381252 219Catalyst Contributors, see Catalyst.pm
fbcc39ad 220
221=head1 COPYRIGHT
222
536bee89 223This library is free software. You can redistribute it and/or modify it under
fbcc39ad 224the same terms as Perl itself.
225
85d9fce6 226=cut