File Coverage

blib/lib/Mason/Request.pm
Criterion Covered Total %
statement 334 345 96.8
branch 39 48 81.2
condition 9 15 60.0
subroutine 104 108 96.3
pod n/a
total 486 516 94.1


line stmt bran cond sub pod time code
1             package Mason::Request;
2             $Mason::Request::VERSION = '2.24';
3 20     20   120 use Carp;
  20         68  
  20         1640  
4 20     20   107 use File::Basename;
  20         31  
  20         1103  
5 20     20   103 use Guard;
  20         27  
  20         837  
6 20     20   10266 use Log::Any qw($log);
  20         32919  
  20         78  
7 20     20   8129 use Mason::Exceptions;
  20         54  
  20         577  
8 20     20   8287 use Mason::TieHandle;
  20         40  
  20         495  
9 20     20   6294 use Mason::Types;
  20         56  
  20         977  
10 20     20   164 use Mason::Moose;
  20         36  
  20         181  
11 20     20   32649 use Scalar::Util qw(blessed reftype weaken);
  20         79  
  20         1425  
12 20     20   192 use Try::Tiny;
  20         32  
  20         5589  
13              
14             my $default_out = sub { my ( $text, $self ) = @_; $self->result->_append_output($text) };
15             my $next_id = 0;
16              
17             # Passed attributes
18             #
19             has 'interp' => ( required => 1, weak_ref => 1 );
20             has 'out_method' => ( isa => 'Mason::Types::OutMethod', default => sub { $default_out }, coerce => 1 );
21              
22             # Derived attributes
23             #
24             has 'buffer_stack' => ( init_arg => undef, default => sub { [] } );
25             has 'declined' => ( init_arg => undef, is => 'rw' );
26             has 'declined_paths' => ( default => sub { {} } );
27             has 'go_result' => ( init_arg => undef );
28             has 'id' => ( init_arg => undef, default => sub { $next_id++ } );
29             has 'output' => ( init_arg => undef, default => '' );
30             has 'page' => ( init_arg => undef );
31             has 'path_info' => ( init_arg => undef, default => '' );
32             has 'request_args' => ( init_arg => undef );
33             has 'request_code_cache' => ( init_arg => undef, default => sub { {} } );
34             has 'request_path' => ( init_arg => undef );
35             has 'result' => ( init_arg => undef, lazy_build => 1 );
36             has 'run_params' => ( init_arg => undef );
37              
38             # Globals, localized to each request
39             #
40             our ( $current_request, $current_buffer );
41 20     20   6936 method current_request () { $current_request }
  0     0   0  
  0         0  
  0         0  
