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