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