42              
43             #
44             # BUILD
45             #
46              
47 20     20   6427 method BUILD ($params) {
  185     185   367  
  185         324  
  185         222  
48              
49             # Make a copy of params sans interp
50             #
51 185         482 $self->{orig_request_params} = $params;
52 185         5858 delete( $self->{orig_request_params}->{interp} );
53             }
54              
55 20     20   6194 method _build_result () {
  127     127   236  
  127         203  
56 127         3418 return $self->interp->result_class->new;
57             }
58              
59             #
60             # PUBLIC METHODS
61             #
62              
63 20     20   6015 method abort ($aborted_value) {
  24     24   44  
  24         50  
  24         32  
64 24         281 Mason::Exception::Abort->throw(
65             error => 'Request->abort was called',
66             aborted_value => $aborted_value
67             );
68             }
69              
70 20     20   6901 method aborted ($err) {
  31     31   54  
  31         55  
  31         50  
71 31   100     367 return blessed($err) && $err->isa('Mason::Exception::Abort');
72             }
73              
74 20     20   6484 method add_cleanup ($code) {
  1     1   2  
  1         3  
  1         8  
75 1         2 push( @{ $self->{cleanups} }, $code );
  1         9  
76             }
77              
78 20     20   6133 method cache () {
  0     0   0  
  0         0  
79 0         0 die 'caching is now in the cache plugin (Mason::Plugin::Cache)';
80             }
81              
82 20     20   7111 method capture ($code) {
  36     36   43  
  36         48  
  36         36  
83 36 50 33     198 croak "capture() expects a code reference" unless defined($code) && ref($code) eq 'CODE';
84 36         35 my $output;
85             {
86 36         34 $self->_push_buffer;
  36         77  
87 36     36   131 scope_guard { $output = ${ $self->_current_buffer }; $self->_pop_buffer; };
  36         42  
  36         104  
  36         95  
88 36         49 $code->();
89             }
90 36         208 return $output;
91             }
92              
93 20     20   7509 method clear_and_abort () {
  21     21   39  
  21         27  
94 21         82 $self->clear_buffer;
95 21         97 $self->abort(@_);
96             }
97              
98 20     20   5798 method clear_buffer () {
  24     24   44  
  24         38  
99 24         34 foreach my $buffer ( @{ $self->buffer_stack } ) {
  24         585  
100 24         69 $$buffer = '';
101             }
102             }
103              
104 20     20   6184 method comp () {
  37     37   68  
  37         47  
105 37         153 $self->construct(@_)->main();
106             }
107              
108 20     20   5886 method comp_exists ($path) {
  6     6   7  
  6         8  
  6         4  
109 6         142 return $self->interp->comp_exists( $self->rel_to_abs($path) );
110             }
111              
112 20     20   6061 method construct () {
  37     37   56  
  37         46  
113 37         51 my $path = shift;
114 37 100       189 my $compc = $self->load($path)
115             or $self->_comp_not_found($path);
116 34         1536 return $compc->new( @_, 'm' => $self );
117             }
118              
119 20     20   6136 method current_comp_class () {
  19     19   26  
  19         24  
120 19         25 my $cnt = 1;
121 19         23 while (1) {
122 82 100       147 if ( my $pkg = ( caller($cnt) )[0] ) {
123 81 100 66     1659 return $pkg if $pkg->isa('Mason::Component') && $pkg ne 'Mason::Component';
124             }
125             else {
126 1         113 confess("cannot determine current_comp_class from stack");
127             }
128 63         102 $cnt++;
129             }
130             }
131              
132 20     20   6989 method decline () {
  21     21   49  
  21         28  
133 21         622 $self->declined(1);
134 21         86 $self->clear_and_abort;
135             }
136              
137 20     20   5819 method filter () {
  2     2   3  
  2         2  
138 2         8 $self->_apply_filters(@_);
139             }
140              
141 20     20   5946 method flush_buffer () {
  127     127   854  
  127         205  
142 127         707 my $request_buffer = $self->_request_buffer;
143 127         536 $self->process_output($request_buffer);
144 127 100       4064 $self->out_method->( $$request_buffer, $self )
145             if length $$request_buffer;
146 127         372 $$request_buffer = '';
147             }
148              
149 20     20   6436 method go () {
  3     3   5  
  3         5  
150 3         12 $self->clear_buffer;
151 3         3 my %request_params = ( %{ $self->{orig_request_params} } );
  3         13  
152 3 100       9 if ( ref( $_[0] ) eq 'HASH' ) {
153 1         3 %request_params = ( %request_params, %{ shift(@_) } );
  1         3  
154             }
155 3         13 $self->{go_result} = $self->_run_subrequest( \%request_params, @_ );
156 3         16 $self->abort();
157             }
158              
159 20     20   7166 method load ($path) {
  37     37   59  
  37         64  
  37         49  
160 37         1099 my $compc = $self->interp->load( $self->rel_to_abs($path) );
161             }
162              
163 20     20   7013 method log () {
  1     1   2  
  1         2  
164 1         5 return $self->current_comp_class->cmeta->log();
165             }
166              
167 20     20   5850 method notes () {
  5     5   6  
  5         4  
168 5 50       11 return $self->{notes}
169             unless @_;
170 5         4 my $key = shift;
171 5 100       19 return $self->{notes}->{$key} unless @_;
172 2         7 return $self->{notes}->{$key} = shift;
173             }
174              
175 20     20   6365 method print () {
  44     44   116  
  44         46  
176 44         118 my $buffer = $self->_current_buffer;
177 44         86 for (@_) {
178 44 100       210 $$buffer .= $_ if defined;
179             }
180             }
181              
182 20     20   6601 method rel_to_abs ($path) {
  49     49   74  
  49         84  
  49         55  
183 49 100       216 $path = join( "/", $self->current_comp_class->cmeta->dir_path, $path )
184             unless substr( $path, 0, 1 ) eq '/';
185 49         810 return $path;
186             }
187              
188 20     20   7250 method scomp () {
  3     3   6  
  3         3  
189 3         6 my @params = @_;
190 3     3   20 my $buf = $self->capture( sub { $self->comp(@params) } );
  3         15  
191 3         20 return $buf;
192             }
193              
194 20     20   6778 method visit () {
  3     3   5  
  3         3  
195 3         3 my $buf;
196 3         5 my %request_params = ( %{ $self->{orig_request_params} }, out_method => \$buf );
  3         12  
197 3 100       9 if ( ref( $_[0] ) eq 'HASH' ) {
198 1         2 %request_params = ( %request_params, %{ shift(@_) } );
  1         4  
199             }
200 3         15 my $result = $self->_run_subrequest( \%request_params, @_ );
201 3         12 $self->print($buf);
202 3         78 return $result;
203             }
204              
205             #
206             # MODIFIABLE METHODS
207             #
208              
209 20     20   7227 method cleanup_request () {
  184     184   310  
  184         264  
210 184         4999 $self->interp->_flush_load_cache();
211 184         7202 foreach my $cleanup ( @{ $self->{cleanups} } ) {
  184         1421  
212             try {
213 1     1   37 $cleanup->($self);
214             }
215             catch {
216 0     0   0 warn "error during request cleanup: $_";
217 1         9 };
218             }
219             }
220              
221 20     20   8044 method construct_page_component ($compc, $args) {
  158     158   274  
  158         325  
  158         230  
222 158         5442 return $compc->new( %$args, 'm' => $self );
223             }
224              
225 20     20   6236 method catch_abort ($code) {
  158     158   295  
  158         277  
  158         239  
226 158         238 my $retval;
227             try {
228 158     158   5678 $retval = $code->();
229             }
230             catch {
231 31     31   464 my $err = $_;
232 31 100       166 if ( $self->aborted($err) ) {
233 24         537 $retval = $err->aborted_value;
234             }
235             else {
236 7         49 die $err;
237             }
238 158         1207 };
239 151         3547 return $retval;
240             }
241              
242 20     20   7327 method match_request_path ($request_path) {
  205     205   347  
  205         380  
  205         269  
243 205         5420 $self->interp->match_request_path->( $self, $request_path );
244             }
245              
246 20     20   6020 method process_output ($outref) {
  127     127   191  
  127         262  
  127         181  
247              
248             # No-op by default
249             }
250              
251 20     20   6626 method run () {
  184     184   344  
  184         238  
252              
253             # Get path and either hash or hashref of arguments
254             #
255 184         298 my $request_path = shift;
256 184         5284 $self->interp->_assert_absolute_path($request_path);
257 184         285 my $request_args;
258 184 50 33     757 if ( @_ == 1 && reftype( $_[0] ) eq 'HASH' ) {
259 0         0 $request_args = shift;
260             }
261             else {
262 184         463 $request_args = {@_};
263             }
264              
265             # Save off the requested path and args
266             #
267 184         483 $self->{request_path} = $request_path;
268 184         401 $self->{request_args} = $request_args;
269              
270             # Localize current_request and current_buffer until end of scope. Use a guard
271             # because 'local' doesn't work with the aliases inside components.
272             #
273 184         294 my $save_current_request = $current_request;
274 184         255 my $save_current_buffer = $current_buffer;
275 184     184   1537 scope_guard { $current_request = $save_current_request; $current_buffer = $save_current_buffer };
  184         393  
  184         4915  
276 184         291 $current_request = $self;
277 184         866 $self->_push_buffer();
278              
279             # Clean up after request
280             #
281 184     184   812 scope_guard { $self->cleanup_request() };
  184         19146  
282              
283             # Flush interp load cache
284             #
285 184         5609 $self->interp->_flush_load_cache();
286              
287             # Check the static_source touch file, if it exists, before the
288             # first component is loaded.
289             #
290 184         11959 $self->interp->_check_static_source_touch_file();
291              
292             # Turn request path into a page component
293             #
294 205         969 match_request_path:
295             my $page_path = $self->match_request_path($request_path);
296 158         4651 my $page_compc = $self->interp->load($page_path);
297 158 50       5568 $log->debugf( "starting request with component '%s'", $page_path )
298             if $log->is_debug;
299              
300             $self->catch_abort(
301             sub {
302              
303             # Construct page component
304             #
305 158     158   907 my $page = $self->construct_page_component( $page_compc, $request_args );
306 157         517 $self->{page} = $page;
307              
308             # Dispatch to page component, with 'print' tied to component output.
309             #
310 157         1696 $self->with_tied_print( sub { $page->handle } );
  157         1625  
311             }
312 158         2209 );
313              
314             # If declined, retry match
315             #
316 151 100       5384 if ( $self->declined ) {
317 21         442 $self->declined(0);
318 21         79 $self->{declined_paths}->{$page_path} = 1;
319 21         184 goto match_request_path;
320             }
321              
322             # If go() was called in this request, return the result of the subrequest
323             #
324 130 100       3676 return $self->go_result if defined( $self->go_result );
325              
326             # Send output to its final destination
327             #
328 127         765 $self->flush_buffer;
329              
330 127         3210 return $self->result;
331             }
332              
333 20     20   13362 method with_tied_print ($code) {
  157     157   301  
  157         338  
  157         227  
334 157         464 local *TH;
335 157         1819 tie *TH, 'Mason::TieHandle';
336 157         795 my $old = select TH;
337 157     157   1225 scope_guard { select $old };
  157         27839  
338 157         608 return $code->();
339             }
340              
341             #
342             # PRIVATE METHODS
343             #
344              
345 20     20   7373 method _apply_one_filter ($filter, $yield) {
  42     42   44  
  42         47  
  42         36  
346 42         43 my $filtered_output;
347 42 50       76 if ( ref($yield) ne 'CODE' ) {
348 0 0       0 my $orig_yield = defined($yield) ? $yield : '';
349 0     0   0 $yield = sub { $orig_yield };
  0         0  
350             }
351 42 100 66     157 if ( ref($filter) eq 'CODE' ) {
    100          
352 32         43 local $_ = $yield->();
353 32 50       75 $_ = '' if !defined($_);
354 32         70 $filtered_output = $filter->($_);
355             }
356             elsif ( blessed($filter) && $filter->can('apply_filter') ) {
357 9         22 $filtered_output = $filter->apply_filter($yield);
358             }
359             else {
360 1         15 die "'$filter' is neither a code ref nor a filter object";
361             }
362 41         132 return $filtered_output;
363             }
364              
365 20     20   9285 method _apply_filters () {
  78     78   77  
  78         70  
366 78         83 my $yield = pop(@_);
367 78 100       152 if ( ref($yield) ne 'CODE' ) {
368 1 50       18 my $orig_yield = defined($yield) ? $yield : '';
369 1     1   5 $yield = sub { $orig_yield };
  1         2  
370             }
371 78 100       119 if ( !@_ ) {
372 36         55 return $yield->();
373             }
374             else {
375 42         47 my $filter = pop(@_);
376 42     42   172 return $self->_apply_filters( @_, sub { $self->_apply_one_filter( $filter, $yield ) } );
  42         113  
377             }
378             }
379              
380 20     20   9141 method _apply_filters_to_output () {
  22     22   36  
  22         32  
381 22         32 my $output_method = pop(@_);
382             my $yield = sub {
383 27     27   41 my @args = @_;
384 27         120 $self->capture( sub { $output_method->(@args) } );
  27         51  
385 22         98 };
386 22         81 my $filtered_output = $self->_apply_filters( @_, $yield );
387 21         90 $self->print($filtered_output);
388             }
389              
390 20     20   7653 method _comp_not_found ($path) {
  3     3   69  
  3         15  
  3         3  
391 3         101 croak sprintf( "could not find component for path '%s' - component root is [%s]",
392 3         9 $path, join( ", ", @{ $self->interp->comp_root } ) );
393             }
394              
395 20     20   6894 method _current_buffer () {
  116     116   113  
  116         88  
396 116         262 $self->{buffer_stack}->[-1];
397             }
398              
399 20     20   6151 method _pop_buffer () {
  36     36   42  
  36         35  
400 36         28 pop( @{ $self->{buffer_stack} } );
  36         54  
401 36         59 $current_buffer = $self->_current_buffer;
402             }
403              
404 20     20   6432 method _push_buffer () {
  220     220   360  
  220         308  
405 220         516 my $s = '';
406 220         630 push( @{ $self->{buffer_stack} }, \$s );
  220         655  
407 220         494 $current_buffer = \$s;
408             }
409              
410 20     20   6387 method _request_buffer () {
  129     129   208  
  129         187  
411 129         400 $self->{buffer_stack}->[0];
412             }
413              
414 20     20   5943 method _reset_next_id () {
  6     6   8  
  6         11  
415              
416             # for testing
417 6         15 $next_id = 0;
418             }
419              
420 20     20   5737 method _run_subrequest () {
  6     6   13  
  6         6  
421 6         13 my $request_params = shift(@_);
422 6         20 my $path = $self->rel_to_abs( shift(@_) );
423 6         150 $self->interp->run( $request_params, $path, @_ );
424             }
425              
426             __PACKAGE__->meta->make_immutable();
427              
428             1;
429              
430             __END__
431              
432             =pod
433              
434             =head1 NAME
435              
436             Mason::Request - Mason Request Class
437              
438             =head1 SYNOPSIS
439              
440             $m->abort (...)
441             $m->comp (...)
442             etc.
443              
444             =head1 DESCRIPTION
445              
446             Mason::Request represents a single request for a page, and is the access point
447             for most Mason features not provided by syntactic tags.
448              
449             A Mason request is created when you call C<< $interp->run >>, or in a web
450             environment, for each new web request. A new (sub-)request is also created when
451             you call L<visit|/visit> or L<go|/go> on the current request.
452              
453             Inside a component you can access the current request object via the global
454             C<$m>. Outside of a component, you can use the class method
455             C<Mason::Request-E<gt>current_request>.
456              
457             =head1 COMPONENT PATHS
458              
459             The methods L<comp|/comp>, L<comp_exists|/comp_exists>,
460             L<construct|/construct>, L<go|/go>, L<load|/load>, and L<visit|/visit> take a
461             component path argument. If the path does not begin with a '/', then it is made
462             absolute based on the current component path (using L<rel_to_abs|/rel_to_abs>).
463              
464             Component paths are like URL paths, and always use a forward slash (/) as the
465             separator, regardless of what your operating system uses.
466              
467             =head1 PARAMETERS TO THE new() CONSTRUCTOR
468              
469             These parameters would normally be passed in an initial hashref to C<<
470             $interp->run >>, C<< $m->visit >>, or C<< $m->go >>.
471              
472             =over
473              
474             =item out_method
475              
476             Indicates where to send the page output. If out_method is a scalar reference,
477             output is appended to the scalar. If out_method is a code reference, the code
478             is called with the output string. For example, to send output to a file called
479             "mason.out":
480              
481             open(my $fh, ">", "mason.out);
482             ...
483             out_method => sub { $fh->print($_[0]) }
484              
485             When C<out_method> is unspecified, the output can be obtained from the
486             L<Mason::Result|Mason::Result> object returned from C<< $interp->run >>.
487              
488             =back
489              
490             =head1 PUBLIC METHODS
491              
492             =over
493              
494             =item abort ()
495              
496             Ends the current request, finishing the page without returning through
497             components.
498              
499             C<abort> is implemented by throwing an C<Mason::Exception::Abort> object and
500             can thus be caught by C<eval>. The C<aborted> method is a shortcut for
501             determining whether a caught error was generated by C<abort>.
502              
503             =item aborted ([$err])
504              
505             Returns true or undef indicating whether the specified C<$err> was generated by
506             C<abort>. If no C<$err> was passed, uses C<$@>.
507              
508             In this L<Try::Tiny|Try::Tiny> code, we catch and process fatal errors while
509             letting C<abort> exceptions pass through:
510              
511             try {
512             code_that_may_fail_or_abort()
513             } catch {
514             die $_ if $m->aborted($_);
515             # handle fatal errors...
516             };
517              
518             =item add_cleanup (code)
519              
520             Add a code reference to be executed when the request is L<cleaned
521             up|/cleanup_request>.
522              
523             =item clear_and_abort ()
524              
525             This method is syntactic sugar for calling C<clear_buffer()> and then
526             C<abort()>. If you are aborting the request because of an error (or, in a web
527             environment, to do a redirect), you will often want to clear the buffer first
528             so that any output generated up to that point is not sent to the client.
529              
530             =item capture (code)
531              
532             Execute the I<code>, capturing and returning any Mason output instead of
533             outputting it. e.g. the following
534              
535             my $buf = $m->capture(sub { $m->comp('/foo') });
536              
537             is equivalent to
538              
539             my $buf = $m->scomp('/foo');
540              
541             =item clear_buffer ()
542              
543             Clears the Mason output buffer. Any output sent before this line is discarded.
544             Useful for handling error conditions that can only be detected in the middle of
545             a request.
546              
547             clear_buffer is, of course, thwarted by L<flush_buffer|/flush_buffer>.
548              
549             =item comp (path[, params ...])
550              
551             Creates a new instance of the component designated by I<path>, and calls its
552             C<main> method. I<params>, if any, are passed to the constructor.
553              
554             The C<< <& &> >> tag provides a shortcut for C<$m-E<gt>comp>.
555              
556             =item comp_exists (path)
557              
558             Makes the component I<path> absolute if necessary, and calls L<Interp
559             comp_exists|Mason::Interp/comp_exists> to determine whether a component exists
560             at that path.
561              
562             =item current_comp_class ()
563              
564             Returns the current component class. This is determined by walking up the Perl
565             caller() stack until the first Mason::Component subclass is found.
566              
567             =item current_request ()
568              
569             This class method returns the C<Mason::Request> currently in use. If called
570             when no Mason request is active it will return C<undef>.
571              
572             =item construct (path[, params ...])
573              
574             Constructs and return a new instance of the component designated by I<path>.
575             I<params>, if any, are passed to the constructor. Throws an error if I<path>
576             does not exist.
577              
578             =item decline ()
579              
580             Clears the output buffer and tries the current request again, but acting as if
581             the previously chosen page component(s) do not exist.
582              
583             For example, if the following components exist:
584              
585             /news/sports.mc
586             /news/dhandler.mc
587             /dhandler.mc
588              
589             then a request for path C</news/sports> will initially resolve to
590             C</news/sports.mc>. A call to C<< $m->decline >> would restart the request and
591             resolve to C</news/dhandler.mc>, a second C<< $m->decline >> would resolve to
592             C</dhandler.mc>, and a third would throw a "not found" error.
593              
594             =item filter (filter_expr, [filter_expr...], string|coderef)
595              
596             Applies one or more filters to a string or to a coderef that returns a string.
597              
598             my $filtered_string = $m->filter($.Trim, $.NoBlankLines, $string);
599              
600             =item flush_buffer ()
601              
602             Flushes the main output buffer. Anything currently in the buffer is sent to the
603             request's L<out_method|/out_method>.
604              
605             Note that anything output within a C<< $m->scomp >> or C<< $m->capture >> will
606             not have made it to the main output buffer, and thus cannot be flushed.
607              
608             =item go ([request params], path, args...)
609              
610             Performs an internal redirect. Clears the output buffer, runs a new request for
611             the given I<path> and I<args>, and then L<aborts|/abort> when that request is
612             done.
613              
614             The first argument may optionally be a hashref of parameters which are passed
615             to the C<Mason::Request> constructor.
616              
617             See also L<visit|/visit>.
618              
619             =item interp ()
620              
621             Returns the L<Interp|Mason::Interp> object associated with this request.
622              
623             =item load (path)
624              
625             Makes the component I<path> absolute if necessary, and calls L<Interp
626             load|Mason::Interp/load> to load the component class associated with the path.
627              
628             =item log ()
629              
630             Returns a C<Log::Any> logger with a log category specific to the current
631             component. The category for a component "/foo/bar" would be
632             "Mason::Component::foo::bar".
633              
634             =item notes ([key[, value]])
635              
636             The C<notes()> method provides a place to store application data between
637             components - essentially, a hash which persists for the duration of the
638             request.
639              
640             C<notes($key, $value)> stores a new entry in the hash; C<notes($key)> returns a
641             previously stored value; and C<notes()> without any arguments returns a
642             reference to the entire hash of key-value pairs.
643              
644             Consider storing this kind of data in a read-write attribute of the page
645             component.
646              
647             =item print (string)
648              
649             Add the given I<string> to the Mason output buffer. This happens implicitly for
650             all content placed in the main component body.
651              
652             =item page ()
653              
654             Returns the page component originally called in the request.
655              
656             =item path_info ()
657              
658             Returns the remainder of the request path beyond the path of the page
659             component, with no leading slash. e.g. If a request for '/foo/bar/baz' resolves
660             to "/foo.mc", the path_info is "bar/baz". For an exact match, it will contain
661             the empty string (never undef), so you can determine whether there's a
662             path_info with
663              
664             if ( length($m->path_info) )
665              
666             =item rel_to_abs (path)
667              
668             Converts a component I<path> to absolute form based on the current component,
669             if it does not already begin with a '/'.
670              
671             =item request_args ()
672              
673             Returns the original hashref of arguments passed to the request, e.g. via C<<
674             $interp->run >>.
675              
676             =item request_path ()
677              
678             Returns the original path passed to the request, e.g. in C<< $interp->run >>.
679              
680             =item scomp (comp, args...)
681              
682             Like L<comp|Mason::Request/item_comp>, but returns the component output as a
683             string instead of printing it. (Think sprintf versus printf.)
684              
685             See also L<capture|/capture>.
686              
687             =item visit ([request params], path, args...)
688              
689             Performs a subrequest with the given I<path> and I<args>, with output being
690             sent to the current output buffer.
691              
692             The first argument may optionally be a hashref of parameters which are passed
693             to the C<Mason::Request> constructor. e.g. to capture the output of the
694             subrequest:
695              
696             $m->visit({out_method => \my $buffer}, ...);
697              
698             See also L<go|/go>.
699              
700             =back
701              
702             =head1 MODIFIABLE METHODS
703              
704             These methods are not intended to be called externally, but may be useful to
705             modify with method modifiers in L<plugins|Mason::Manual::Plugins> and
706             L<subclasses|Mason::Manual::Subclasses>. Their APIs will be kept as stable as
707             possible.
708              
709             =over
710              
711             =item cleanup_request ()
712              
713             A place to perform cleanup duties when the request finishes or dies with an
714             error, even if the request object is not immediately destroyed. Includes
715             anything registered with L<add_cleanup|/add_cleanup>.
716              
717             =item construct_page_component ($compc, $args)
718              
719             Constructs the page component of class I<$compc>, with hashref of constructor
720             arguments I<$args>.
721              
722             =item match_request_path ($request_path)
723              
724             Given a top level I<$request_path>, return a corresponding component path or
725             undef if none was found. Search includes dhandlers and index files. See
726             L<Mason::Manual::RequestDispatch>.
727              
728             =item process_output ($outref)
729              
730             This method is called on the output buffer right before it is sent to its final
731             destination. I<$outref> is a reference to the output string; the method can
732             modify it as desired.
733              
734             =item run ($request_path, args)
735              
736             Runs the request with I<$request_path> and I<args>, where the latter can be
737             either a hashref or a hash. This is generally called via << $interp->run >>.
738              
739             =item with_tied_print ($code)
740              
741             Execute the given I<$code> with the current selected filehandle ('print') tied
742             to the Mason output stream. You could disable the filehandle selection by
743             overriding this to just call I<$code>.
744              
745             =back
746              
747             =head1 SEE ALSO
748              
749             L<Mason|Mason>
750              
751             =head1 AUTHOR
752              
753             Jonathan Swartz <swartz@pobox.com>
754              
755             =head1 COPYRIGHT AND LICENSE
756              
757             This software is copyright (c) 2012 by Jonathan Swartz.
758              
759             This is free software; you can redistribute it and/or modify it under
760             the same terms as the Perl 5 programming language system itself.
761              
762             =cut