Added Catalyst::Exception
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Helper.pm
1 package Catalyst::Helper;
2
3 use strict;
4 use base 'Class::Accessor::Fast';
5 use Config;
6 use File::Spec;
7 use File::Path;
8 use IO::File;
9 use FindBin;
10 use Template;
11 use Catalyst;
12 use Catalyst::Exception;
13
14 my %cache;
15
16 =head1 NAME
17
18 Catalyst::Helper - Bootstrap a Catalyst application
19
20 =head1 SYNOPSIS
21
22 See L<Catalyst::Manual::Intro>
23
24 =head1 DESCRIPTION
25
26 Bootstrap a Catalyst application. Autogenerates scripts
27
28 =head2 METHODS
29
30 =head3 get_file
31
32 Slurp file from DATA.
33
34 =cut
35
36 sub get_file {
37     my ( $self, $class, $file ) = @_;
38     unless ( $cache{$class} ) {
39         local $/;
40         $cache{$class} = eval "package $class; <DATA>";
41     }
42     my $data = $cache{$class};
43     my @files = split /^__(.+)__\n/m, $data;
44     shift @files;
45     while (@files) {
46         my ( $name, $content ) = splice @files, 0, 2;
47         return $content if $name eq $file;
48     }
49     return 0;
50 }
51
52 =head3 mk_app
53
54 Create the main application skeleton.
55
56 =cut
57
58 sub mk_app {
59     my ( $self, $name ) = @_;
60     return 0 if $name =~ /[^\w\:]/;
61     $self->{name} = $name;
62     $self->{dir}  = $name;
63     $self->{dir} =~ s/\:\:/-/g;
64     $self->{appprefix} = lc $self->{dir};
65     $self->{appprefix} =~ s/-/_/g;
66     $self->{startperl} = $Config{startperl};
67     $self->{scriptgen} = $Catalyst::CATALYST_SCRIPT_GEN;
68     $self->{author}    = $self->{author} = $ENV{'AUTHOR'}
69       || eval { @{ [ getpwuid($<) ] }[6] }
70       || 'Catalyst developer';
71     $self->_mk_dirs;
72     $self->_mk_appclass;
73     $self->_mk_build;
74     $self->_mk_makefile;
75     $self->_mk_readme;
76     $self->_mk_changes;
77     $self->_mk_apptest;
78     $self->_mk_cgi;
79     $self->_mk_fastcgi;
80     $self->_mk_server;
81     $self->_mk_test;
82     $self->_mk_create;
83     return 1;
84 }
85
86 =head3 mk_component
87
88 This method is called by create.pl to make new components
89 for your application.
90
91 =cut
92
93 sub mk_component {
94     my $self = shift;
95     my $app  = shift;
96     $self->{app} = $app;
97     $self->{author} = $self->{author} = $ENV{'AUTHOR'}
98       || eval { @{ [ getpwuid($<) ] }[6] }
99       || 'A clever guy';
100     $self->{base} = File::Spec->catdir( $FindBin::Bin, '..' );
101     unless ( $_[0] =~ /^(?:model|m|view|v|controller|c)$/i ) {
102         my $helper = shift;
103         my @args   = @_;
104         my $class  = "Catalyst::Helper::$helper";
105         eval "require $class";
106         
107         if ( $@ ) {
108             Catalyst::Exception->throw( 
109                 message => qq/Couldn't load helper "$class", "$@"/
110             );
111         }
112         
113         if ( $class->can('mk_stuff') ) {
114             return 1 unless $class->mk_stuff( $self, @args );
115         }
116     }
117     else {
118         my $type   = shift;
119         my $name   = shift || "Missing name for model/view/controller";
120         my $helper = shift;
121         my @args   = @_;
122         return 0 if $name =~ /[^\w\:]/;
123         $type = 'M' if $type =~ /model|m/i;
124         $type = 'V' if $type =~ /view|v/i;
125         $type = 'C' if $type =~ /controller|c/i;
126         $self->{type}  = $type;
127         $self->{name}  = $name;
128         $self->{class} = "$app\::$type\::$name";
129
130         # Class
131         my $appdir = File::Spec->catdir( split /\:\:/, $app );
132         my $path =
133           File::Spec->catdir( $FindBin::Bin, '..', 'lib', $appdir, $type );
134         my $file = $name;
135         if ( $name =~ /\:/ ) {
136             my @path = split /\:\:/, $name;
137             $file = pop @path;
138             $path = File::Spec->catdir( $path, @path );
139             mkpath $path;
140         }
141         $file = File::Spec->catfile( $path, "$file.pm" );
142         $self->{file} = $file;
143
144         # Test
145         $self->{test_dir} = File::Spec->catdir( $FindBin::Bin, '..', 't' );
146         $self->{test}     = $self->next_test;
147
148         # Helper
149         if ($helper) {
150             my $comp = 'Model';
151             $comp = 'View'       if $type eq 'V';
152             $comp = 'Controller' if $type eq 'C';
153             my $class = "Catalyst::Helper::$comp\::$helper";
154             eval "require $class";
155             
156             if ( $@ ) {
157                 Catalyst::Exception->throw( 
158                     message => qq/Couldn't load helper "$class", "$@"/
159                 );
160             }            
161         
162             if ( $class->can('mk_compclass') ) {
163                 return 1 unless $class->mk_compclass( $self, @args );
164             }
165             else { return 1 unless $self->_mk_compclass }
166
167             if ( $class->can('mk_comptest') ) {
168                 $class->mk_comptest( $self, @args );
169             }
170             else { $self->_mk_comptest }
171         }
172
173         # Fallback
174         else {
175             return 1 unless $self->_mk_compclass;
176             $self->_mk_comptest;
177         }
178     }
179     return 1;
180 }
181
182 =head3 mk_dir
183
184 Surprisingly, this function makes a directory.
185
186 =cut
187
188 sub mk_dir {
189     my ( $self, $dir ) = @_;
190     if ( -d $dir ) {
191         print qq/ exists "$dir"\n/;
192         return 0;
193     }
194     if ( mkpath $dir) {
195         print qq/created "$dir"\n/;
196         return 1;
197     }
198     
199     Catalyst::Exception->throw( 
200         message => qq/Couldn't create "$dir", "$!"/
201     );    
202 }
203
204 =head3 mk_file
205
206 writes content to a file.
207
208 =cut
209
210 sub mk_file {
211     my ( $self, $file, $content ) = @_;
212     if ( -e $file ) {
213         print qq/ exists "$file"\n/;
214         return 0;
215     }
216     if ( my $f = IO::File->new("> $file") ) {
217         print $f $content;
218         print qq/created "$file"\n/;
219         return 1;
220     }
221     
222     Catalyst::Exception->throw( 
223         message => qq/Couldn't create "$file", "$!"/
224     );       
225 }
226
227 =head3 next_test
228
229 =cut
230
231 sub next_test {
232     my ( $self, $tname ) = @_;
233     if ($tname) { $tname = "$tname.t" }
234     else {
235         my $name   = $self->{name};
236         my $prefix = $name;
237         $prefix =~ s/::/-/g;
238         $prefix         = $prefix;
239         $tname          = $prefix . '.t';
240         $self->{prefix} = $prefix;
241         $prefix = lc $prefix;
242         $prefix =~ s/-/\//g;
243         $self->{uri} = $prefix;
244     }
245     my $dir  = $self->{test_dir};
246     my $type = $self->{type};
247     return File::Spec->catfile( $dir, $type, $tname );
248 }
249
250 =head3 render_file
251
252 Render and create a file from a template in DATA using 
253 Template Toolkit.
254
255 =cut
256
257 sub render_file {
258     my ( $self, $file, $path, $vars ) = @_;
259     $vars ||= {};
260     my $t = Template->new;
261     my $template = $self->get_file( ( caller(0) )[0], $file );
262     return 0 unless $template;
263     my $output;
264     $t->process( \$template, { %{$self}, %$vars }, \$output );
265     $self->mk_file( $path, $output );
266 }
267
268 sub _mk_dirs {
269     my $self = shift;
270     $self->mk_dir( $self->{dir} );
271     $self->{script} = File::Spec->catdir( $self->{dir}, 'script' );
272     $self->mk_dir( $self->{script} );
273     $self->{lib} = File::Spec->catdir( $self->{dir}, 'lib' );
274     $self->mk_dir( $self->{lib} );
275     $self->{root} = File::Spec->catdir( $self->{dir}, 'root' );
276     $self->mk_dir( $self->{root} );
277     $self->{t} = File::Spec->catdir( $self->{dir}, 't' );
278     $self->mk_dir( $self->{t} );
279     $self->mk_dir( File::Spec->catdir( $self->{t}, 'M' ) );
280     $self->mk_dir( File::Spec->catdir( $self->{t}, 'V' ) );
281     $self->mk_dir( File::Spec->catdir( $self->{t}, 'C' ) );
282     $self->{class} = File::Spec->catdir( split( /\:\:/, $self->{name} ) );
283     $self->{mod} = File::Spec->catdir( $self->{lib}, $self->{class} );
284     $self->mk_dir( $self->{mod} );
285     $self->{m} = File::Spec->catdir( $self->{mod}, 'M' );
286     $self->mk_dir( $self->{m} );
287     $self->{v} = File::Spec->catdir( $self->{mod}, 'V' );
288     $self->mk_dir( $self->{v} );
289     $self->{c} = File::Spec->catdir( $self->{mod}, 'C' );
290     $self->mk_dir( $self->{c} );
291     $self->{base} = File::Spec->rel2abs( $self->{dir} );
292 }
293
294 sub _mk_appclass {
295     my $self = shift;
296     my $mod  = $self->{mod};
297     $self->render_file( 'appclass', "$mod.pm" );
298 }
299
300 sub _mk_build {
301     my $self = shift;
302     my $dir  = $self->{dir};
303     $self->render_file( 'build', "$dir\/Build.PL" );
304 }
305
306 sub _mk_makefile {
307     my $self = shift;
308     my $dir  = $self->{dir};
309     $self->render_file( 'makefile', "$dir\/Makefile.PL" );
310 }
311
312 sub _mk_readme {
313     my $self = shift;
314     my $dir  = $self->{dir};
315     $self->render_file( 'readme', "$dir\/README" );
316 }
317
318 sub _mk_changes {
319     my $self = shift;
320     my $dir  = $self->{dir};
321     my $time = localtime time;
322     $self->render_file( 'changes', "$dir\/Changes", { time => $time } );
323 }
324
325 sub _mk_apptest {
326     my $self = shift;
327     my $t    = $self->{t};
328     $self->render_file( 'apptest',         "$t\/01app.t" );
329     $self->render_file( 'podtest',         "$t\/02pod.t" );
330     $self->render_file( 'podcoveragetest', "$t\/03podcoverage.t" );
331 }
332
333 sub _mk_cgi {
334     my $self      = shift;
335     my $script    = $self->{script};
336     my $appprefix = $self->{appprefix};
337     $self->render_file( 'cgi', "$script\/$appprefix\_cgi.pl" );
338     chmod 0700, "$script/$appprefix\_cgi.pl";
339 }
340
341 sub _mk_fastcgi {
342     my $self      = shift;
343     my $script    = $self->{script};
344     my $appprefix = $self->{appprefix};
345     $self->render_file( 'fastcgi', "$script\/$appprefix\_fastcgi.pl" );
346     chmod 0700, "$script/$appprefix\_fastcgi.pl";
347 }
348
349 sub _mk_server {
350     my $self      = shift;
351     my $script    = $self->{script};
352     my $appprefix = $self->{appprefix};
353     $self->render_file( 'server', "$script\/$appprefix\_server.pl" );
354     chmod 0700, "$script/$appprefix\_server.pl";
355 }
356
357 sub _mk_test {
358     my $self      = shift;
359     my $script    = $self->{script};
360     my $appprefix = $self->{appprefix};
361     $self->render_file( 'test', "$script/$appprefix\_test.pl" );
362     chmod 0700, "$script/$appprefix\_test.pl";
363 }
364
365 sub _mk_create {
366     my $self      = shift;
367     my $script    = $self->{script};
368     my $appprefix = $self->{appprefix};
369     $self->render_file( 'create', "$script\/$appprefix\_create.pl" );
370     chmod 0700, "$script/$appprefix\_create.pl";
371 }
372
373 sub _mk_compclass {
374     my $self = shift;
375     my $file = $self->{file};
376     return $self->render_file( 'compclass', "$file" );
377 }
378
379 sub _mk_comptest {
380     my $self = shift;
381     my $test = $self->{test};
382     $self->render_file( 'comptest', "$test" );
383 }
384
385 =head1 HELPERS
386
387 Helpers are classes that provide two methods.
388
389     * mk_compclass - creates the Component class
390     * mk_comptest  - creates the Component test
391
392 So when you call C<bin/create view MyView TT>, create would try to execute
393 Catalyst::Helper::View::TT->mk_compclass and
394 Catalyst::Helper::View::TT->mk_comptest.
395
396 See L<Catalyst::Helper::View::TT> and L<Catalyst::Helper::Model::CDBI> for
397 examples.
398
399 All helper classes should be under one of the following namespaces.
400
401     Catalyst::Helper::Model::
402     Catalyst::Helper::View::
403     Catalyst::Helper::Controller::
404
405 =head1 NOTE
406
407 The helpers will read author name from /etc/passwd by default.
408 To override, please export the AUTHOR variable.
409
410 =head1 SEE ALSO
411
412 L<Catalyst::Manual>, L<Catalyst::Test>, L<Catalyst::Request>,
413 L<Catalyst::Response>, L<Catalyst>
414
415 =head1 AUTHOR
416
417 Sebastian Riedel, C<sri@oook.de>
418
419 =head1 LICENSE
420
421 This library is free software . You can redistribute it and/or modify
422 it under the same terms as perl itself.
423
424 =cut
425
426 1;
427 __DATA__
428
429 __appclass__
430 package [% name %];
431
432 use strict;
433 use Catalyst qw/-Debug/;
434
435 our $VERSION = '0.01';
436
437 [% name %]->config( name => '[% name %]' );
438
439 [% name %]->setup;
440
441 =head1 NAME
442
443 [% name %] - Catalyst based application
444
445 =head1 SYNOPSIS
446
447     script/[% appprefix %]_server.pl
448
449 =head1 DESCRIPTION
450
451 Catalyst based application.
452
453 =head1 METHODS
454
455 =over 4
456
457 =item default
458
459 =cut
460
461 sub default : Private {
462     my ( $self, $c ) = @_;
463     $c->res->output('Congratulations, [% name %] is on Catalyst!');
464 }
465
466 =back
467
468 =head1 AUTHOR
469
470 [%author%]
471
472 =head1 LICENSE
473
474 This library is free software . You can redistribute it and/or modify
475 it under the same terms as perl itself.
476
477 =cut
478
479 1;
480 __makefile__
481     unless ( eval "use Module::Build::Compat 0.02; 1" ) {
482         print "This module requires Module::Build to install itself.\n";
483
484         require ExtUtils::MakeMaker;
485         my $yn =
486           ExtUtils::MakeMaker::prompt( '  Install Module::Build now from CPAN?',            'y' );
487
488         unless ( $yn =~ /^y/i ) {
489             die " *** Cannot install without Module::Build.  Exiting ...\n";
490         }
491
492         require Cwd;
493         require File::Spec;
494         require CPAN;
495
496         # Save this 'cause CPAN will chdir all over the place.
497         my $cwd      = Cwd::cwd();
498         my $makefile = File::Spec->rel2abs($0);
499
500         CPAN::Shell->install('Module::Build::Compat')
501           or die " *** Cannot install without Module::Build.  Exiting ...\n";
502
503         chdir $cwd or die "Cannot chdir() back to $cwd: $!";
504     }
505     eval "use Module::Build::Compat 0.02; 1" or die $@;
506     use lib '_build/lib';
507     Module::Build::Compat->run_build_pl( args => \@ARGV );
508     require Module::Build;
509     Module::Build::Compat->write_makefile( build_class => 'Module::Build' );
510 __build__
511 use strict;
512 use Catalyst::Build;
513
514 my $build = Catalyst::Build->new(
515     create_makefile_pl => 'passthrough',
516     license            => 'perl',
517     module_name        => '[% name %]',
518     requires           => { Catalyst => '5.10' },
519     create_makefile_pl => 'passthrough',
520     script_files       => [ glob('script/*') ],
521     test_files         => [ glob('t/*.t'), glob('t/*/*.t') ]
522 );
523 $build->create_build_script;
524 __readme__
525 Run script/[% appprefix %]_server.pl to test the application.
526 __changes__
527 This file documents the revision history for Perl extension [% name %].
528 0.01  [% time %]
529         - initial revision, generated by Catalyst
530 __apptest__
531 use Test::More tests => 2;
532 use_ok( Catalyst::Test, '[% name %]' );
533
534 ok( request('/')->is_success );
535 __podtest__
536 use Test::More;
537
538 eval "use Test::Pod 1.14";
539 plan skip_all => 'Test::Pod 1.14 required' if $@;
540 plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
541
542 all_pod_files_ok();
543 __podcoveragetest__
544 use Test::More;
545
546 eval "use Test::Pod::Coverage 1.04";
547 plan skip_all => 'Test::Pod::Coverage 1.04 required' if $@;
548 plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
549
550 all_pod_coverage_ok();
551 __cgi__
552 [% startperl %] -w
553
554 BEGIN { $ENV{CATALYST_ENGINE} ||= 'CGI' }
555
556 use strict;
557 use FindBin;
558 use lib "$FindBin::Bin/../lib";
559 use [% name %];
560
561 [% name %]->run;
562
563 1;
564
565 =head1 NAME
566
567 [% appprefix %]_cgi.pl - Catalyst CGI
568
569 =head1 SYNOPSIS
570
571 See L<Catalyst::Manual>
572
573 =head1 DESCRIPTION
574
575 Run a Catalyst application as cgi.
576
577 =head1 AUTHOR
578
579 Sebastian Riedel, C<sri@oook.de>
580
581 =head1 COPYRIGHT
582
583 Copyright 2004 Sebastian Riedel. All rights reserved.
584
585 This library is free software. You can redistribute it and/or modify
586 it under the same terms as perl itself.
587
588 =cut
589 __fastcgi__
590 [% startperl %] -w
591
592 BEGIN { $ENV{CATALYST_ENGINE} ||= 'FastCGI' }
593
594 use strict;
595 use FindBin;
596 use lib "$FindBin::Bin/../lib";
597 use [% name %];
598
599 [% name %]->run;
600
601 1;
602
603 =head1 NAME
604
605 [% appprefix %]_fastcgi.pl - Catalyst FastCGI
606
607 =head1 SYNOPSIS
608
609 See L<Catalyst::Manual>
610
611 =head1 DESCRIPTION
612
613 Run a Catalyst application as fastcgi.
614
615 =head1 AUTHOR
616
617 Sebastian Riedel, C<sri@oook.de>
618
619 =head1 COPYRIGHT
620
621 Copyright 2004 Sebastian Riedel. All rights reserved.
622
623 This library is free software. You can redistribute it and/or modify
624 it under the same terms as perl itself.
625
626 =cut
627 __server__
628 [% startperl %] -w
629
630 BEGIN { 
631     $ENV{CATALYST_ENGINE} ||= 'HTTP';
632     $ENV{CATALYST_SCRIPT_GEN} = [% scriptgen %];
633 }  
634
635 use strict;
636 use Getopt::Long;
637 use Pod::Usage;
638 use FindBin;
639 use lib "$FindBin::Bin/../lib";
640 use [% name %];
641
642 my $help = 0;
643 my $port = 3000;
644
645 GetOptions( 'help|?' => \$help, 'port=s' => \$port );
646
647 pod2usage(1) if $help;
648
649 [% name %]->run($port);
650
651 1;
652
653 =head1 NAME
654
655 [% appprefix %]_server.pl - Catalyst Testserver
656
657 =head1 SYNOPSIS
658
659 [% appprefix %]_server.pl [options]
660
661  Options:
662    -? -help    display this help and exits
663    -p -port    port (defaults to 3000)
664
665  See also:
666    perldoc Catalyst::Manual
667    perldoc Catalyst::Manual::Intro
668
669 =head1 DESCRIPTION
670
671 Run a Catalyst Testserver for this application.
672
673 =head1 AUTHOR
674
675 Sebastian Riedel, C<sri@oook.de>
676
677 =head1 COPYRIGHT
678
679 Copyright 2004 Sebastian Riedel. All rights reserved.
680
681 This library is free software. You can redistribute it and/or modify
682 it under the same terms as perl itself.
683
684 =cut
685 __test__
686 [% startperl %] -w
687
688 BEGIN { $ENV{CATALYST_ENGINE} ||= 'Test' }
689
690 use strict;
691 use Getopt::Long;
692 use Pod::Usage;
693 use FindBin;
694 use lib "$FindBin::Bin/../lib";
695 use [% name %];
696
697 my $help = 0;
698
699 GetOptions( 'help|?' => \$help );
700
701 pod2usage(1) if ( $help || !$ARGV[0] );
702
703 print [% name %]->run($ARGV[0])->content . "\n";
704
705 1;
706
707 =head1 NAME
708
709 [% appprefix %]_test.pl - Catalyst Test
710
711 =head1 SYNOPSIS
712
713 [% appprefix %]_test.pl [options] uri
714
715  Options:
716    -help    display this help and exits
717
718  Examples:
719    [% appprefix %]_test.pl http://localhost/some_action
720    [% appprefix %]_test.pl /some_action
721
722  See also:
723    perldoc Catalyst::Manual
724    perldoc Catalyst::Manual::Intro
725
726 =head1 DESCRIPTION
727
728 Run a Catalyst action from the comand line.
729
730 =head1 AUTHOR
731
732 Sebastian Riedel, C<sri@oook.de>
733
734 =head1 COPYRIGHT
735
736 Copyright 2004 Sebastian Riedel. All rights reserved.
737
738 This library is free software. You can redistribute it and/or modify
739 it under the same terms as perl itself.
740
741 =cut
742 __create__
743 [% startperl %] -w
744
745 use strict;
746 use Getopt::Long;
747 use Pod::Usage;
748 use Catalyst::Helper;
749
750 my $help = 0;
751
752 GetOptions( 'help|?' => \$help );
753
754 pod2usage(1) if ( $help || !$ARGV[0] );
755
756 my $helper = Catalyst::Helper->new;
757 pod2usage(1) unless $helper->mk_component( '[% name %]', @ARGV );
758
759 1;
760
761 =head1 NAME
762
763 [% appprefix %]_create.pl - Create a new Catalyst Component
764
765 =head1 SYNOPSIS
766
767 [% appprefix %]_create.pl [options] model|view|controller name [helper] [options]
768
769  Options:
770    -help    display this help and exits
771
772  Examples:
773    [% appprefix %]_create.pl controller My::Controller
774    [% appprefix %]_create.pl view My::View
775    [% appprefix %]_create.pl view MyView TT
776    [% appprefix %]_create.pl view TT TT
777    [% appprefix %]_create.pl model My::Model
778    [% appprefix %]_create.pl model SomeDB CDBI dbi:SQLite:/tmp/my.db
779    [% appprefix %]_create.pl model AnotherDB CDBI dbi:Pg:dbname=foo root 4321
780
781  See also:
782    perldoc Catalyst::Manual
783    perldoc Catalyst::Manual::Intro
784
785 =head1 DESCRIPTION
786
787 Create a new Catalyst Component.
788
789 =head1 AUTHOR
790
791 Sebastian Riedel, C<sri\@oook.de>
792
793 =head1 COPYRIGHT
794
795 Copyright 2004 Sebastian Riedel. All rights reserved.
796
797 This library is free software. You can redistribute it and/or modify
798 it under the same terms as perl itself.
799
800 =cut
801 __compclass__
802 package [% class %];
803
804 use strict;
805 use base 'Catalyst::Base';
806
807 =head1 NAME
808
809 [% class %] - Catalyst component
810
811 =head1 SYNOPSIS
812
813 See L<[% app %]>
814
815 =head1 DESCRIPTION
816
817 Catalyst component.
818 [% IF type == 'C' %]
819 =head1 METHODS
820
821 =over 4
822
823 =item default
824
825 =cut
826
827 sub default : Private {
828     my ( $self, $c ) = @_;
829     $c->res->output('Congratulations, [% class %] is on Catalyst!');
830 }
831
832 =back
833 [% END %]
834 =head1 AUTHOR
835
836 [%author%]
837
838 =head1 LICENSE
839
840 This library is free software . You can redistribute it and/or modify
841 it under the same terms as perl itself.
842
843 =cut
844
845 1;
846 __comptest__
847 [% IF type == 'C' %]
848 use Test::More tests => 3;
849 use_ok( Catalyst::Test, '[% app %]' );
850 use_ok('[% class %]');
851
852 ok( request('[% uri %]')->is_success );
853 [% ELSE %]
854 use Test::More tests => 1;
855 use_ok('[% class %]');
856 [% END %]