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