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