Delete crap
[catagits/Catalyst-Devel.git] / lib / Catalyst / Helper.pm
CommitLineData
68ccb5e5 1package Catalyst::Helper;
2
3use strict;
c93c671b 4use warnings;
b8dea4e7 5use base 'Class::Accessor::Fast';
68ccb5e5 6use Config;
7use File::Spec;
8use File::Path;
68ccb5e5 9use FindBin;
2415f774 10use IO::File;
11use POSIX 'strftime';
68ccb5e5 12use Template;
9ffb6b83 13use Catalyst::Devel;
68ccb5e5 14use Catalyst::Utils;
15use Catalyst::Exception;
afd739f1 16use Path::Class qw/dir file/;
17use File::ShareDir qw/dist_dir/;
239b5fc0 18use Moose;
19use aliased 'Path::Class::Dir';
20
68ccb5e5 21
22my %cache;
23
24=head1 NAME
25
26Catalyst::Helper - Bootstrap a Catalyst application
27
28=head1 SYNOPSIS
29
fab70e0a 30 catalyst.pl <myappname>
68ccb5e5 31
32=cut
33
faae88e5 34
35
afd739f1 36sub get_sharedir_file {
37 my ($self, @filename) = @_;
76b106bc 38 my $dist_dir;
39 if (-d "inc/.author") { # Can't use sharedir if we're in a checkout
40 # this feels horrible, better ideas?
41 $dist_dir = 'share';
42 }
43 else {
44 $dist_dir = dist_dir('Catalyst-Devel');
45 }
46 my $file = file( $dist_dir, @filename);
afd739f1 47 my $contents = $file->slurp;
48 return $contents;
49}
50
faae88e5 51# Do not touch this method, *EVER*, it is needed for back compat.
68ccb5e5 52sub get_file {
03082a71 53 my ( $self, $class, $file ) = @_;
54 unless ( $cache{$class} ) {
55 local $/;
56 $cache{$class} = eval "package $class; <DATA>";
57 }
58 my $data = $cache{$class};
0acedf59 59 Carp::confess("Could not get data from __DATA__ segment for $class")
60 unless $data;
03082a71 61 my @files = split /^__(.+)__\r?\n/m, $data;
62 shift @files;
63 while (@files) {
64 my ( $name, $content ) = splice @files, 0, 2;
65 return $content if $name eq $file;
66 }
67 return 0;
68ccb5e5 68}
69
03082a71 70
68ccb5e5 71sub mk_app {
72 my ( $self, $name ) = @_;
73
74 # Needs to be here for PAR
75 require Catalyst;
76
555cab18 77 if ( $name =~ /[^\w:]/ || $name =~ /^\d/ || $name =~ /\b:\b|:{3,}/) {
68ccb5e5 78 warn "Error: Invalid application name.\n";
79 return 0;
80 }
902763f2 81 $self->{name } = $name;
82 $self->{dir } = $name;
83 $self->{dir } =~ s/\:\:/-/g;
84 $self->{script } = File::Spec->catdir( $self->{dir}, 'script' );
85 $self->{appprefix } = Catalyst::Utils::appprefix($name);
e9345225 86 $self->{appenv } = Catalyst::Utils::class2env($name);
675fef06 87 $self->{startperl } = -r '/usr/bin/env'
88 ? '#!/usr/bin/env perl'
9bc8b354 89 : "#!$Config{perlpath} -w";
9ffb6b83 90 $self->{scriptgen } = $Catalyst::Devel::CATALYST_SCRIPT_GEN || 4;
902763f2 91 $self->{catalyst_version} = $Catalyst::VERSION;
92 $self->{author } = $self->{author} = $ENV{'AUTHOR'}
68ccb5e5 93 || eval { @{ [ getpwuid($<) ] }[6] }
94 || 'Catalyst developer';
95
96 my $gen_scripts = ( $self->{makefile} ) ? 0 : 1;
97 my $gen_makefile = ( $self->{scripts} ) ? 0 : 1;
98 my $gen_app = ( $self->{scripts} || $self->{makefile} ) ? 0 : 1;
99
100 if ($gen_app) {
101 $self->_mk_dirs;
102 $self->_mk_config;
103 $self->_mk_appclass;
104 $self->_mk_rootclass;
105 $self->_mk_readme;
106 $self->_mk_changes;
107 $self->_mk_apptest;
108 $self->_mk_images;
109 $self->_mk_favicon;
110 }
111 if ($gen_makefile) {
112 $self->_mk_makefile;
113 }
114 if ($gen_scripts) {
115 $self->_mk_cgi;
116 $self->_mk_fastcgi;
117 $self->_mk_server;
118 $self->_mk_test;
119 $self->_mk_create;
45d74601 120 $self->_mk_information;
68ccb5e5 121 }
122 return $self->{dir};
123}
124
68ccb5e5 125sub mk_component {
126 my $self = shift;
127 my $app = shift;
128 $self->{app} = $app;
129 $self->{author} = $self->{author} = $ENV{'AUTHOR'}
130 || eval { @{ [ getpwuid($<) ] }[6] }
131 || 'A clever guy';
132 $self->{base} ||= File::Spec->catdir( $FindBin::Bin, '..' );
133 unless ( $_[0] =~ /^(?:model|view|controller)$/i ) {
134 my $helper = shift;
135 my @args = @_;
136 my $class = "Catalyst::Helper::$helper";
137 eval "require $class";
138
139 if ($@) {
140 Catalyst::Exception->throw(
141 message => qq/Couldn't load helper "$class", "$@"/ );
142 }
143
144 if ( $class->can('mk_stuff') ) {
145 return 1 unless $class->mk_stuff( $self, @args );
146 }
147 }
148 else {
149 my $type = shift;
150 my $name = shift || "Missing name for model/view/controller";
151 my $helper = shift;
152 my @args = @_;
fab70e0a 153 return 0 if $name =~ /[^\w\:]/;
68ccb5e5 154 $type = lc $type;
155 $self->{long_type} = ucfirst $type;
156 $type = 'M' if $type =~ /model/i;
157 $type = 'V' if $type =~ /view/i;
158 $type = 'C' if $type =~ /controller/i;
159 my $appdir = File::Spec->catdir( split /\:\:/, $app );
160 my $test_path =
161 File::Spec->catdir( $FindBin::Bin, '..', 'lib', $appdir, 'C' );
162 $type = $self->{long_type} unless -d $test_path;
163 $self->{type} = $type;
164 $self->{name} = $name;
165 $self->{class} = "$app\::$type\::$name";
166
167 # Class
168 my $path =
169 File::Spec->catdir( $FindBin::Bin, '..', 'lib', $appdir, $type );
170 my $file = $name;
171 if ( $name =~ /\:/ ) {
172 my @path = split /\:\:/, $name;
173 $file = pop @path;
174 $path = File::Spec->catdir( $path, @path );
175 }
176 $self->mk_dir($path);
177 $file = File::Spec->catfile( $path, "$file.pm" );
178 $self->{file} = $file;
179
180 # Test
181 $self->{test_dir} = File::Spec->catdir( $FindBin::Bin, '..', 't' );
182 $self->{test} = $self->next_test;
183
184 # Helper
185 if ($helper) {
186 my $comp = $self->{long_type};
187 my $class = "Catalyst::Helper::$comp\::$helper";
188 eval "require $class";
189
190 if ($@) {
191 Catalyst::Exception->throw(
192 message => qq/Couldn't load helper "$class", "$@"/ );
193 }
194
195 if ( $class->can('mk_compclass') ) {
196 return 1 unless $class->mk_compclass( $self, @args );
197 }
198 else { return 1 unless $self->_mk_compclass }
199
200 if ( $class->can('mk_comptest') ) {
201 $class->mk_comptest( $self, @args );
202 }
203 else { $self->_mk_comptest }
204 }
205
206 # Fallback
207 else {
208 return 1 unless $self->_mk_compclass;
209 $self->_mk_comptest;
210 }
211 }
212 return 1;
213}
214
68ccb5e5 215sub mk_dir {
216 my ( $self, $dir ) = @_;
217 if ( -d $dir ) {
218 print qq/ exists "$dir"\n/;
219 return 0;
220 }
221 if ( mkpath [$dir] ) {
222 print qq/created "$dir"\n/;
223 return 1;
224 }
225
226 Catalyst::Exception->throw( message => qq/Couldn't create "$dir", "$!"/ );
227}
228
68ccb5e5 229sub mk_file {
230 my ( $self, $file, $content ) = @_;
06f62452 231 if ( -e $file && -s _ ) {
68ccb5e5 232 print qq/ exists "$file"\n/;
233 return 0
234 unless ( $self->{'.newfiles'}
235 || $self->{scripts}
236 || $self->{makefile} );
237 if ( $self->{'.newfiles'} ) {
238 if ( my $f = IO::File->new("< $file") ) {
239 my $oldcontent = join( '', (<$f>) );
240 return 0 if $content eq $oldcontent;
241 }
242 $file .= '.new';
243 }
244 }
245 if ( my $f = IO::File->new("> $file") ) {
246 binmode $f;
247 print $f $content;
248 print qq/created "$file"\n/;
249 return 1;
250 }
251
252 Catalyst::Exception->throw( message => qq/Couldn't create "$file", "$!"/ );
253}
254
68ccb5e5 255sub next_test {
256 my ( $self, $tname ) = @_;
257 if ($tname) { $tname = "$tname.t" }
258 else {
259 my $name = $self->{name};
260 my $prefix = $name;
261 $prefix =~ s/::/-/g;
262 $prefix = $prefix;
263 $tname = $prefix . '.t';
264 $self->{prefix} = $prefix;
265 $prefix = lc $prefix;
266 $prefix =~ s/-/\//g;
267 $self->{uri} = "/$prefix";
268 }
269 my $dir = $self->{test_dir};
270 my $type = lc $self->{type};
271 $self->mk_dir($dir);
272 return File::Spec->catfile( $dir, "$type\_$tname" );
273}
274
faae88e5 275# Do not touch this method, *EVER*, it is needed for back compat.
7025ed89 276## addendum: we had to split this method so we could have backwards
277## compatability. otherwise, we'd have no way to pass stuff from __DATA__
faae88e5 278
68ccb5e5 279sub render_file {
280 my ( $self, $file, $path, $vars ) = @_;
7025ed89 281 my $template = $self->get_file( ( caller(0) )[0], $file );
06f62452 282 $self->render_file_contents($template, $path, $vars);
7025ed89 283}
284
285sub render_sharedir_file {
286 my ( $self, $file, $path, $vars ) = @_;
287 my $template = $self->get_sharedir_file( $file );
e97273a4 288 $self->render_file_contents($template, $path, $vars);
7025ed89 289}
290
291sub render_file_contents {
292 my ( $self, $template, $path, $vars ) = @_;
68ccb5e5 293 $vars ||= {};
294 my $t = Template->new;
68ccb5e5 295 return 0 unless $template;
296 my $output;
297 $t->process( \$template, { %{$self}, %$vars }, \$output )
298 || Catalyst::Exception->throw(
7025ed89 299 message => qq/Couldn't process "$template", / . $t->error() );
68ccb5e5 300 $self->mk_file( $path, $output );
301}
302
45d74601 303sub _mk_information {
304 my $self = shift;
305 print qq/Change to application directory and Run "perl Makefile.PL" to make sure your install is complete\n/;
306}
307
68ccb5e5 308sub _mk_dirs {
309 my $self = shift;
310 $self->mk_dir( $self->{dir} );
311 $self->mk_dir( $self->{script} );
312 $self->{lib} = File::Spec->catdir( $self->{dir}, 'lib' );
313 $self->mk_dir( $self->{lib} );
314 $self->{root} = File::Spec->catdir( $self->{dir}, 'root' );
315 $self->mk_dir( $self->{root} );
316 $self->{static} = File::Spec->catdir( $self->{root}, 'static' );
317 $self->mk_dir( $self->{static} );
318 $self->{images} = File::Spec->catdir( $self->{static}, 'images' );
319 $self->mk_dir( $self->{images} );
320 $self->{t} = File::Spec->catdir( $self->{dir}, 't' );
321 $self->mk_dir( $self->{t} );
322
323 $self->{class} = File::Spec->catdir( split( /\:\:/, $self->{name} ) );
324 $self->{mod} = File::Spec->catdir( $self->{lib}, $self->{class} );
325 $self->mk_dir( $self->{mod} );
326
327 if ( $self->{short} ) {
328 $self->{m} = File::Spec->catdir( $self->{mod}, 'M' );
329 $self->mk_dir( $self->{m} );
330 $self->{v} = File::Spec->catdir( $self->{mod}, 'V' );
331 $self->mk_dir( $self->{v} );
332 $self->{c} = File::Spec->catdir( $self->{mod}, 'C' );
333 $self->mk_dir( $self->{c} );
334 }
335 else {
336 $self->{m} = File::Spec->catdir( $self->{mod}, 'Model' );
337 $self->mk_dir( $self->{m} );
338 $self->{v} = File::Spec->catdir( $self->{mod}, 'View' );
339 $self->mk_dir( $self->{v} );
340 $self->{c} = File::Spec->catdir( $self->{mod}, 'Controller' );
341 $self->mk_dir( $self->{c} );
342 }
343 my $name = $self->{name};
344 $self->{rootname} =
345 $self->{short} ? "$name\::C::Root" : "$name\::Controller::Root";
346 $self->{base} = File::Spec->rel2abs( $self->{dir} );
347}
348
349sub _mk_appclass {
350 my $self = shift;
351 my $mod = $self->{mod};
0acedf59 352 $self->render_sharedir_file( 'lib/appclass.tt', "$mod.pm" );
68ccb5e5 353}
354
355sub _mk_rootclass {
356 my $self = shift;
0acedf59 357 $self->render_sharedir_file( 'lib/MyApp/Controller/rootclass.tt',
68ccb5e5 358 File::Spec->catfile( $self->{c}, "Root.pm" ) );
359}
360
361sub _mk_makefile {
362 my $self = shift;
363 $self->{path} = File::Spec->catfile( 'lib', split( '::', $self->{name} ) );
364 $self->{path} .= '.pm';
365 my $dir = $self->{dir};
0acedf59 366 $self->render_sharedir_file( 'makefile.tt', "$dir\/Makefile.PL" );
68ccb5e5 367
368 if ( $self->{makefile} ) {
369
370 # deprecate the old Build.PL file when regenerating Makefile.PL
371 $self->_deprecate_file(
372 File::Spec->catdir( $self->{dir}, 'Build.PL' ) );
373 }
374}
375
376sub _mk_config {
377 my $self = shift;
378 my $dir = $self->{dir};
379 my $appprefix = $self->{appprefix};
0acedf59 380 $self->render_sharedir_file( 'config.tt',
a4e6d745 381 File::Spec->catfile( $dir, "$appprefix.conf" ) );
68ccb5e5 382}
383
384sub _mk_readme {
385 my $self = shift;
386 my $dir = $self->{dir};
0acedf59 387 $self->render_sharedir_file( 'readme.tt', "$dir\/README" );
68ccb5e5 388}
389
390sub _mk_changes {
391 my $self = shift;
392 my $dir = $self->{dir};
5b1ec88b 393 my $time = strftime('%Y-%m-%d %H:%M:%S', localtime time);
0acedf59 394 $self->render_sharedir_file( 'changes.tt', "$dir\/Changes", { time => $time } );
68ccb5e5 395}
396
397sub _mk_apptest {
398 my $self = shift;
399 my $t = $self->{t};
0acedf59 400 $self->render_sharedir_file( 't/apptest.tt', "$t\/01app.t" );
401 $self->render_sharedir_file( 't/podtest.tt', "$t\/02pod.t" );
402 $self->render_sharedir_file( 't/podcoveragetest.tt', "$t\/03podcoverage.t" );
68ccb5e5 403}
404
405sub _mk_cgi {
406 my $self = shift;
407 my $script = $self->{script};
408 my $appprefix = $self->{appprefix};
0acedf59 409 $self->render_sharedir_file( 'script/cgi.tt', "$script\/$appprefix\_cgi.pl" );
68ccb5e5 410 chmod 0700, "$script/$appprefix\_cgi.pl";
411}
412
413sub _mk_fastcgi {
414 my $self = shift;
415 my $script = $self->{script};
416 my $appprefix = $self->{appprefix};
0acedf59 417 $self->render_sharedir_file( 'script/fastcgi.tt', "$script\/$appprefix\_fastcgi.pl" );
68ccb5e5 418 chmod 0700, "$script/$appprefix\_fastcgi.pl";
419}
420
421sub _mk_server {
422 my $self = shift;
423 my $script = $self->{script};
424 my $appprefix = $self->{appprefix};
0acedf59 425 $self->render_sharedir_file( 'script/server.tt', "$script\/$appprefix\_server.pl" );
68ccb5e5 426 chmod 0700, "$script/$appprefix\_server.pl";
427}
428
429sub _mk_test {
430 my $self = shift;
431 my $script = $self->{script};
432 my $appprefix = $self->{appprefix};
0acedf59 433 $self->render_sharedir_file( 'script/test.tt', "$script/$appprefix\_test.pl" );
68ccb5e5 434 chmod 0700, "$script/$appprefix\_test.pl";
435}
436
437sub _mk_create {
438 my $self = shift;
439 my $script = $self->{script};
440 my $appprefix = $self->{appprefix};
0acedf59 441 $self->render_sharedir_file( 'script/create.tt', "$script\/$appprefix\_create.pl" );
68ccb5e5 442 chmod 0700, "$script/$appprefix\_create.pl";
443}
444
445sub _mk_compclass {
446 my $self = shift;
447 my $file = $self->{file};
0acedf59 448 return $self->render_sharedir_file( 'compclass.tt', "$file" );
68ccb5e5 449}
450
451sub _mk_comptest {
452 my $self = shift;
453 my $test = $self->{test};
0acedf59 454 $self->render_sharedir_file( 'comptest.tt', "$test" );
68ccb5e5 455}
456
457sub _mk_images {
458 my $self = shift;
459 my $images = $self->{images};
460 my @images =
461 qw/catalyst_logo btn_120x50_built btn_120x50_built_shadow
462 btn_120x50_powered btn_120x50_powered_shadow btn_88x31_built
463 btn_88x31_built_shadow btn_88x31_powered btn_88x31_powered_shadow/;
464 for my $name (@images) {
9e5643df 465 my $image = $self->get_sharedir_file("root", "$name.png");
68ccb5e5 466 $self->mk_file( File::Spec->catfile( $images, "$name.png" ), $image );
467 }
468}
469
470sub _mk_favicon {
471 my $self = shift;
472 my $root = $self->{root};
afd739f1 473 my $favicon = $self->get_sharedir_file( 'root', 'favicon.ico' );
474 my $dest = File::Spec->catfile( $root, "favicon.ico" );
475 $self->mk_file( $dest, $favicon );
68ccb5e5 476
477}
478
479sub _deprecate_file {
480 my ( $self, $file ) = @_;
481 if ( -e $file ) {
482 my $oldcontent;
483 if ( my $f = IO::File->new("< $file") ) {
484 $oldcontent = join( '', (<$f>) );
485 }
486 my $newfile = $file . '.deprecated';
487 if ( my $f = IO::File->new("> $newfile") ) {
488 binmode $f;
489 print $f $oldcontent;
490 print qq/created "$newfile"\n/;
491 unlink $file;
492 print qq/removed "$file"\n/;
493 return 1;
494 }
495 Catalyst::Exception->throw(
496 message => qq/Couldn't create "$file", "$!"/ );
497 }
498}
499
239b5fc0 500
501## this is so you don't have to do make install after every change to test
502sub _find_share_dir {
503 my ($self, $args) = @_;
504 my $share_name = $self->name;
505 if ($share_name =~ s!^/(.*?)/!!) {
506 my $dist = $1;
507 $args->{share_base_dir} = eval {
508 Dir->new(File::ShareDir::dist_dir($dist))
509 ->subdir('share');
510 };
511 if ($@) {
512 # not installed
513 my $file = __FILE__;
514 my $dir = Dir->new(dirname($file));
515 my $share_base;
516 while ($dir->parent) {
517 if (-d $dir->subdir('share') && -d $dir->subdir('share')->subdir('root')) {
518 $share_base = $dir->subdir('share')->subdir('root');
519 last;
520 }
521 $dir = $dir->parent;
522 }
523 confess "could not find sharebase by recursion. ended up at $dir, from $file"
524 unless $share_base;
525 $args->{share_base_dir} = $share_base;
526 }
527 }
528 my $base = $args->{share_base_dir}->subdir($share_name);
529 confess "No such share base directory ${base}"
530 unless -d $base;
531 $self->share_dir($base);
532};
533
534
535
fab70e0a 536=head1 DESCRIPTION
537
538This module is used by B<catalyst.pl> to create a set of scripts for a
539new catalyst application. The scripts each contain documentation and
540will output help on how to use them if called incorrectly or in some
541cases, with no arguments.
542
543It also provides some useful methods for a Helper module to call when
544creating a component. See L</METHODS>.
545
546=head1 SCRIPTS
547
548=head2 _create.pl
549
550Used to create new components for a catalyst application at the
551development stage.
552
553=head2 _server.pl
554
555The catalyst test server, starts an HTTPD which outputs debugging to
556the terminal.
557
558=head2 _test.pl
559
560A script for running tests from the command-line.
561
562=head2 _cgi.pl
563
564Run your application as a CGI.
565
566=head2 _fastcgi.pl
567
568Run the application as a fastcgi app. Either by hand, or call this
569from FastCgiServer in your http server config.
570
68ccb5e5 571=head1 HELPERS
572
fab70e0a 573The L</_create.pl> script creates application components using Helper
574modules. The Catalyst team provides a good number of Helper modules
575for you to use. You can also add your own.
576
68ccb5e5 577Helpers are classes that provide two methods.
578
579 * mk_compclass - creates the Component class
580 * mk_comptest - creates the Component test
581
fab70e0a 582So when you call C<scripts/myapp_create.pl view MyView TT>, create
583will try to execute Catalyst::Helper::View::TT->mk_compclass and
68ccb5e5 584Catalyst::Helper::View::TT->mk_comptest.
585
c4c50c2d 586See L<Catalyst::Helper::View::TT> and
587L<Catalyst::Helper::Model::DBIC::Schema> for examples.
68ccb5e5 588
589All helper classes should be under one of the following namespaces.
590
591 Catalyst::Helper::Model::
592 Catalyst::Helper::View::
593 Catalyst::Helper::Controller::
594
675fef06 595=head2 COMMON HELPERS
bc8d7994 596
597=over
598
599=item *
600
601L<Catalyst::Helper::Model::DBIC::Schema> - DBIx::Class models
602
603=item *
604
605L<Catalyst::Helper::View::TT> - Template Toolkit view
606
607=item *
608
609L<Catalyst::Helper::Model::LDAP>
610
611=item *
612
613L<Catalyst::Helper::Model::Adaptor> - wrap any class into a Catalyst model
614
615=back
616
617=head3 NOTE
618
675fef06 619The helpers will read author name from /etc/passwd by default. + To override, please export the AUTHOR variable.
bc8d7994 620
621=head1 METHODS
622
fab70e0a 623=head2 mk_compclass
624
625This method in your Helper module is called with C<$helper>
626which is a L<Catalyst::Helper> object, and whichever other arguments
627the user added to the command-line. You can use the $helper to call methods
628described below.
629
630If the Helper module does not contain a C<mk_compclass> method, it
631will fall back to calling L</render_file>, with an argument of
632C<compclass>.
633
634=head2 mk_comptest
635
636This method in your Helper module is called with C<$helper>
637which is a L<Catalyst::Helper> object, and whichever other arguments
638the user added to the command-line. You can use the $helper to call methods
639described below.
640
641If the Helper module does not contain a C<mk_compclass> method, it
642will fall back to calling L</render_file>, with an argument of
643C<comptest>.
644
645=head2 mk_stuff
646
647This method is called if the user does not supply any of the usual
648component types C<view>, C<controller>, C<model>. It is passed the
649C<$helper> object (an instance of L<Catalyst::Helper>), and any other
650arguments the user typed.
651
652There is no fallback for this method.
653
bc8d7994 654=head1 INTERNAL METHODS
fab70e0a 655
656These are the methods that the Helper classes can call on the
657<$helper> object passed to them.
658
28eb1300 659=head2 render_file ($file, $path, $vars)
fab70e0a 660
28eb1300 661Render and create a file from a template in DATA using Template
662Toolkit. $file is the relevent chunk of the __DATA__ section, $path is
663the path to the file and $vars is the hashref as expected by
664L<Template Toolkit|Template>.
fab70e0a 665
28eb1300 666=head2 get_file ($class, $file)
fab70e0a 667
668Fetch file contents from the DATA section. This is used internally by
28eb1300 669L</render_file>. $class is the name of the class to get the DATA
670section from. __PACKAGE__ or ( caller(0) )[0] might be sensible
671values for this.
fab70e0a 672
673=head2 mk_app
674
675Create the main application skeleton. This is called by L<catalyst.pl>.
676
28eb1300 677=head2 mk_component ($app)
fab70e0a 678
679This method is called by L<create.pl> to make new components
680for your application.
681
28eb1300 682=head3 mk_dir ($path)
fab70e0a 683
684Surprisingly, this function makes a directory.
685
28eb1300 686=head2 mk_file ($file, $content)
fab70e0a 687
688Writes content to a file. Called by L</render_file>.
689
28eb1300 690=head2 next_test ($test_name)
fab70e0a 691
692Calculates the name of the next numbered test file and returns it.
28eb1300 693Don't give the number or the .t suffix for the test name.
fab70e0a 694
68ccb5e5 695=head1 NOTE
696
697The helpers will read author name from /etc/passwd by default.
698To override, please export the AUTHOR variable.
699
700=head1 SEE ALSO
701
702L<Catalyst::Manual>, L<Catalyst::Test>, L<Catalyst::Request>,
703L<Catalyst::Response>, L<Catalyst>
704
f64c718c 705=head1 AUTHORS
68ccb5e5 706
f64c718c 707Catalyst Contributors, see Catalyst.pm
68ccb5e5 708
709=head1 LICENSE
710
7cd3b67e 711This library is free software. You can redistribute it and/or modify
68ccb5e5 712it under the same terms as Perl itself.
713
64d4433e 714=begin pod_to_ignore
715
68ccb5e5 716=cut
717
7181;
68ccb5e5 719