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