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