more docs
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Helper.pm
CommitLineData
fc7ec1d9 1package Catalyst::Helper;
2
3use strict;
4use base 'Class::Accessor::Fast';
5use File::Spec;
6use File::Path;
7use IO::File;
8use FindBin;
9
10=head1 NAME
11
12Catalyst::Helper - Bootstrap a Catalyst application
13
14=head1 SYNOPSIS
15
16See L<Catalyst::Manual::Intro>
17
18=head1 DESCRIPTION
19
20Bootstrap a Catalyst application.
21
22=head2 METHODS
23
24=head3 mk_app
25
26=cut
27
28sub mk_app {
29 my ( $self, $name ) = @_;
30 return 0 if $name =~ /[^\w\:]/;
31 $self->{name} = $name;
32 $self->{dir} = $name;
33 $self->{dir} =~ s/\:\:/-/g;
34 $self->_mk_dirs;
35 $self->_mk_appclass;
36 $self->_mk_makefile;
37 $self->_mk_apptest;
38 $self->_mk_server;
39 $self->_mk_test;
40 $self->_mk_create;
41 return 1;
42}
43
44sub _mk_dirs {
45 my $self = shift;
46 mkpath $self->{dir} unless -d $self->{dir};
47 $self->{bin} = File::Spec->catdir( $self->{dir}, 'bin' );
48 mkpath $self->{bin};
49 $self->{lib} = File::Spec->catdir( $self->{dir}, 'lib' );
50 mkpath $self->{lib};
51 $self->{root} = File::Spec->catdir( $self->{dir}, 'root' );
52 mkpath $self->{root};
53 $self->{t} = File::Spec->catdir( $self->{dir}, 't' );
54 mkpath $self->{t};
55 $self->{class} = File::Spec->catdir( split( /\:\:/, $self->{name} ) );
56 $self->{mod} = File::Spec->catdir( $self->{lib}, $self->{class} );
57 mkpath $self->{mod};
58 $self->{m} = File::Spec->catdir( $self->{mod}, 'M' );
59 mkpath $self->{m};
60 $self->{v} = File::Spec->catdir( $self->{mod}, 'V' );
61 mkpath $self->{v};
62 $self->{c} = File::Spec->catdir( $self->{mod}, 'C' );
63 mkpath $self->{c};
64 $self->{base} = File::Spec->rel2abs( $self->{dir} );
65}
66
67sub _mk_appclass {
68 my $self = shift;
69 my $mod = $self->{mod};
70 my $name = $self->{name};
71 my $base = $self->{base};
72 my $class = IO::File->new("> $mod.pm")
73 or die qq/Couldn't open "$mod.pm", "$!"/;
74 print $class <<"EOF";
75package $name;
76
77use strict;
78use Catalyst qw/-Debug/;
79
80our \$VERSION = '0.01';
81
82$name->config(
83 name => '$name',
84 root => '$base/root',
85);
86
87$name->action(
88
89 '!default' => sub {
90 my ( \$self, \$c ) = \@_;
91 \$c->res->output('Congratulations, $name is on Catalyst!');
92 },
93
94);
95
96=head1 NAME
97
98$name - A very nice application
99
100=head1 SYNOPSIS
101
102 Very simple to use
103
104=head1 DESCRIPTION
105
106Very nice application.
107
108=head1 AUTHOR
109
110Clever guy
111
112=head1 LICENSE
113
114This library is free software . You can redistribute it and/or modify it under
115the same terms as perl itself.
116
117=cut
118
1191;
120EOF
121}
122
123sub _mk_makefile {
124 my $self = shift;
125 my $name = $self->{name};
126 my $dir = $self->{dir};
127 my $class = $self->{class};
128 my $makefile = IO::File->new("> $dir/Makefile.PL")
129 or die qq/Couldn't open "$dir\/Makefile.PL", "$!"/;
130 print $makefile <<"EOF";
131use ExtUtils::MakeMaker;
132
133WriteMakefile(
134 NAME => '$name',
135 VERSION_FROM => 'lib/$class.pm',
136 PREREQ_PM => { Catalyst => 0 }
137);
138EOF
139}
140
141sub _mk_apptest {
142 my $self = shift;
143 my $t = $self->{t};
144 my $name = $self->{name};
145 my $test = IO::File->new("> $t/01app.t")
146 or die qq/Couldn't open "$t\/01app.t", "$!"/;
147 print $test <<"EOF";
148use Test::More tests => 2;
149use_ok( Catalyst::Test, '$name' );
150
151ok( request('/')->is_success );
152EOF
1df125c9 153 my $pc = IO::File->new("> $t/02podcoverage.t")
154 or die qq/Couldn't open "$t\/02podcoverage.t", "$!"/;
155 print $pc <<"EOF";
156use Test::More;
157
158eval "use Test::Pod::Coverage 1.04";
159plan skip_all => 'Test::Pod::Coverage 1.04 required' if \$@;
160plan skip_all => 'set TEST_POD to enable this test' unless \$ENV{TEST_POD};
161
162all_pod_coverage_ok();
163EOF
fc7ec1d9 164}
165
166sub _mk_server {
167 my $self = shift;
168 my $name = $self->{name};
169 my $bin = $self->{bin};
170 my $server = IO::File->new("> $bin/server")
171 or die qq/Could't open "$bin\/server", "$!"/;
172 print $server <<"EOF";
173#!/usr/bin/perl -w
174
175use strict;
176use Getopt::Long;
177use Pod::Usage;
178use FindBin;
179use lib "\$FindBin::Bin/../lib";
180use Catalyst::Test '$name';
181
182my \$help = 0;
183my \$port = 3000;
184
185GetOptions( 'help|?' => \\\$help, 'port=s' => \\\$port );
186
187pod2usage(1) if \$help;
188
189Catalyst::Test::server(\$port);
190
1911;
192__END__
193
194=head1 NAME
195
196server - Catalyst Testserver
197
198=head1 SYNOPSIS
199
200server [options]
201
202 Options:
203 -help display this help and exits
204 -port port (defaults to 3000)
205
03a53815 206 See also:
207 perldoc Catalyst::Manual
208 perldoc Catalyst::Manual::Intro
209
fc7ec1d9 210=head1 DESCRIPTION
211
212Run a Catalyst Testserver for this application.
213
214=head1 AUTHOR
215
216Sebastian Riedel, C<sri\@oook.de>
217
218=head1 COPYRIGHT
219
220Copyright 2004 Sebastian Riedel. All rights reserved.
221
222This library is free software. You can redistribute it and/or modify it under
223the same terms as perl itself.
224
225=cut
226EOF
227 chmod 0700, "$bin/server";
228}
229
230sub _mk_test {
231 my $self = shift;
232 my $name = $self->{name};
233 my $bin = $self->{bin};
234 my $test = IO::File->new("> $bin/test")
235 or die qq/Could't open "$bin\/test", "$!"/;
236 print $test <<"EOF";
237#!/usr/bin/perl -w
238
239use strict;
240use Getopt::Long;
241use Pod::Usage;
242use FindBin;
243use lib "\$FindBin::Bin/../lib";
244
245my \$help = 0;
246
247GetOptions( 'help|?' => \\\$help );
248
249pod2usage(1) if ( \$help || !\$ARGV[0] );
250
251require Catalyst::Test;
252import Catalyst::Test '$name';
253
254print get(\$ARGV[0]) . "\n";
255
2561;
257__END__
258
259=head1 NAME
260
261test - Catalyst Test
262
263=head1 SYNOPSIS
264
265test [options] uri
266
267 Options:
268 -help display this help and exits
269
270 Examples:
d7c505f3 271 perl test http://localhost/some_action
272 perl test /some_action
fc7ec1d9 273
03a53815 274 See also:
275 perldoc Catalyst::Manual
276 perldoc Catalyst::Manual::Intro
277
fc7ec1d9 278=head1 DESCRIPTION
279
280Run a Catalyst action from the comand line.
281
282=head1 AUTHOR
283
284Sebastian Riedel, C<sri\@oook.de>
285
286=head1 COPYRIGHT
287
288Copyright 2004 Sebastian Riedel. All rights reserved.
289
290This library is free software. You can redistribute it and/or modify it under
291the same terms as perl itself.
292
293=cut
294EOF
295 chmod 0700, "$bin/test";
296}
297
298sub _mk_create {
299 my $self = shift;
300 my $name = $self->{name};
301 my $bin = $self->{bin};
302 my $create = IO::File->new("> $bin/create")
303 or die qq/Could't open "$bin\/create", "$!"/;
304 print $create <<"EOF";
305#!/usr/bin/perl -w
306
307use strict;
308use Getopt::Long;
309use Pod::Usage;
310use Catalyst::Helper;
311
312my \$help = 0;
313
314GetOptions( 'help|?' => \$help );
315
316pod2usage(1) if ( \$help || !\$ARGV[1] );
317
318my \$helper = Catalyst::Helper->new;
319pod2usage(1) unless \$helper->mk_component( '$name', \@ARGV );
320
3211;
322__END__
323
324=head1 NAME
325
326create - Create a new Catalyst Component
327
328=head1 SYNOPSIS
329
03a53815 330create [options] model|view|controller name [helper] [options]
fc7ec1d9 331
332 Options:
333 -help display this help and exits
334
335 Examples:
d7c505f3 336 perl create controller My::Controller
337 perl create view My::View
338 perl create view MyView TT
339 perl create view TT TT
340 perl create model My::Model
341 perl create model SomeDB CDBI dbi:SQLite:/tmp/my.db
342 perl create model AnotherDB CDBI dbi:Pg:dbname=foo root 4321
03a53815 343
344 See also:
345 perldoc Catalyst::Manual
346 perldoc Catalyst::Manual::Intro
fc7ec1d9 347
348=head1 DESCRIPTION
349
350Create a new Catalyst Component.
351
352=head1 AUTHOR
353
354Sebastian Riedel, C<sri\@oook.de>
355
356=head1 COPYRIGHT
357
358Copyright 2004 Sebastian Riedel. All rights reserved.
359
360This library is free software. You can redistribute it and/or modify it under
361the same terms as perl itself.
362
363=cut
364EOF
365 chmod 0700, "$bin/create";
366}
367
368=head3 mk_component
369
370=cut
371
372sub mk_component {
373 my ( $self, $app, $type, $name, $helper, @args ) = @_;
374 return 0
375 if ( $name =~ /[^\w\:]/ || !\$type =~ /^model|m|view|v|controller|c\$/i );
376 return 0 if $name =~ /[^\w\:]/;
377 $type = 'M' if $type =~ /model|m/i;
378 $type = 'V' if $type =~ /view|v/i;
379 $type = 'C' if $type =~ /controller|c/i;
380 $self->{type} = $type;
381 $self->{name} = $name;
382 $self->{class} = "$app\::$type\::$name";
383 $self->{app} = $app;
384
385 # Class
386 my $appdir = File::Spec->catdir( split /\:\:/, $app );
387 my $path = File::Spec->catdir( $FindBin::Bin, '..', 'lib', $appdir, $type );
388 my $file = $name;
389 if ( $name =~ /\:/ ) {
390 my @path = split /\:\:/, $name;
391 $file = pop @path;
392 $path = File::Spec->catdir( $path, @path );
393 mkpath $path;
394 }
395 $file = File::Spec->catfile( $path, "$file.pm" );
396 $self->{file} = $file;
397
398 # Test
399 my $dir = File::Spec->catdir( $FindBin::Bin, '..', 't' );
400 my $num = '01';
401 for my $i (<$dir/*.t>) {
402 $i =~ /(\d+)[^\/]*.t$/;
403 my $j = $1 || $num;
404 $num = $j if $j > $num;
405 }
406 $num++;
407 $num = sprintf '%02d', $num;
408 my $prefix = $name;
409 $prefix =~ s/::/_/g;
410 $prefix = lc $prefix;
411 my $tname = lc( $num . $type . '_' . $prefix . '.t' );
412 $self->{prefix} = $prefix;
413 $self->{test_dir} = $dir;
414 $self->{test} = "$dir/$tname";
415
416 # Helper
417 if ($helper) {
418 my $comp = 'Model';
419 $comp = 'View' if $type eq 'V';
420 $comp = 'Controller' if $type eq 'C';
421 my $class = "Catalyst::Helper::$comp\::$helper";
422 eval "require $class";
423 die qq/Couldn't load helper "$class", "$@"/ if $@;
424 if ( $class->can('mk_compclass') ) {
425 $class->mk_compclass( $self, @args );
426 }
427 else { $self->_mk_compclass }
428
429 if ( $class->can('mk_comptest') ) {
430 $class->mk_comptest( $self, @args );
431 }
432 else { $self->_mk_comptest }
433 }
434
435 # Fallback
436 else {
437 $self->_mk_compclass;
438 $self->_mk_comptest;
439 }
440 return 1;
441}
442
443sub _mk_compclass {
444 my $self = shift;
445 my $app = $self->{app};
446 my $class = $self->{class};
447 my $type = $self->{type};
448 my $action = '';
449 $action = <<"EOF" if $type eq 'C';
450
451$app->action(
452
453 '!?default' => sub {
454 my ( \$self, \$c ) = \@_;
455 \$c->res->output('Congratulations, $class is on Catalyst!');
456 },
457
458);
459EOF
460 my $file = $self->{file};
461 my $comp = IO::File->new("> $file")
462 or die qq/Couldn't open "$file", "$!"/;
463 print $comp <<"EOF";
464package $class;
465
466use strict;
467use base 'Catalyst::Base';
468$action
469=head1 NAME
470
471$class - A Component
472
473=head1 SYNOPSIS
474
475 Very simple to use
476
477=head1 DESCRIPTION
478
479Very nice component.
480
481=head1 AUTHOR
482
483Clever guy
484
485=head1 LICENSE
486
487This library is free software . You can redistribute it and/or modify it under
488the same terms as perl itself.
489
490=cut
491
4921;
493EOF
494}
495
496sub _mk_comptest {
497 my $self = shift;
498 my $prefix = $self->{prefix};
499 my $type = $self->{type};
500 my $class = $self->{class};
501 my $app = $self->{app};
502 my $test = $self->{test};
503 my $t = IO::File->new("> $test") or die qq/Couldn't open "$test", "$!"/;
504
505 if ( $self->{type} eq 'C' ) {
506 print $t <<"EOF";
507use Test::More tests => 3;
508use_ok( Catalyst::Test, '$app' );
509use_ok('$class');
510
511ok( request('$prefix')->is_success );
512EOF
513 }
514 else {
515 print $t <<"EOF";
516use Test::More tests => 1;
517use_ok('$class');
518EOF
519 }
520}
521
7833fdfc 522=head1 HELPERS
523
524Helpers are classes that provide two methods.
525
526 * mk_compclass - creates the Component class
527 * mk_comptest - creates the Component test
528
529So when you call C<bin/create view MyView TT>, create would try to execute
530Catalyst::Helper::View::TT->mk_compclass and
531Catalyst::Helper::View::TT->mk_comptest.
532
533See L<Catalyst::Helper::View::TT> and L<Catalyst::Helper::Model::CDBI> for
534examples.
535
536All helper classes should be under one of the following namespaces.
537
538 Catalyst::Helper::Model::
539 Catalyst::Helper::View::
540 Catalyst::Helper::Controller::
541
fc7ec1d9 542=head1 SEE ALSO
543
544L<Catalyst::Manual>, L<Catalyst::Test>, L<Catalyst::Request>,
545L<Catalyst::Response>, L<Catalyst>
546
547=head1 AUTHOR
548
549Sebastian Riedel, C<sri@oook.de>
550
551=head1 LICENSE
552
553This library is free software . You can redistribute it and/or modify it under
554the same terms as perl itself.
555
556=cut
557
5581;