Updated pod
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Base.pm
1 package Catalyst::Base;
2
3 use strict;
4 use base qw/Catalyst::Component Catalyst::AttrContainer Class::Accessor::Fast/;
5
6 use Catalyst::Exception;
7 use Catalyst::Utils;
8 use Class::Inspector;
9 use NEXT;
10
11 __PACKAGE__->mk_classdata($_) for qw/_dispatch_steps _action_class/;
12
13 __PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
14 __PACKAGE__->_action_class('Catalyst::Action');
15
16 sub _DISPATCH : Private {
17     my ( $self, $c ) = @_;
18
19     foreach my $disp ( @{ $self->_dispatch_steps } ) {
20         last unless $c->forward($disp);
21     }
22
23     $c->forward('_END');
24 }
25
26 sub _BEGIN : Private {
27     my ( $self, $c ) = @_;
28     my $begin = ( $c->get_actions( 'begin', $c->namespace ) )[-1];
29     return 1 unless $begin;
30     $begin->execute($c);
31     return !@{ $c->error };
32 }
33
34 sub _AUTO : Private {
35     my ( $self, $c ) = @_;
36     my @auto = $c->get_actions( 'auto', $c->namespace );
37     foreach my $auto (@auto) {
38         $auto->execute($c);
39         return 0 unless $c->state;
40     }
41     return 1;
42 }
43
44 sub _ACTION : Private {
45     my ( $self, $c ) = @_;
46     $c->action->execute($c);
47     return !@{ $c->error };
48 }
49
50 sub _END : Private {
51     my ( $self, $c ) = @_;
52     my $end = ( $c->get_actions( 'end', $c->namespace ) )[-1];
53     return 1 unless $end;
54     $end->execute($c);
55     return !@{ $c->error };
56 }
57
58 =head1 NAME
59
60 Catalyst::Base - Catalyst Base Class
61
62 =head1 SYNOPSIS
63
64 See L<Catalyst>
65
66 =head1 DESCRIPTION
67
68 Catalyst Base Class
69
70 =head1 METHODS
71
72 =over 4
73
74 =item $self->action_namespace($c)
75
76 =cut
77
78 sub action_namespace {
79     my ( $self, $c ) = @_;
80     return Catalyst::Utils::class2prefix( ref $self,
81         $c->config->{case_sensitive} )
82       || '';
83 }
84
85 =item $self->register_actions($c)
86
87 =cut
88
89 sub register_actions {
90     my ( $self, $c ) = @_;
91     my $class = ref $self || $self;
92     my $namespace = $self->action_namespace($c);
93     my %methods;
94     $methods{ $self->can($_) } = $_
95       for @{ Class::Inspector->methods($class) || [] };
96
97     # Advanced inheritance support for plugins and the like
98     my @action_cache;
99     {
100         no strict 'refs';
101         for my $isa ( @{"$class\::ISA"}, $class ) {
102             push @action_cache, @{ $isa->_action_cache }
103               if $isa->can('_action_cache');
104         }
105     }
106
107     foreach my $cache (@action_cache) {
108         my $code   = $cache->[0];
109         my $method = $methods{$code};
110         next unless $method;
111         my $attrs = $self->_parse_attrs( @{ $cache->[1] } );
112         if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
113             $c->log->debug( 'Bad action definition "'
114                   . join( ' ', @{ $cache->[1] } )
115                   . qq/" for "$class->$method"/ )
116               if $c->debug;
117             next;
118         }
119         my $reverse = $namespace ? "$namespace/$method" : $method;
120         my $action = $self->_action_class->new(
121             {
122                 name       => $method,
123                 code       => $code,
124                 reverse    => $reverse,
125                 namespace  => $namespace,
126                 class      => $class,
127                 attributes => $attrs,
128             }
129         );
130         $c->dispatcher->register( $c, $action );
131     }
132 }
133
134 sub _parse_attrs {
135     my ( $self, @attrs ) = @_;
136     my %attributes;
137     foreach my $attr (@attrs) {
138
139         # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
140
141         if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
142         {
143
144             if ( defined $value ) {
145                 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
146             }
147             push( @{ $attributes{$key} }, $value );
148         }
149     }
150     return \%attributes;
151 }
152
153 =back
154
155 =head1 SEE ALSO
156
157 L<Catalyst>, L<Catalyst::Controller>.
158
159 =head1 AUTHOR
160
161 Sebastian Riedel, C<sri@cpan.org>
162 Marcus Ramberg, C<mramberg@cpan.org>
163 Matt S Trout, C<mst@shadowcatsystems.co.uk>
164
165 =head1 COPYRIGHT
166
167 This program is free software, you can redistribute it and/or modify it under
168 the same terms as Perl itself.
169
170 =cut
171
172 1;