File Coverage

blib/lib/HTML/MasonX/Free/Request.pm
Criterion Covered Total %
statement 59 81 72.8
branch 16 36 44.4
condition 1 3 33.3
subroutine 6 6 100.0
pod 1 1 100.0
total 83 127 65.3


line stmt bran cond sub pod time code
1 3     3   1084 use strict;
  3         4  
  3         64  
2 3     3   9 use warnings;
  3         3  
  3         112  
3             package HTML::MasonX::Free::Request;
4             $HTML::MasonX::Free::Request::VERSION = '0.006';
5             # ABSTRACT: a request class that eliminates the wrapping chain
6 3     3   9 use parent 'HTML::Mason::Request';
  3         2  
  3         13  
7              
8             #pod =head1 OVERVIEW
9             #pod
10             #pod You don't want to know about this class. The basic thing is: if you're using
11             #pod L<HTML::MasonX::Free::Resolver>, you should use this.
12             #pod
13             #pod If you want a little more information: this gets rid of the notion of
14             #pod automatically execing the whole wrapping chain (like autohandlers) for
15             #pod components. It's gross, but it can make things a fair bit simpler.
16             #pod
17             #pod =cut
18              
19 3     3   147 use Log::Any qw($log);
  3         7  
  3         31  
20 3         15 use HTML::Mason::Exceptions( abbr => [qw(error param_error syntax_error
21 3     3   560 top_level_not_found_error error)] );
  3         3  
