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