1 package Catalyst::Helper;
13 use Catalyst::Exception;
14 use Path::Class qw/dir file/;
15 use File::ShareDir qw/dist_dir/;
16 use MooseX::Types::Moose qw/Str Bool Int/;
18 with 'MooseX::Getopt';
25 Catalyst::Helper - Bootstrap a Catalyst application
29 catalyst.pl <myappname>
34 ## this stays in Helper.pm #####################################################
35 sub get_sharedir_file {
36 my ($self, @filename) = @_;
38 if (-d dir("inc", ".author") { # Can't use sharedir if we're in a checkout
39 # this feels horrible, better ideas?
43 $dist_dir = dist_dir('Catalyst-Devel');
45 my $file = file( $dist_dir, @filename);
46 my $contents = $file->slurp;
50 # Do not touch this method, *EVER*, it is needed for back compat.
52 my ( $self, $class, $file ) = @_;
53 unless ( $cache{$class} ) {
55 $cache{$class} = eval "package $class; <DATA>";
57 my $data = $cache{$class};
58 Carp::confess("Could not get data from __DATA__ segment for $class")
60 my @files = split /^__(.+)__\r?\n/m, $data;
63 my ( $name, $content ) = splice @files, 0, 2;
64 return $content if $name eq $file;
69 ################################################################################
73 my ( $self, $dir ) = @_;
75 print qq/ exists "$dir"\n/;
78 if ( mkpath [$dir] ) {
79 print qq/created "$dir"\n/;
83 Catalyst::Exception->throw( message => qq/Couldn't create "$dir", "$!"/ );
87 my ( $self, $file, $content ) = @_;
88 if ( -e $file && -s _ ) {
89 print qq/ exists "$file"\n/;
91 unless ( $self->{'.newfiles'}
93 || $self->{makefile} );
94 if ( $self->{'.newfiles'} ) {
95 if ( my $f = IO::File->new("< $file") ) {
96 my $oldcontent = join( '', (<$f>) );
97 return 0 if $content eq $oldcontent;
102 if ( my $f = IO::File->new("> $file") ) {
105 print qq/created "$file"\n/;
109 Catalyst::Exception->throw( message => qq/Couldn't create "$file", "$!"/ );
113 my ( $self, $tname ) = @_;
114 if ($tname) { $tname = "$tname.t" }
116 my $name = $self->{name};
120 $tname = $prefix . '.t';
121 $self->{prefix} = $prefix;
122 $prefix = lc $prefix;
124 $self->{uri} = "/$prefix";
126 my $dir = $self->{test_dir};
127 my $type = lc $self->{type};
129 return File::Spec->catfile( $dir, "$type\_$tname" );
132 # Do not touch this method, *EVER*, it is needed for back compat. ##############
133 ## addendum: we had to split this method so we could have backwards
134 ## compatability. otherwise, we'd have no way to pass stuff from __DATA__
136 my ( $self, $file, $path, $vars ) = @_;
137 my $template = $self->get_file( ( caller(0) )[0], $file );
138 $self->render_file_contents($template, $path, $vars);
140 ################################################################################
142 sub render_sharedir_file {
143 my ( $self, $file, $path, $vars ) = @_;
144 my $template = $self->get_sharedir_file( $file );
145 $self->render_file_contents($template, $path, $vars);
148 sub render_file_contents {
149 my ( $self, $template, $path, $vars ) = @_;
151 my $t = Template->new;
152 return 0 unless $template;
154 $t->process( \$template, { %{$self}, %$vars }, \$output )
155 || Catalyst::Exception->throw(
156 message => qq/Couldn't process "$template", / . $t->error() );
157 $self->mk_file( $path, $output );
161 sub _mk_information {
163 print qq/Change to application directory and Run "perl Makefile.PL" to make sure your install is complete\n/;
168 $self->mk_dir( $self->{dir} );
169 $self->mk_dir( $self->{script} );
170 $self->{lib} = File::Spec->catdir( $self->{dir}, 'lib' );
171 $self->mk_dir( $self->{lib} );
172 $self->{root} = File::Spec->catdir( $self->{dir}, 'root' );
173 $self->mk_dir( $self->{root} );
174 $self->{static} = File::Spec->catdir( $self->{root}, 'static' );
175 $self->mk_dir( $self->{static} );
176 $self->{images} = File::Spec->catdir( $self->{static}, 'images' );
177 $self->mk_dir( $self->{images} );
178 $self->{t} = File::Spec->catdir( $self->{dir}, 't' );
179 $self->mk_dir( $self->{t} );
181 $self->{class} = File::Spec->catdir( split( /\:\:/, $self->{name} ) );
182 $self->{mod} = File::Spec->catdir( $self->{lib}, $self->{class} );
183 $self->mk_dir( $self->{mod} );
185 if ( $self->{short} ) {
186 $self->{m} = File::Spec->catdir( $self->{mod}, 'M' );
187 $self->mk_dir( $self->{m} );
188 $self->{v} = File::Spec->catdir( $self->{mod}, 'V' );
189 $self->mk_dir( $self->{v} );
190 $self->{c} = File::Spec->catdir( $self->{mod}, 'C' );
191 $self->mk_dir( $self->{c} );
194 $self->{m} = File::Spec->catdir( $self->{mod}, 'Model' );
195 $self->mk_dir( $self->{m} );
196 $self->{v} = File::Spec->catdir( $self->{mod}, 'View' );
197 $self->mk_dir( $self->{v} );
198 $self->{c} = File::Spec->catdir( $self->{mod}, 'Controller' );
199 $self->mk_dir( $self->{c} );
201 my $name = $self->{name};
203 $self->{short} ? "$name\::C::Root" : "$name\::Controller::Root";
204 $self->{base} = File::Spec->rel2abs( $self->{dir} );
210 my $mod = $self->{mod};
211 $self->render_sharedir_file( File::Spec->catfile('lib', 'MyApp.pm.tt'), "$mod.pm" );
217 $self->render_sharedir_file( File::Spec->catfile('lib', 'MyApp', 'Controller', 'Root.pm.tt'),
218 File::Spec->catfile( $self->{c}, "Root.pm" ) );
224 $self->{path} = File::Spec->catfile( 'lib', split( '::', $self->{name} ) );
225 $self->{path} .= '.pm';
226 my $dir = $self->{dir};
227 $self->render_sharedir_file( 'Makefile.PL.tt', "$dir\/Makefile.PL" );
229 if ( $self->{makefile} ) {
231 # deprecate the old Build.PL file when regenerating Makefile.PL
232 $self->_deprecate_file(
233 File::Spec->catdir( $self->{dir}, 'Build.PL' ) );
240 my $dir = $self->{dir};
241 my $appprefix = $self->{appprefix};
242 $self->render_sharedir_file( 'myapp.conf.tt',
243 File::Spec->catfile( $dir, "$appprefix.conf" ) );
249 my $dir = $self->{dir};
250 $self->render_sharedir_file( 'README.tt', "$dir\/README" );
256 my $dir = $self->{dir};
257 my $time = strftime('%Y-%m-%d %H:%M:%S', localtime time);
258 $self->render_sharedir_file( 'Changes.tt', "$dir\/Changes", { time => $time } );
264 $self->render_sharedir_file( File::Spec->catfile('t', '01app.t.tt'), "$t\/01app.t" );
265 $self->render_sharedir_file( File::Spec->catfile('t', '02pod.t.tt'), "$t\/02pod.t" );
266 $self->render_sharedir_file( File::Spec->catfile('t', '03podcoverage.t.tt'), "$t\/03podcoverage.t" );
271 my $script = $self->{script};
272 my $appprefix = $self->{appprefix};
273 $self->render_sharedir_file( File::Spec->catfile('script', 'myapp_cgi.pl.tt'), "$script\/$appprefix\_cgi.pl" );
274 chmod 0700, "$script/$appprefix\_cgi.pl";
279 my $script = $self->{script};
280 my $appprefix = $self->{appprefix};
281 $self->render_sharedir_file( File::Spec->catfile('script', 'myapp_fastcgi.pl.tt'), "$script\/$appprefix\_fastcgi.pl" );
282 chmod 0700, "$script/$appprefix\_fastcgi.pl";
287 my $script = $self->{script};
288 my $appprefix = $self->{appprefix};
289 $self->render_sharedir_file( File::Spec->catfile('script', 'myapp_server.pl.tt'), "$script\/$appprefix\_server.pl" );
290 chmod 0700, "$script/$appprefix\_server.pl";
295 my $script = $self->{script};
296 my $appprefix = $self->{appprefix};
297 $self->render_sharedir_file( File::Spec->catfile('script', 'myapp_test.pl.tt'), "$script/$appprefix\_test.pl" );
298 chmod 0700, "$script/$appprefix\_test.pl";
303 my $script = $self->{script};
304 my $appprefix = $self->{appprefix};
305 $self->render_sharedir_file( File::Spec->catfile('script', 'myapp_create.pl.tt'), "$script\/$appprefix\_create.pl" );
306 chmod 0700, "$script/$appprefix\_create.pl";
312 my $file = $self->{file};
313 return $self->render_sharedir_file( 'myapp_compclass.pl.tt', "$file" );
319 my $test = $self->{test};
320 $self->render_sharedir_file( 'comptest.tt', "$test" ); ## wtf do i rename this to?
325 my $images = $self->{images};
327 qw/catalyst_logo btn_120x50_built btn_120x50_built_shadow
328 btn_120x50_powered btn_120x50_powered_shadow btn_88x31_built
329 btn_88x31_built_shadow btn_88x31_powered btn_88x31_powered_shadow/;
330 for my $name (@images) {
331 my $image = $self->get_sharedir_file("root", "static", "images", "$name.png.bin");
332 $self->mk_file( File::Spec->catfile( $images, "$name.png" ), $image );
339 my $root = $self->{root};
340 my $favicon = $self->get_sharedir_file( 'root', 'favicon.ico.bin' );
341 my $dest = File::Spec->catfile( $root, "favicon.ico" );
342 $self->mk_file( $dest, $favicon );
346 sub _deprecate_file {
347 my ( $self, $file ) = @_;
350 if ( my $f = IO::File->new("< $file") ) {
351 $oldcontent = join( '', (<$f>) );
353 my $newfile = $file . '.deprecated';
354 if ( my $f = IO::File->new("> $newfile") ) {
356 print $f $oldcontent;
357 print qq/created "$newfile"\n/;
359 print qq/removed "$file"\n/;
362 Catalyst::Exception->throw(
363 message => qq/Couldn't create "$file", "$!"/ );
369 This module is used by B<catalyst.pl> to create a set of scripts for a
370 new catalyst application. The scripts each contain documentation and
371 will output help on how to use them if called incorrectly or in some
372 cases, with no arguments.
374 It also provides some useful methods for a Helper module to call when
375 creating a component. See L</METHODS>.
381 Used to create new components for a catalyst application at the
386 The catalyst test server, starts an HTTPD which outputs debugging to
391 A script for running tests from the command-line.
395 Run your application as a CGI.
399 Run the application as a fastcgi app. Either by hand, or call this
400 from FastCgiServer in your http server config.
404 The L</_create.pl> script creates application components using Helper
405 modules. The Catalyst team provides a good number of Helper modules
406 for you to use. You can also add your own.
408 Helpers are classes that provide two methods.
410 * mk_compclass - creates the Component class
411 * mk_comptest - creates the Component test
413 So when you call C<scripts/myapp_create.pl view MyView TT>, create
414 will try to execute Catalyst::Helper::View::TT->mk_compclass and
415 Catalyst::Helper::View::TT->mk_comptest.
417 See L<Catalyst::Helper::View::TT> and
418 L<Catalyst::Helper::Model::DBIC::Schema> for examples.
420 All helper classes should be under one of the following namespaces.
422 Catalyst::Helper::Model::
423 Catalyst::Helper::View::
424 Catalyst::Helper::Controller::
426 =head2 COMMON HELPERS
432 L<Catalyst::Helper::Model::DBIC::Schema> - DBIx::Class models
436 L<Catalyst::Helper::View::TT> - Template Toolkit view
440 L<Catalyst::Helper::Model::LDAP>
444 L<Catalyst::Helper::Model::Adaptor> - wrap any class into a Catalyst model
450 The helpers will read author name from /etc/passwd by default. + To override, please export the AUTHOR variable.
456 This method in your Helper module is called with C<$helper>
457 which is a L<Catalyst::Helper> object, and whichever other arguments
458 the user added to the command-line. You can use the $helper to call methods
461 If the Helper module does not contain a C<mk_compclass> method, it
462 will fall back to calling L</render_file>, with an argument of
467 This method in your Helper module is called with C<$helper>
468 which is a L<Catalyst::Helper> object, and whichever other arguments
469 the user added to the command-line. You can use the $helper to call methods
472 If the Helper module does not contain a C<mk_compclass> method, it
473 will fall back to calling L</render_file>, with an argument of
478 This method is called if the user does not supply any of the usual
479 component types C<view>, C<controller>, C<model>. It is passed the
480 C<$helper> object (an instance of L<Catalyst::Helper>), and any other
481 arguments the user typed.
483 There is no fallback for this method.
485 =head1 INTERNAL METHODS
487 These are the methods that the Helper classes can call on the
488 <$helper> object passed to them.
490 =head2 render_file ($file, $path, $vars)
492 Render and create a file from a template in DATA using Template
493 Toolkit. $file is the relevent chunk of the __DATA__ section, $path is
494 the path to the file and $vars is the hashref as expected by
495 L<Template Toolkit|Template>.
497 =head2 get_file ($class, $file)
499 Fetch file contents from the DATA section. This is used internally by
500 L</render_file>. $class is the name of the class to get the DATA
501 section from. __PACKAGE__ or ( caller(0) )[0] might be sensible
506 Create the main application skeleton. This is called by L<catalyst.pl>.
508 =head2 mk_component ($app)
510 This method is called by L<create.pl> to make new components
511 for your application.
513 =head3 mk_dir ($path)
515 Surprisingly, this function makes a directory.
517 =head2 mk_file ($file, $content)
519 Writes content to a file. Called by L</render_file>.
521 =head2 next_test ($test_name)
523 Calculates the name of the next numbered test file and returns it.
524 Don't give the number or the .t suffix for the test name.
528 Alias for L<Path::Class::Dir>
532 =head2 get_sharedir_file
534 Method for getting a file out of share/
538 =head2 render_file_contents
540 Process a L<Template::Toolkit> template.
544 =head2 render_sharedir_file
546 Render a template/image file from our share directory
553 The helpers will read author name from /etc/passwd by default.
554 To override, please export the AUTHOR variable.
558 L<Catalyst::Manual>, L<Catalyst::Test>, L<Catalyst::Request>,
559 L<Catalyst::Response>, L<Catalyst>
563 Catalyst Contributors, see Catalyst.pm
567 This library is free software. You can redistribute it and/or modify
568 it under the same terms as Perl itself.