22              
23             # BEGIN DIRECT THEFT FROM HTML-Mason 1.50
24             sub exec {
25 23     23 1 6931 my ($self) = @_;
26              
27             # If the request failed to initialize, the error has already been handled
28             # at the bottom of _initialize(); just return.
29 23 50       47 return unless $self->initialized();
30              
31 23 50       94 local $SIG{'__DIE__'} = $self->component_error_handler
32             if $self->component_error_handler;
33              
34             # Cheap way to prevent users from executing the same request twice.
35             #
36 23 50       196 if ($self->{execd}++) {
37 0         0 error "Can only call exec() once for a given request object. Did you want to use a subrequest?";
38             }
39              
40             # Check for infinite subrequest loop.
41             #
42 23 50       45 error "subrequest depth > " . $self->max_recurse . " (infinite subrequest loop?)"
43             if $self->request_depth > $self->max_recurse;
44              
45             #
46             # $m is a dynamically scoped global containing this
47             # request. This needs to be defined in the HTML::Mason::Commands
48             # package, as well as the component package if that is different.
49             #
50 23         110 local $HTML::Mason::Commands::m = $self;
51              
52             # Dynamically scoped global pointing at the top of the request stack.
53             #
54 23         21 $self->{top_stack} = undef;
55              
56             # Save context of subroutine for use inside eval.
57 23         21 my $wantarray = wantarray;
58 23         14 my @result;
59              
60             # Initialize output buffer to interpreter's preallocated buffer
61             # before clearing, to reduce memory reallocations.
62             #
63 23         37 $self->{request_buffer} = $self->interp->preallocated_output_buffer;
64 23         82 $self->{request_buffer} = '';
65              
66 23 50       64 $log->debugf("starting request for '%s'", $self->request_comp->title)
67             if $log->is_debug;
68              
69 23         144 eval {
70             # Build wrapper chain and index.
71 23         41 my $request_comp = $self->request_comp;
72 23         43 my $first_comp;
73             {
74 23         18 my @wrapper_chain = ($request_comp);
  23         26  
75              
76             ## XXX: eliminated for(;;) loop here -- rjbs, 2012-09-24
77 23         16 $first_comp = $wrapper_chain[0];
78 23         33 $self->{wrapper_chain} = [@wrapper_chain];
79             $self->{wrapper_index} = { map
80 23         40 { $wrapper_chain[$_]->comp_id => $_ }
  23         52  
81             (0..$#wrapper_chain)
82             };
83             }
84              
85             # Get original request_args array reference to avoid copying.
86 23         102 my $request_args = $self->{request_args};
87             {
88 23         18 local *SELECTED;
  23         38  
89 23         147 tie *SELECTED, 'Tie::Handle::Mason';
90              
91 23         114 my $old = select SELECTED;
92 23         59 my $mods = {base_comp => $request_comp, store => \($self->{request_buffer}), flushable => 1};
93              
94 23 50       45 if ($self->{has_plugins}) {
95 0         0 my $context = bless
96             [$self, $request_args],
97             'HTML::Mason::Plugin::Context::StartRequest';
98 0         0 eval {
99 0         0 foreach my $plugin_instance (@{$self->plugin_instances}) {
  0         0  
100 0         0 $plugin_instance->start_request_hook( $context );
101             }
102             };
103 0 0       0 if ($@) {
104 0         0 select $old;
105 0         0 rethrow_exception $@;
106             }
107             }
108              
109 23 50       54 if ($wantarray) {
    50          
110 0         0 @result = eval {$self->comp($mods, $first_comp, @$request_args)};
  0         0  
111             } elsif (defined($wantarray)) {
112 0         0 $result[0] = eval {$self->comp($mods, $first_comp, @$request_args)};
  0         0  
113             } else {
114 23         24 eval {$self->comp($mods, $first_comp, @$request_args)};
  23         71  
115             }
116            
117 23         352 my $error = $@;
118              
119 23 50       42 if ($self->{has_plugins}) {
120             # plugins called in reverse order when exiting.
121             my $context = bless
122 0         0 [$self, $request_args, \$self->{request_buffer}, $wantarray, \@result, \$error],
123             'HTML::Mason::Plugin::Context::EndRequest';
124 0         0 eval {
125 0         0 foreach my $plugin_instance (@{$self->{plugin_instances_reverse}}) {
  0         0  
126 0         0 $plugin_instance->end_request_hook( $context );
127             }
128             };
129 0 0       0 if ($@) {
130             # plugin errors take precedence over component errors
131 0         0 $error = $@;
132             }
133             }
134            
135 23         65 select $old;
136 23         55 rethrow_exception $error;
137             }
138             };
139              
140 23 50       167 $log->debugf("finishing request for '%s'", $self->request_comp->title)
141             if $log->is_debug;
142              
143             # Purge code cache if necessary.
144 23         152 $self->interp->purge_code_cache;
145              
146             # Handle errors.
147 23         118 my $err = $@;
148 23 50 33     46 if ($err and !$self->_aborted_or_declined($err)) {
149 0         0 $self->_handle_error($err);
150 0         0 return;
151             }
152              
153             # If there's anything in the output buffer, send it to out_method.
154             # Otherwise skip out_method call to avoid triggering side effects
155             # (e.g. HTTP header sending).
156 23 50       43 if (length($self->{request_buffer}) > 0) {
157 23         61 $self->out_method->($self->{request_buffer});
158             }
159              
160             # Return aborted value or result.
161 23 50       141 @result = ($err->aborted_value) if $self->aborted($err);
162 23 50       362 @result = ($err->declined_value) if $self->declined($err);
163 23 50       309 return $wantarray ? @result : defined($wantarray) ? $result[0] : undef;
    50          
164             }
165             # BEGIN DIRECT THEFT FROM HTML-Mason 1.50
166              
167             1;
168              
169             __END__
170              
171             =pod
172              
173             =encoding UTF-8
174              
175             =head1 NAME
176              
177             HTML::MasonX::Free::Request - a request class that eliminates the wrapping chain
178              
179             =head1 VERSION
180              
181             version 0.006
182              
183             =head1 OVERVIEW
184              
185             You don't want to know about this class. The basic thing is: if you're using
186             L<HTML::MasonX::Free::Resolver>, you should use this.
187              
188             If you want a little more information: this gets rid of the notion of
189             automatically execing the whole wrapping chain (like autohandlers) for
190             components. It's gross, but it can make things a fair bit simpler.
191              
192             =head1 AUTHOR
193              
194             Ricardo Signes <rjbs@cpan.org>
195              
196             =head1 COPYRIGHT AND LICENSE
197              
198             This software is copyright (c) 2016 by Ricardo Signes.
199              
200             This is free software; you can redistribute it and/or modify it under
201             the same terms as the Perl 5 programming language system itself.
202              
203             =cut