use accessor for expose_methods rather than access config directly
[catagits/Catalyst-View-TT.git] / lib / Catalyst / View / TT.pm
CommitLineData
8077080c 1package Catalyst::View::TT;
2
3use strict;
6229ce0d 4use warnings;
5
7d8aa5ec 6use base qw/Catalyst::View/;
9e739e1e 7use Data::Dump 'dump';
8077080c 8use Template;
9use Template::Timer;
e8693f1b 10use MRO::Compat;
316f014a 11use Scalar::Util qw/blessed/;
8077080c 12
5c2affa4 13our $VERSION = '0.34';
8077080c 14
15__PACKAGE__->mk_accessors('template');
46cdc47d 16__PACKAGE__->mk_accessors('expose_methods');
e2bbd784 17__PACKAGE__->mk_accessors('include_path');
8077080c 18
9d574573 19*paths = \&include_path;
20
8077080c 21=head1 NAME
22
23Catalyst::View::TT - Template View Class
24
25=head1 SYNOPSIS
26
bd4ee63a 27# use the helper to create your View
ad50568f 28
226c1dd3 29 myapp_create.pl view Web TT
8077080c 30
226c1dd3 31# add custom configration in View/Web.pm
8cd017a8 32
940a2e8a 33 __PACKAGE__->config(
226c1dd3 34 # any TT configuration items go here
35 INCLUDE_PATH => [
36 MyApp->path_to( 'root', 'src' ),
37 MyApp->path_to( 'root', 'lib' ),
38 ],
39 TEMPLATE_EXTENSION => '.tt',
40 CATALYST_VAR => 'c',
41 TIMER => 0,
42 # Not set by default
43 PRE_PROCESS => 'config/main',
44 WRAPPER => 'site/wrapper',
45 render_die => 1, # Default for new apps, see render method docs
a6fa99df 46 expose_methods => [qw/method_in_view_class/],
ae035767 47 );
f5b61ad7 48
6229ce0d 49# render view from lib/MyApp.pm or lib/MyApp::Controller::SomeController.pm
f5b61ad7 50
8cd017a8 51 sub message : Global {
94b3529a 52 my ( $self, $c ) = @_;
53 $c->stash->{template} = 'message.tt2';
54 $c->stash->{message} = 'Hello World!';
226c1dd3 55 $c->forward( $c->view('Web') );
8cd017a8 56 }
8077080c 57
8cd017a8 58# access variables from template
59
60 The message is: [% message %].
f5b61ad7 61
8cd017a8 62 # example when CATALYST_VAR is set to 'Catalyst'
f5b61ad7 63 Context is [% Catalyst %]
64 The base is [% Catalyst.req.base %]
65 The name is [% Catalyst.config.name %]
66
8cd017a8 67 # example when CATALYST_VAR isn't set
68 Context is [% c %]
69 The base is [% base %]
70 The name is [% name %]
71
bd4ee63a 72=cut
73
74sub _coerce_paths {
75 my ( $paths, $dlim ) = shift;
76 return () if ( !$paths );
77 return @{$paths} if ( ref $paths eq 'ARRAY' );
78
79 # tweak delim to ignore C:/
80 unless ( defined $dlim ) {
81 $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
82 }
83 return split( /$dlim/, $paths );
84}
85
86sub new {
87 my ( $class, $c, $arguments ) = @_;
88 my $config = {
89 EVAL_PERL => 0,
90 TEMPLATE_EXTENSION => '',
91 %{ $class->config },
92 %{$arguments},
93 };
94 if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) {
95 my $delim = $config->{DELIMITER};
96 my @include_path
97 = _coerce_paths( $config->{INCLUDE_PATH}, $delim );
98 if ( !@include_path ) {
99 my $root = $c->config->{root};
100 my $base = Path::Class::dir( $root, 'base' );
101 @include_path = ( "$root", "$base" );
102 }
103 $config->{INCLUDE_PATH} = \@include_path;
104 }
105
106 # if we're debugging and/or the TIMER option is set, then we install
107 # Template::Timer as a custom CONTEXT object, but only if we haven't
108 # already got a custom CONTEXT defined
109
110 if ( $config->{TIMER} ) {
111 if ( $config->{CONTEXT} ) {
112 $c->log->error(
113 'Cannot use Template::Timer - a TT CONTEXT is already defined'
114 );
115 }
116 else {
117 $config->{CONTEXT} = Template::Timer->new(%$config);
118 }
119 }
120
121 if ( $c->debug && $config->{DUMP_CONFIG} ) {
9e739e1e 122 $c->log->debug( "TT Config: ", dump($config) );
bd4ee63a 123 }
6175bba7 124
e8693f1b 125 my $self = $class->next::method(
f5b61ad7 126 $c, { %$config },
6175bba7 127 );
128
129 # Set base include paths. Local'd in render if needed
130 $self->include_path($config->{INCLUDE_PATH});
f5b61ad7 131
46cdc47d 132 $self->expose_methods($config->{expose_methods});
6175bba7 133 $self->config($config);
134
135 # Creation of template outside of call to new so that we can pass [ $self ]
136 # as INCLUDE_PATH config item, which then gets ->paths() called to get list
137 # of include paths to search for templates.
f5b61ad7 138
6175bba7 139 # Use a weakend copy of self so we dont have loops preventing GC from working
140 my $copy = $self;
141 Scalar::Util::weaken($copy);
142 $config->{INCLUDE_PATH} = [ sub { $copy->paths } ];
143
bd4ee63a 144 if ( $config->{PROVIDERS} ) {
145 my @providers = ();
146 if ( ref($config->{PROVIDERS}) eq 'ARRAY') {
147 foreach my $p (@{$config->{PROVIDERS}}) {
148 my $pname = $p->{name};
149 my $prov = 'Template::Provider';
150 if($pname eq '_file_')
151 {
152 $p->{args} = { %$config };
153 }
154 else
155 {
51199593 156 if($pname =~ s/^\+//) {
157 $prov = $pname;
158 }
159 else
160 {
161 $prov .= "::$pname";
162 }
6175bba7 163 # We copy the args people want from the config
164 # to the args
165 $p->{args} ||= {};
166 if ($p->{copy_config}) {
167 map { $p->{args}->{$_} = $config->{$_} }
168 grep { exists $config->{$_} }
169 @{ $p->{copy_config} };
170 }
bd4ee63a 171 }
fc0ffed0 172 local $@;
bd4ee63a 173 eval "require $prov";
174 if(!$@) {
175 push @providers, "$prov"->new($p->{args});
176 }
177 else
178 {
179 $c->log->warn("Can't load $prov, ($@)");
180 }
181 }
182 }
183 delete $config->{PROVIDERS};
184 if(@providers) {
185 $config->{LOAD_TEMPLATES} = \@providers;
186 }
187 }
f5b61ad7 188
189 $self->{template} =
bd4ee63a 190 Template->new($config) || do {
191 my $error = Template->error();
192 $c->log->error($error);
193 $c->error($error);
194 return undef;
195 };
196
197
198 return $self;
199}
200
201sub process {
202 my ( $self, $c ) = @_;
203
204 my $template = $c->stash->{template}
205 || $c->action . $self->config->{TEMPLATE_EXTENSION};
206
207 unless (defined $template) {
208 $c->log->debug('No template specified for rendering') if $c->debug;
209 return 0;
210 }
211
fc0ffed0 212 local $@;
cad820fe 213 my $output = eval { $self->render($c, $template) };
214 if (my $err = $@) {
c5c3c6bd 215 return $self->_rendering_error($c, $template . ': ' . $err);
316f014a 216 }
217 if (blessed($output) && $output->isa('Template::Exception')) {
218 $self->_rendering_error($c, $output);
bd4ee63a 219 }
220
221 unless ( $c->response->content_type ) {
222 $c->response->content_type('text/html; charset=utf-8');
223 }
224
225 $c->response->body($output);
226
227 return 1;
228}
229
316f014a 230sub _rendering_error {
231 my ($self, $c, $err) = @_;
232 my $error = qq/Couldn't render template "$err"/;
233 $c->log->error($error);
234 $c->error($error);
235 return 0;
236}
237
bd4ee63a 238sub render {
239 my ($self, $c, $template, $args) = @_;
240
cbb149dc 241 $c->log->debug(qq/Rendering template "$template"/) if $c && $c->debug;
bd4ee63a 242
243 my $output;
f5b61ad7 244 my $vars = {
bd4ee63a 245 (ref $args eq 'HASH' ? %$args : %{ $c->stash() }),
246 $self->template_vars($c)
247 };
248
f5b61ad7 249 local $self->{include_path} =
bd4ee63a 250 [ @{ $vars->{additional_template_paths} }, @{ $self->{include_path} } ]
251 if ref $vars->{additional_template_paths};
252
596ff245 253 unless ( $self->template->process( $template, $vars, \$output ) ) {
254 if (exists $self->{render_die}) {
255 die $self->template->error if $self->{render_die};
256 return $self->template->error;
257 }
131a8e59 258 $c->log->debug('The Catalyst::View::TT render() method will start dying on error in a future release. Unless you are calling the render() method manually, you probably want the new behaviour, so set render_die => 1 in config for ' . blessed($self) . '. If you wish to continue to return the exception rather than throwing it, add render_die => 0 to your config.') if $c->debug;
596ff245 259 return $self->template->error;
260 }
cad820fe 261 return $output;
bd4ee63a 262}
263
264sub template_vars {
265 my ( $self, $c ) = @_;
266
cbb149dc 267 return () unless $c;
bd4ee63a 268 my $cvar = $self->config->{CATALYST_VAR};
269
a6fa99df 270 my %vars = defined $cvar
bd4ee63a 271 ? ( $cvar => $c )
272 : (
273 c => $c,
274 base => $c->req->base,
275 name => $c->config->{name}
a6fa99df 276 );
277
46cdc47d 278 if ($self->expose_methods) {
a6fa99df 279 my $meta = $self->meta;
46cdc47d 280 foreach my $method_name (@{$self->expose_methods}) {
a6fa99df 281 my $method = $meta->get_method( $method_name );
282 unless ($method) {
283 Catalyst::Exception->throw( "$method_name not found in TT view" );
284 }
285 my $method_body = $method->body;
286 my $sub = sub {
287 $self->$method_body($c, @_);
288 };
289 $vars{$method_name} = $sub;
290 }
291 }
292 return %vars;
bd4ee63a 293}
294
bd4ee63a 2951;
296
297__END__
298
8cd017a8 299=head1 DESCRIPTION
300
301This is the Catalyst view class for the L<Template Toolkit|Template>.
302Your application should defined a view class which is a subclass of
226c1dd3 303this module. Throughout this manual it will be assumed that your application
304is named F<MyApp> and you are creating a TT view named F<Web>; these names
305are placeholders and should always be replaced with whatever name you've
306chosen for your application and your view. The easiest way to create a TT
307view class is through the F<myapp_create.pl> script that is created along
308with the application:
8cd017a8 309
226c1dd3 310 $ script/myapp_create.pl view Web TT
8cd017a8 311
226c1dd3 312This creates a F<MyApp::View::Web.pm> module in the F<lib> directory (again,
8cd017a8 313replacing C<MyApp> with the name of your application) which looks
314something like this:
315
226c1dd3 316 package FooBar::View::Web;
f5b61ad7 317
8cd017a8 318 use strict;
c18eae32 319 use warnings;
f5b61ad7 320
c18eae32 321 use base 'Catalyst::View::TT';
8077080c 322
a1b7968f 323 __PACKAGE__->config(DEBUG => 'all');
8077080c 324
8cd017a8 325Now you can modify your action handlers in the main application and/or
326controllers to forward to your view class. You might choose to do this
327in the end() method, for example, to automatically forward all actions
328to the TT view class.
722fede4 329
8cd017a8 330 # In MyApp or MyApp::Controller::SomeController
f5b61ad7 331
8cd017a8 332 sub end : Private {
94b3529a 333 my( $self, $c ) = @_;
226c1dd3 334 $c->forward( $c->view('Web') );
8cd017a8 335 }
8077080c 336
2844488f 337But if you are using the standard auto-generated end action, you don't even need
338to do this!
339
340 # in MyApp::Controller::Root
341 sub end : ActionClass('RenderView') {} # no need to change this line
342
343 # in MyApp.pm
344 __PACKAGE__->config(
345 ...
226c1dd3 346 default_view => 'Web',
2844488f 347 );
348
349This will Just Work. And it has the advantages that:
350
351=over 4
352
353=item *
354
355If you want to use a different view for a given request, just set
356<< $c->stash->{current_view} >>. (See L<Catalyst>'s C<< $c->view >> method
357for details.
358
359=item *
360
361<< $c->res->redirect >> is handled by default. If you just forward to
226c1dd3 362C<View::Web> in your C<end> routine, you could break this by sending additional
2844488f 363content.
364
365=back
366
367See L<Catalyst::Action::RenderView> for more details.
368
8cd017a8 369=head2 CONFIGURATION
4687ac0d 370
8cd017a8 371There are a three different ways to configure your view class. The
372first way is to call the C<config()> method in the view subclass. This
373happens when the module is first loaded.
8077080c 374
226c1dd3 375 package MyApp::View::Web;
f5b61ad7 376
8cd017a8 377 use strict;
378 use base 'Catalyst::View::TT';
722fede4 379
226c1dd3 380 __PACKAGE__->config({
7d8aa5ec 381 INCLUDE_PATH => [
382 MyApp->path_to( 'root', 'templates', 'lib' ),
383 MyApp->path_to( 'root', 'templates', 'src' ),
384 ],
8cd017a8 385 PRE_PROCESS => 'config/main',
386 WRAPPER => 'site/wrapper',
387 });
388
226c1dd3 389You may also override the configuration provided in the view class by adding
390a 'View::Web' section to your application config (either in the application
391main class, or in your configuration file). This should be reserved for
392deployment-specific concerns. For example:
8cd017a8 393
226c1dd3 394 # MyApp_local.conf (Config::General format)
f5b61ad7 395
226c1dd3 396 <View Web>
397 WRAPPER "custom_wrapper"
398 INCLUDE_PATH __path_to('root/templates/custom_site')__
399 INCLUDE_PATH __path_to('root/templates')__
400 </View>
8cd017a8 401
226c1dd3 402might be used as part of a simple way to deploy different instances of the
403same application with different themes.
8cd017a8 404
e2bbd784 405=head2 DYNAMIC INCLUDE_PATH
406
f7dfca06 407Sometimes it is desirable to modify INCLUDE_PATH for your templates at run time.
f5b61ad7 408
f7dfca06 409Additional paths can be added to the start of INCLUDE_PATH via the stash as
410follows:
411
412 $c->stash->{additional_template_paths} =
413 [$c->config->{root} . '/test_include_path'];
414
415If you need to add paths to the end of INCLUDE_PATH, there is also an
416include_path() accessor available:
417
226c1dd3 418 push( @{ $c->view('Web')->include_path }, qw/path/ );
f7dfca06 419
420Note that if you use include_path() to add extra paths to INCLUDE_PATH, you
421MUST check for duplicate paths. Without such checking, the above code will add
422"path" to INCLUDE_PATH at every request, causing a memory leak.
423
424A safer approach is to use include_path() to overwrite the array of paths
425rather than adding to it. This eliminates both the need to perform duplicate
426checking and the chance of a memory leak:
e2bbd784 427
226c1dd3 428 @{ $c->view('Web')->include_path } = qw/path another_path/;
e2bbd784 429
f5b61ad7 430If you are calling C<render> directly then you can specify dynamic paths by
9d574573 431having a C<additional_template_paths> key with a value of additonal directories
1bc9fc55 432to search. See L<CAPTURING TEMPLATE OUTPUT> for an example showing this.
433
8cd017a8 434=head2 RENDERING VIEWS
435
436The view plugin renders the template specified in the C<template>
f5b61ad7 437item in the stash.
8cd017a8 438
439 sub message : Global {
94b3529a 440 my ( $self, $c ) = @_;
441 $c->stash->{template} = 'message.tt2';
226c1dd3 442 $c->forward( $c->view('Web') );
8cd017a8 443 }
722fede4 444
c969f23a 445If a stash item isn't defined, then it instead uses the
446stringification of the action dispatched to (as defined by $c->action)
447in the above example, this would be C<message>, but because the default
448is to append '.tt', it would load C<root/message.tt>.
8cd017a8 449
450The items defined in the stash are passed to the Template Toolkit for
451use as template variables.
452
8cd017a8 453 sub default : Private {
94b3529a 454 my ( $self, $c ) = @_;
455 $c->stash->{template} = 'message.tt2';
456 $c->stash->{message} = 'Hello World!';
226c1dd3 457 $c->forward( $c->view('Web') );
8cd017a8 458 }
7b592fc7 459
8cd017a8 460A number of other template variables are also added:
8077080c 461
8cd017a8 462 c A reference to the context object, $c
463 base The URL base, from $c->req->base()
464 name The application name, from $c->config->{ name }
465
466These can be accessed from the template in the usual way:
467
468<message.tt2>:
469
470 The message is: [% message %]
471 The base is [% base %]
472 The name is [% name %]
473
8cd017a8 474
1bc9fc55 475The output generated by the template is stored in C<< $c->response->body >>.
476
477=head2 CAPTURING TEMPLATE OUTPUT
478
479If you wish to use the output of a template for some other purpose than
480displaying in the response, e.g. for sending an email, this is possible using
481L<Catalyst::Plugin::Email> and the L<render> method:
482
483 sub send_email : Local {
484 my ($self, $c) = @_;
f5b61ad7 485
1bc9fc55 486 $c->email(
487 header => [
488 To => 'me@localhost',
489 Subject => 'A TT Email',
490 ],
226c1dd3 491 body => $c->view('Web')->render($c, 'email.tt', {
9d574573 492 additional_template_paths => [ $c->config->{root} . '/email_templates'],
1bc9fc55 493 email_tmpl_param1 => 'foo'
494 }
495 ),
496 );
497 # Redirect or display a message
498 }
8cd017a8 499
500=head2 TEMPLATE PROFILING
501
1bc9fc55 502See L<C<TIMER>> property of the L<config> method.
503
caa61517 504=head2 METHODS
8077080c 505
b63ddd04 506=head2 new
2774dc77 507
f5b61ad7 508The constructor for the TT view. Sets up the template provider,
2774dc77 509and reads the application config.
510
81b7f2a2 511=head2 process($c)
8077080c 512
1bc9fc55 513Renders the template specified in C<< $c->stash->{template} >> or
ad50568f 514C<< $c->action >> (the private name of the matched action). Calls L<render> to
1bc9fc55 515perform actual rendering. Output is stored in C<< $c->response->body >>.
8077080c 516
81b7f2a2 517It is possible to forward to the process method of a TT view from inside
518Catalyst like this:
519
226c1dd3 520 $c->forward('View::Web');
81b7f2a2 521
522N.B. This is usually done automatically by L<Catalyst::Action::RenderView>.
f2ee4d6c 523
b63ddd04 524=head2 render($c, $template, \%args)
1bc9fc55 525
cad820fe 526Renders the given template and returns output. Throws a L<Template::Exception>
f5b61ad7 527object upon error.
1bc9fc55 528
75dc0329 529The template variables are set to C<%$args> if C<$args> is a hashref, or
530C<< $c->stash >> otherwise. In either case the variables are augmented with
3d543eda 531C<base> set to C<< $c->req->base >>, C<c> to C<$c>, and C<name> to
1bc9fc55 532C<< $c->config->{name} >>. Alternately, the C<CATALYST_VAR> configuration item
533can be defined to specify the name of a template variable through which the
3d543eda 534context reference (C<$c>) can be accessed. In this case, the C<c>, C<base>, and
1bc9fc55 535C<name> variables are omitted.
536
f5b61ad7 537C<$template> can be anything that Template::process understands how to
1bc9fc55 538process, including the name of a template file or a reference to a test string.
539See L<Template::process|Template/process> for a full list of supported formats.
540
f59953e1 541To use the render method outside of your Catalyst app, just pass a undef context.
cbb149dc 542This can be useful for tests, for instance.
543
81b7f2a2 544It is possible to forward to the render method of a TT view from inside Catalyst
545to render page fragments like this:
546
226c1dd3 547 my $fragment = $c->forward("View::Web", "render", $template_name, $c->stash->{fragment_data});
f2ee4d6c 548
3715305f 549=head3 Backwards compatibility note
550
551The render method used to just return the Template::Exception object, rather
552than just throwing it. This is now deprecated and instead the render method
553will throw an exception for new applications.
554
555This behaviour can be activated (and is activated in the default skeleton
556configuration) by using C<< render_die => 1 >>. If you rely on the legacy
557behaviour then a warning will be issued.
558
559To silence this warning, set C<< render_die => 0 >>, but it is recommended
560you adjust your code so that it works with C<< render_die => 1 >>.
561
562In a future release, C<< render_die => 1 >> will become the default if
563unspecified.
564
b63ddd04 565=head2 template_vars
850ee226 566
1bc9fc55 567Returns a list of keys/values to be used as the catalyst variables in the
850ee226 568template.
569
b63ddd04 570=head2 config
8077080c 571
8cd017a8 572This method allows your view subclass to pass additional settings to
4729c102 573the TT configuration hash, or to set the options as below:
574
b63ddd04 575=head2 paths
576
577The list of paths TT will look for templates in.
4729c102 578
a6fa99df 579=head2 expose_methods
580
581The list of methods in your View class which should be made available to the templates.
582
583For example:
584
585 expose_methods => [qw/uri_for_static/],
586
587 ...
588
589 sub uri_for_css {
590 my ($self, $c, $filename) = @_;
591
592 # additional complexity like checking file exists here
593
594 return $c->uri_for('/static/css/' . $filename);
595 }
596
597Then in the template:
598
599 [% uri_for_css('home.css') %]
600
f5b61ad7 601=head2 C<CATALYST_VAR>
4729c102 602
603Allows you to change the name of the Catalyst context object. If set, it will also
604remove the base and name aliases, so you will have access them through <context>.
605
226c1dd3 606For example, if CATALYST_VAR has been set to "Catalyst", a template might
607contain:
4729c102 608
609 The base is [% Catalyst.req.base %]
610 The name is [% Catalyst.config.name %]
611
b63ddd04 612=head2 C<TIMER>
4729c102 613
614If you have configured Catalyst for debug output, and turned on the TIMER setting,
615C<Catalyst::View::TT> will enable profiling of template processing
616(using L<Template::Timer>). This will embed HTML comments in the
617output from your templates, such as:
618
619 <!-- TIMER START: process mainmenu/mainmenu.ttml -->
620 <!-- TIMER START: include mainmenu/cssindex.tt -->
621 <!-- TIMER START: process mainmenu/cssindex.tt -->
622 <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
623 <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
624
625 ....
626
627 <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
628
629
b63ddd04 630=head2 C<TEMPLATE_EXTENSION>
4729c102 631
747f2b6d 632a sufix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
4729c102 633
634For example:
635
6229ce0d 636 package MyApp::Controller::Test;
f5b61ad7 637 sub test : Local { .. }
4729c102 638
639Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for
640<root>/test/test.tt.
641
51199593 642=head2 C<PROVIDERS>
643
644Allows you to specify the template providers that TT will use.
645
646 MyApp->config({
647 name => 'MyApp',
648 root => MyApp->path_to('root'),
226c1dd3 649 'View::Web' => {
51199593 650 PROVIDERS => [
651 {
652 name => 'DBI',
653 args => {
654 DBI_DSN => 'dbi:DB2:books',
655 DBI_USER=> 'foo'
656 }
657 }, {
658 name => '_file_',
659 args => {}
660 }
661 ]
662 },
663 });
664
665The 'name' key should correspond to the class name of the provider you
666want to use. The _file_ name is a special case that represents the default
667TT file-based provider. By default the name is will be prefixed with
668'Template::Provider::'. You can fully qualify the name by using a unary
669plus:
670
671 name => '+MyApp::Provider::Foo'
672
6175bba7 673You can also specify the 'copy_config' key as an arrayref, to copy those keys
674from the general config, into the config for the provider:
f5b61ad7 675
6175bba7 676 DEFAULT_ENCODING => 'utf-8',
677 PROVIDERS => [
678 {
679 name => 'Encoding',
680 copy_config => [qw(DEFAULT_ENCODING INCLUDE_PATH)]
681 }
682 ]
f5b61ad7 683
6175bba7 684This can prove useful when you want to use the additional_template_paths hack
685in your own provider, or if you need to use Template::Provider::Encoding
686
8cd017a8 687=head2 HELPERS
688
689The L<Catalyst::Helper::View::TT> and
690L<Catalyst::Helper::View::TTSite> helper modules are provided to create
691your view module. There are invoked by the F<myapp_create.pl> script:
692
226c1dd3 693 $ script/myapp_create.pl view Web TT
8cd017a8 694
226c1dd3 695 $ script/myapp_create.pl view Web TTSite
8cd017a8 696
697The L<Catalyst::Helper::View::TT> module creates a basic TT view
698module. The L<Catalyst::Helper::View::TTSite> module goes a little
699further. It also creates a default set of templates to get you
700started. It also configures the view module to locate the templates
701automatically.
702
02c64502 703=head1 NOTES
704
705If you are using the L<CGI> module inside your templates, you will
706experience that the Catalyst server appears to hang while rendering
707the web page. This is due to the debug mode of L<CGI> (which is
708waiting for input in the terminal window). Turning off the
709debug mode using the "-no_debug" option solves the
710problem, eg.:
711
712 [% USE CGI('-no_debug') %]
713
8077080c 714=head1 SEE ALSO
715
8cd017a8 716L<Catalyst>, L<Catalyst::Helper::View::TT>,
717L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
8077080c 718
c0eb0527 719=head1 AUTHORS
8077080c 720
721Sebastian Riedel, C<sri@cpan.org>
c0eb0527 722
d938377b 723Marcus Ramberg, C<mramberg@cpan.org>
c0eb0527 724
722fede4 725Jesse Sheidlower, C<jester@panix.com>
c0eb0527 726
8cd017a8 727Andy Wardley, C<abw@cpan.org>
8077080c 728
729=head1 COPYRIGHT
730
f5b61ad7 731This program is free software. You can redistribute it and/or modify it
2774dc77 732under the same terms as Perl itself.
8077080c 733
734=cut