Reverting back to old behavior for components
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
CommitLineData
fc7ec1d9 1package Catalyst;
2
3use strict;
ac733264 4use base 'Catalyst::Base';
fc7ec1d9 5use UNIVERSAL::require;
6use Catalyst::Log;
0f7ecc53 7use Text::ASCIITable;
4f6748f1 8use Path::Class;
367d15f8 9our $CATALYST_SCRIPT_GEN = 4;
fc7ec1d9 10
424b2705 11__PACKAGE__->mk_classdata($_) for qw/dispatcher engine log/;
fc7ec1d9 12
367d15f8 13our $VERSION = '5.20';
fc7ec1d9 14our @ISA;
15
16=head1 NAME
17
18Catalyst - The Elegant MVC Web Application Framework
19
20=head1 SYNOPSIS
21
22 # use the helper to start a new application
91864987 23 catalyst.pl MyApp
fc7ec1d9 24 cd MyApp
25
26 # add models, views, controllers
d01df17d 27 script/create.pl model Something
28 script/create.pl view Stuff
29 script/create.pl controller Yada
fc7ec1d9 30
31 # built in testserver
d01df17d 32 script/server.pl
fc7ec1d9 33
34 # command line interface
d01df17d 35 script/test.pl /yada
fc7ec1d9 36
37
fc7ec1d9 38 use Catalyst;
39
40 use Catalyst qw/My::Module My::OtherModule/;
41
42 use Catalyst '-Debug';
43
44 use Catalyst qw/-Debug -Engine=CGI/;
45
5a8ed4fe 46 sub default : Private { $_[1]->res->output('Hello') } );
47
e3dc9d78 48 sub index : Path('/index.html') {
5a8ed4fe 49 my ( $self, $c ) = @_;
50 $c->res->output('Hello');
064834ea 51 $c->forward('foo');
5a8ed4fe 52 }
53
064834ea 54 sub product : Regex('^product[_]*(\d*).html$') {
5a8ed4fe 55 my ( $self, $c ) = @_;
56 $c->stash->{template} = 'product.tt';
57 $c->stash->{product} = $c->req->snippets->[0];
58 }
fc7ec1d9 59
3803e98f 60See also L<Catalyst::Manual::Intro>
61
fc7ec1d9 62=head1 DESCRIPTION
63
64Catalyst is based upon L<Maypole>, which you should consider for smaller
65projects.
66
67The key concept of Catalyst is DRY (Don't Repeat Yourself).
68
69See L<Catalyst::Manual> for more documentation.
70
23f9d934 71Catalyst plugins can be loaded by naming them as arguments to the "use Catalyst" statement.
1985c30b 72Omit the C<Catalyst::Plugin::> prefix from the plugin name,
23f9d934 73so C<Catalyst::Plugin::My::Module> becomes C<My::Module>.
fc7ec1d9 74
75 use Catalyst 'My::Module';
76
23f9d934 77Special flags like -Debug and -Engine can also be specifed as arguments when
78Catalyst is loaded:
fc7ec1d9 79
80 use Catalyst qw/-Debug My::Module/;
81
23f9d934 82The position of plugins and flags in the chain is important, because they are
83loaded in exactly the order that they appear.
fc7ec1d9 84
23f9d934 85The following flags are supported:
86
87=over 4
88
89=item -Debug
90
91enables debug output, i.e.:
fc7ec1d9 92
93 use Catalyst '-Debug';
94
23f9d934 95this is equivalent to:
fc7ec1d9 96
97 use Catalyst;
98 sub debug { 1 }
99
23f9d934 100=item -Engine
fc7ec1d9 101
102Force Catalyst to use a specific engine.
23f9d934 103Omit the C<Catalyst::Engine::> prefix of the engine name, i.e.:
fc7ec1d9 104
105 use Catalyst '-Engine=CGI';
106
23f9d934 107=back
fc7ec1d9 108
23f9d934 109=head1 METHODS
110
111=over 4
112
113=item debug
fc7ec1d9 114
115Overload to enable debug messages.
116
117=cut
118
119sub debug { 0 }
120
23f9d934 121=item config
fc7ec1d9 122
123Returns a hashref containing your applications settings.
124
125=cut
126
fc7ec1d9 127sub import {
128 my ( $self, @options ) = @_;
129 my $caller = caller(0);
130
99fe1710 131 # Prepare inheritance
22402712 132 unless ( $caller->isa($self) ) {
fc7ec1d9 133 no strict 'refs';
22402712 134 push @{"$caller\::ISA"}, $self;
1c99e125 135 }
136
d96e14c2 137 if ( $caller->engine ) {
42a57832 138 return; # Catalyst is already initialized
d96e14c2 139 }
140
32620e3e 141 unless ( $caller->log ) {
142 $caller->log( Catalyst::Log->new );
fc7ec1d9 143 }
fc7ec1d9 144
99fe1710 145 # Debug?
1985c30b 146 if ( $ENV{CATALYST_DEBUG} || $ENV{ uc($caller) . '_DEBUG' } ) {
147 no strict 'refs';
148 *{"$caller\::debug"} = sub { 1 };
149 $caller->log->debug('Debug messages enabled');
150 }
151
424b2705 152 my $engine = 'Catalyst::Engine::CGI';
153 my $dispatcher = 'Catalyst::Dispatcher';
6dc87a0f 154
99fe1710 155 # Detect mod_perl
6dc87a0f 156 if ( $ENV{MOD_PERL} ) {
157
158 require mod_perl;
159
ceb7ed54 160 if ( $ENV{MOD_PERL_API_VERSION} == 2 ) {
300aea89 161 $engine = 'Catalyst::Engine::Apache::MP20';
162 }
163 elsif ( $mod_perl::VERSION >= 1.99 ) {
111728e3 164 $engine = 'Catalyst::Engine::Apache::MP19';
6dc87a0f 165 }
166 else {
111728e3 167 $engine = 'Catalyst::Engine::Apache::MP13';
6dc87a0f 168 }
169 }
1985c30b 170
300aea89 171 $caller->log->info( "You are running an old helper script! "
172 . "Please update your scripts by regenerating the "
173 . "application and copying over the new scripts." )
174 if ( $ENV{CATALYST_SCRIPT_GEN}
87232381 175 && ( $ENV{CATALYST_SCRIPT_GEN} < $CATALYST_SCRIPT_GEN ) );
300aea89 176
99fe1710 177 # Process options
937fcdd8 178 my @plugins;
fc7ec1d9 179 foreach (@options) {
99fe1710 180
fc7ec1d9 181 if (/^\-Debug$/) {
1985c30b 182 next if $caller->debug;
fc7ec1d9 183 no strict 'refs';
1c99e125 184 *{"$caller\::debug"} = sub { 1 };
fc7ec1d9 185 $caller->log->debug('Debug messages enabled');
186 }
99fe1710 187
424b2705 188 elsif (/^-Dispatcher=(.*)$/) {
189 $dispatcher = "Catalyst::Dispatcher::$1";
190 }
99fe1710 191
fc7ec1d9 192 elsif (/^-Engine=(.*)$/) { $engine = "Catalyst::Engine::$1" }
193 elsif (/^-.*$/) { $caller->log->error(qq/Unknown flag "$_"/) }
99fe1710 194
fc7ec1d9 195 else {
196 my $plugin = "Catalyst::Plugin::$_";
197
c4695f3a 198 $plugin->require;
91dc9907 199
f88238ea 200 if ($@) { die qq/Couldn't load plugin "$plugin", "$@"/ }
fc7ec1d9 201 else {
f5f84847 202 push @plugins, $plugin;
502619e5 203 no strict 'refs';
204 push @{"$caller\::ISA"}, $plugin;
fc7ec1d9 205 }
206 }
99fe1710 207
fc7ec1d9 208 }
99fe1710 209
210 # Plugin table
d2d570d4 211 my $t = Text::ASCIITable->new( { hide_HeadRow => 1, hide_HeadLine => 1 } );
0f7ecc53 212 $t->setCols('Class');
0822f9a4 213 $t->setColWidth( 'Class', 75, 1 );
cd677e12 214 $t->addRow($_) for @plugins;
0f7ecc53 215 $caller->log->debug( 'Loaded plugins', $t->draw )
937fcdd8 216 if ( @plugins && $caller->debug );
fc7ec1d9 217
424b2705 218 # Dispatcher
219 $dispatcher = "Catalyst::Dispatcher::$ENV{CATALYST_DISPATCHER}"
220 if $ENV{CATALYST_DISPATCHER};
367d15f8 221 my $appdis = $ENV{ uc($caller) . '_DISPATCHER' };
222 $dispatcher = "Catalyst::Dispatcher::$appdis" if $appdis;
424b2705 223
224 $dispatcher->require;
225 die qq/Couldn't load dispatcher "$dispatcher", "$@"/ if $@;
226 {
227 no strict 'refs';
228 push @{"$caller\::ISA"}, $dispatcher;
229 }
230 $caller->dispatcher($dispatcher);
231 $caller->log->debug(qq/Loaded dispatcher "$dispatcher"/) if $caller->debug;
232
e8bf1b2d 233 # Engine
234 $engine = "Catalyst::Engine::$ENV{CATALYST_ENGINE}"
235 if $ENV{CATALYST_ENGINE};
367d15f8 236 my $appeng = $ENV{ uc($caller) . '_ENGINE' };
237 $engine = "Catalyst::Engine::$appeng" if $appeng;
e8bf1b2d 238
239 $engine->require;
240 die qq/Couldn't load engine "$engine", "$@"/ if $@;
241 {
242 no strict 'refs';
243 push @{"$caller\::ISA"}, $engine;
244 }
245 $caller->engine($engine);
246 $caller->log->debug(qq/Loaded engine "$engine"/) if $caller->debug;
4f6748f1 247
248 # Find home
249 my $name = $caller;
250 $name =~ s/\:\:/\//g;
75aeff23 251 my $home;
252 if ( my $path = $INC{"$name.pm"} ) {
253 $home = file($path)->absolute->dir;
254 $name =~ /(\w+)$/;
255 my $append = $1;
256 my $subdir = dir($home)->subdir($append);
257 for ( split '/', $name ) { $home = dir($home)->parent }
258 if ( $home =~ /blib$/ ) { $home = dir($home)->parent }
259 elsif ( !-f file( $home, 'Makefile.PL' ) ) { $home = $subdir }
260 }
4f6748f1 261
262 if ( $caller->debug ) {
263 $home
264 ? ( -d $home )
265 ? $caller->log->debug(qq/Found home "$home"/)
266 : $caller->log->debug(qq/Home "$home" doesn't exist/)
267 : $caller->log->debug(q/Couldn't find home/);
268 }
75aeff23 269 $caller->config->{home} = $home || '';
270 $caller->config->{root} = defined $home ? dir($home)->subdir('root') : '';
fc7ec1d9 271}
272
70cb38f0 273=item $c->engine
274
275Contains the engine class.
276
145074c2 277=item $c->log
278
279Contains the logging object. Unless it is already set Catalyst sets this up with a
280C<Catalyst::Log> object. To use your own log class:
281
282 $c->log( MyLogger->new );
283 $c->log->info("now logging with my own logger!");
284
285Your log class should implement the methods described in the C<Catalyst::Log>
286man page.
287
87232381 288=item $c->plugin( $name, $class, @args )
289
290Instant plugins for Catalyst.
291Classdata accessor/mutator will be created, class loaded and instantiated.
292
293 MyApp->plugin( 'prototype', 'HTML::Prototype' );
294
295 $c->prototype->define_javascript_functions;
296
297=cut
298
299sub plugin {
300 my ( $class, $name, $plugin, @args ) = @_;
301 $plugin->require;
302 my $error = $UNIVERSAL::require::ERROR;
303 die qq/Couldn't load instant plugin "$plugin", "$error"/ if $error;
304 eval { $plugin->import };
305 $class->mk_classdata($name);
306 my $obj;
307 eval { $obj = $plugin->new(@args) };
308 die qq/Couldn't instantiate instant plugin "$plugin", "$@"/ if $@;
309 $class->$name($obj);
310 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
311 if $class->debug;
312}
145074c2 313
23f9d934 314=back
315
d1a31ac6 316=head1 LIMITATIONS
317
b2b7d352 318mod_perl2 support is considered experimental and may contain bugs.
d1a31ac6 319
3cb1db8c 320=head1 SUPPORT
321
322IRC:
323
324 Join #catalyst on irc.perl.org.
325
326Mailing-Lists:
327
328 http://lists.rawmode.org/mailman/listinfo/catalyst
329 http://lists.rawmode.org/mailman/listinfo/catalyst-dev
1985c30b 330
432d507d 331Web:
332
333 http://catalyst.perl.org
334
fc7ec1d9 335=head1 SEE ALSO
336
61b1e958 337=over 4
338
339=item L<Catalyst::Manual> - The Catalyst Manual
340
341=item L<Catalyst::Engine> - Core Engine
342
343=item L<Catalyst::Log> - The Log Class.
344
345=item L<Catalyst::Request> - The Request Object
346
347=item L<Catalyst::Response> - The Response Object
348
349=item L<Catalyst::Test> - The test suite.
350
351=back
fc7ec1d9 352
353=head1 AUTHOR
354
355Sebastian Riedel, C<sri@oook.de>
356
357=head1 THANK YOU
358
84cf74e7 359Andy Grundman, Andrew Ford, Andrew Ruthven, Autrijus Tang, Christian Hansen,
ce2b098c 360Christopher Hicks, Dan Sully, Danijel Milicevic, David Naughton,
75aeff23 361Gary Ashton Jones, Geoff Richards, Jesse Sheidlower, Jody Belka,
362Johan Lindstrom, Leon Brocard, Marcus Ramberg, Tatsuhiko Miyagawa
363and all the others who've helped.
fc7ec1d9 364
365=head1 LICENSE
366
367This library is free software . You can redistribute it and/or modify it under
368the same terms as perl itself.
369
370=cut
371
3721;