File Coverage

blib/lib/Catalyst/View/Mason.pm
Criterion Covered Total %
statement 21 76 27.6
branch 0 22 0.0
condition 0 6 0.0
subroutine 7 12 58.3
pod n/a
total 28 116 24.1


line stmt bran cond sub pod time code
1             package Catalyst::View::Mason;
2              
3 1     1   906 use strict;
  1         2  
  1         36  
4 1     1   5 use warnings;
  1         2  
  1         32  
5 1     1   15 use base qw/Catalyst::View/;
  1         1  
  1         577  
6 1     1   6 use Scalar::Util qw/blessed/;
  1         1  
  1         84  
7 1     1   5 use File::Spec;
  1         7  
  1         24  
8 1     1   794 use HTML::Mason;
  1         408962  
  1         70  
9 1     1   7689 use MRO::Compat;
  1         5150  
  1         1292  
10              
11             our $VERSION = '0.18';
12              
13             __PACKAGE__->mk_accessors('template');
14              
15             =head1 NAME
16              
17             Catalyst::View::Mason - Mason View Class
18              
19             =head1 SYNOPSIS
20              
21             # use the helper
22             script/create.pl view Mason Mason
23              
24             # lib/MyApp/View/Mason.pm
25             package MyApp::View::Mason;
26              
27             use base 'Catalyst::View::Mason';
28              
29             __PACKAGE__->config(use_match => 0);
30              
31             1;
32              
33             $c->forward('MyApp::View::Mason');
34              
35             =head1 DESCRIPTION
36              
37             Want to use a Mason component in your views? No problem!
38             Catalyst::View::Mason comes to the rescue.
39              
40             =head1 EXAMPLE
41              
42             From the Catalyst controller:
43              
44             $c->stash->{name} = 'Homer'; # Pass a scalar
45             $c->stash->{extra_info} = {
46             last_name => 'Simpson',
47             children => [qw(Bart Lisa Maggie)]
48             }; # A ref works too
49              
50             From the Mason template:
51              
52             <%args>
53             $name
54             $extra_info
55             </%args>
56             <p>Your name is <strong><% $name %> <% $extra_info->{last_name} %></strong>
57             <p>Your children are:
58             <ul>
59             % foreach my $child (@{$extra_info->{children}}) {
60             <li><% $child %></li>
61             % }
62             </ul>
63              
64             =head1 METHODS
65              
66             =cut
67              
68             =head2 new($app, \%config)
69              
70             =cut
71              
72             sub new {
73 0     0     my ($self, $app, $arguments) = @_;
74              
75 0           my %config = (
76             comp_root => $app->config->{root},
77             data_dir => File::Spec->catdir(
78             File::Spec->tmpdir,
79             sprintf('%s_%d_mason_data_dir', $app, $<),
80             ),
81             use_match => 0,
82             allow_globals => [],
83             template_extension => q//,
84             always_append_template_extension => 0,
85 0           %{ $self->config },
86 0           %{ $arguments },
87             );
88              
89             # stringify data_dir
90 0           $config{data_dir} .= q//;
91              
92             # stringify comp_root if it isn't an unblessed array reference already
93 0 0 0       $config{comp_root} .= q//
94             if blessed($config{comp_root}) || ref $config{comp_root} ne 'ARRAY';
95              
96 0           unshift @{ $config{allow_globals} }, qw/$c $base $name/;
  0            
97 0           $self = $self->next::method($app, \%config);
98 0           $self->{output} = q//;
99              
100 0           $self->config({ %config });
101              
102             # those are config options for the view, not mason itself.
103 0           delete @config{qw/
104             use_match
105             template_extension
106             always_append_template_extension
107             catalyst_component_name
108             /};
109              
110 0 0         if ($self->config->{use_match}) {
111 0           $app->log->warn(sprintf(<<'EOW', ref $self));
112             DEPRECATION WARNING: %s sets the use_match config variable to a true value.
113             This has been deprecated. Please see the Catalyst::View::Mason
114             documentation for details on use_match.
115             EOW
116             }
117              
118             $self->template(
119 0           HTML::Mason::Interp->new(
120             %config,
121             out_method => \$self->{output},
122             )
123             );
124              
125 0           return $self;
126             }
127              
128             =head2 get_component_path
129              
130             Returns the component path from $c->stash->{template} or
131             $c->request->match or $c->action (depending on the use_match setting).
132              
133             =cut
134              
135             sub get_component_path {
136 0     0     my ($self, $c) = @_;
137              
138 0           my $component_path = $c->stash->{template};
139 0           my $extension = $self->config->{template_extension};
140              
141 0 0         if (defined $component_path) {
142 0 0         $component_path .= $extension
143             if $self->config->{always_append_template_extension};
144             }
145             else {
146 0 0         $component_path = $self->config->{use_match}
147             ? $c->request->match
148             : $c->action;
149              
150 0           $component_path .= $extension;
151             }
152              
153 0           return $component_path;
154             }
155              
156             =head2 process
157              
158             Renders the component specified in $c->stash->{template} or $c->request->match
159             or $c->action (depending on the use_match setting) to $c->response->body.
160              
161             Note that the component name must be absolute, or is converted to absolute
162             (i.e., a / is added to the beginning if it doesn't start with one).
163              
164             Mason global variables C<$base>, C<$c>, and C<$name> are automatically
165             set to the base, context, and name of the app, respectively.
166              
167             =cut
168              
169             sub process {
170 0     0     my ($self, $c) = @_;
171              
172 0           my $component_path = $self->get_component_path($c);
173 0           my $output = $self->render($c, $component_path);
174              
175 0 0 0       if (blessed($output) && $output->isa('HTML::Mason::Exception')) {
176 0           chomp $output;
177 0           my $error = qq/Couldn't render component "$component_path" - error was "$output"/;
178 0           $c->log->error($error);
179 0           $c->error($error);
180 0           return 0;
181             }
182              
183 0 0         unless ($c->response->content_type) {
184 0           $c->response->content_type('text/html; charset=utf-8');
185             }
186              
187 0           $c->response->body($output);
188              
189 0           return 1;
190             }
191              
192             =head2 render($c, $component_path, \%args)
193              
194             Renders the given template and returns output, or a HTML::Mason::Exception
195             object upon error.
196              
197             The template variables are set to %$args if $args is a hashref, or
198             $c-E<gt>stash otherwise.
199              
200             =cut
201              
202             sub _default_globals {
203 0     0     my ($self, $c) = @_;
204              
205 0           my %default_globals = (
206             '$c' => $c,
207             '$base' => $c->request->base,
208             '$name' => $c->config->{name},
209             );
210              
211 0           return %default_globals;
212             }
213              
214             sub render {
215 0     0     my ($self, $c, $component_path, $args) = @_;
216              
217 0 0         if ($component_path !~ m{^/}) {
218 0           $component_path = '/' . $component_path;
219             }
220              
221 0 0         $c->log->debug(qq/Rendering component "$component_path"/) if $c->debug;
222              
223             # Set the URL base, context and name of the app as global Mason vars
224             # $base, $c and $name
225 0           my %default_globals = $self->_default_globals($c);
226 0           while (my ($key, $val) = each %default_globals) {
227 0           $self->template->set_global($key => $val);
228             }
229              
230 0           $self->{output} = q//;
231              
232 0           eval {
233 0           $self->template->exec(
234             $component_path,
235 0 0         ref $args eq 'HASH' ? %{ $args } : %{ $c->stash },
  0            
236             );
237             };
238              
239 0 0         if (my $error = $@) {
240 0           return $error;
241             }
242              
243 0           return $self->{output};
244             }
245              
246             =head3 config
247              
248             This allows you to to pass additional settings to the HTML::Mason::Interp
249             constructor or to set the options as below:
250              
251             =over
252              
253             =item C<template_extension>
254              
255             This string is appended (if present) to C<< $c->action >> when generating a
256             template path.
257              
258             Defaults to an empty string.
259              
260             Example: C<< template_extension => '.html' >>
261              
262             =item C<always_append_template_extension>
263              
264             Set this to a true value if you want C<template_extension> to be appended to
265             the component path even if it was explicitly set.
266              
267             Defaults to 0.
268              
269             Example: C<< always_append_template_extension => 1 >>
270              
271             =item C<use_match>
272              
273             Use C<$c-E<gt>request-E<gt>match> instead of C<$c-E<gt>action> to determine
274             which template to use if C<$c-E<gt>stash-E<gt>{template}> isn't set. This option
275             is deprecated and exists for backward compatibility only.
276              
277             Currently defaults to 0. Old code should set this to 1 to avoid breakage.
278              
279             Example: C<< use_match => 0 >>
280              
281             =back
282              
283             The default HTML::Mason::Interp config options are as follows:
284              
285             =over
286              
287             =item C<comp_root>
288              
289             C<$app-E<gt>config-E<gt>root>
290              
291             =item C<data_dir>
292              
293             C<File::Spec-E<gt>catdir( File::Spec-E<gt>tmpdir, sprintf('%s_%d_mason_data_dir', $app, $E<lt>) )>
294              
295             =item C<allow_globals>
296              
297             C<qw/$c $name $base/>
298              
299             If you add additional allowed globals those will be appended to the list of
300             default globals.
301              
302             =back
303              
304             =cut
305              
306             =head1 SEE ALSO
307              
308             L<Catalyst>, L<HTML::Mason>, "Using Mason from a Standalone Script" in L<HTML::Mason::Admin>
309              
310             =head1 AUTHORS
311              
312             =over 4
313              
314             =item Andres Kievsky C<ank@cpan.org>
315              
316             =item Sebastian Riedel C<sri@cpan.org>
317              
318             =item Marcus Ramberg
319              
320             =item Florian Ragwitz C<rafl@debian.org>
321              
322             =item Justin Hunter C<justin.d.hunter@gmail.com>
323              
324             =back
325              
326             =head1 COPYRIGHT
327              
328             This program is free software, you can redistribute it and/or modify it under
329             the same terms as Perl itself.
330              
331             =cut
332              
333             1;