File Coverage

blib/lib/Catalyst/Utils.pm
Criterion Covered Total %
statement 219 254 86.2
branch 61 92 66.3
condition 37 72 51.3
subroutine 39 41 95.1
pod 22 22 100.0
total 378 481 78.5


line stmt bran cond sub pod time code
1              
2             use strict;
3 187     187   424835 use File::Spec;
  187         419  
  187         5119  
4 186     186   945 use HTTP::Request;
  186         357  
  186         3546  
5 186     186   61870 use Path::Class;
  186         1933832  
  186         6518  
6 186     186   65219 use URI;
  186         5294066  
  186         9715  
7 186     186   1412 use Carp qw/croak/;
  186         383  
  186         4609  
8 186     186   925 use Cwd;
  186         402  
  186         6380  
9 186     186   988 use Class::Load 'is_class_loaded';
  186         381  
  186         7866  
10 186     186   3982 use String::RewritePrefix;
  186         96984  
  186         6846  
11 186     186   58379 use Class::Load ();
  186         175803  
  186         985  
12 186     186   33136 use namespace::clean;
  186         890  
  186         2705  
13 186     186   8027 use Devel::InnerPackage;
  186         114413  
  186         1529  
14 186     186   117030 use Moose::Util;
  186         293266  
  186         7092  
15 186     186   4527  
  186         696018  
  186         1770  
16             =head1 NAME
17              
18             Catalyst::Utils - The Catalyst Utils
19              
20             =head1 SYNOPSIS
21              
22             See L<Catalyst>.
23              
24             =head1 DESCRIPTION
25              
26             Catalyst Utilities.
27              
28             =head1 METHODS
29              
30             =head2 appprefix($class)
31              
32             MyApp::Foo becomes myapp_foo
33              
34             =cut
35              
36             my $class = shift;
37             $class =~ s/::/_/g;
38 91     91 1 290 $class = lc($class);
39 91         369 return $class;
40 91         289 }
41 91         614  
42             =head2 class2appclass($class);
43              
44             MyApp::Controller::Foo::Bar becomes MyApp
45             My::App::Controller::Foo::Bar becomes My::App
46              
47             =cut
48              
49             my $class = shift || '';
50             my $appname = '';
51             if ( $class =~ /^(.+?)::([MVC]|Model|View|Controller)::.+$/ ) {
52 7037   50 7037 1 11791 $appname = $1;
53 7037         9458 }
54 7037 100       39236 return $appname;
55 7036         16922 }
56              
57 7037         16199 =head2 class2classprefix($class);
58              
59             MyApp::Controller::Foo::Bar becomes MyApp::Controller
60             My::App::Controller::Foo::Bar becomes My::App::Controller
61              
62             =cut
63              
64             my $class = shift || '';
65             my $prefix;
66             if ( $class =~ /^(.+?::([MVC]|Model|View|Controller))::.+$/ ) {
67             $prefix = $1;
68 1   50 1 1 5 }
69 1         1 return $prefix;
70 1 50       12 }
71 1         4  
72             =head2 class2classsuffix($class);
73 1         4  
74             MyApp::Controller::Foo::Bar becomes Controller::Foo::Bar
75              
76             =cut
77              
78             my $class = shift || '';
79             my $prefix = class2appclass($class) || '';
80             $class =~ s/$prefix\:://;
81             return $class;
82             }
83 6952   50 6952 1 13231  
84 6952   100     11805 =head2 class2env($class);
85 6952         31618  
86 6952         17944 Returns the environment name for class.
87              
88             MyApp becomes MYAPP
89             My::App becomes MY_APP
90              
91             =cut
92              
93             my $class = shift || '';
94             $class =~ s/::/_/g;
95             return uc($class);
96             }
97              
98             =head2 class2prefix( $class, $case );
99 1056   50 1056 1 2921  
100 1056         2475 Returns the uri prefix for a class. If case is false the prefix is converted to lowercase.
101 1056         3090  
102             My::App::Controller::Foo::Bar becomes foo/bar
103              
104             =cut
105              
106             my $class = shift || '';
107             my $case = shift || 0;
108             my $prefix;
109             if ( $class =~ /^.+?::([MVC]|Model|View|Controller)::(.+)$/ ) {
110             $prefix = $case ? $2 : lc $2;
111             $prefix =~ s{::}{/}g;
112             }
113 6170   50 6170 1 14847 return $prefix;
114 6170   50     18519 }
115 6170         7668  
116 6170 100       30217 =head2 class2tempdir( $class [, $create ] );
117 6015 50       19697  
118 6015         18523 Returns a tempdir for a class. If create is true it will try to create the path.
119              
120 6170         23385 My::App becomes /tmp/my/app
121             My::App::Controller::Foo::Bar becomes /tmp/my/app/c/foo/bar
122              
123             =cut
124              
125             my $class = shift || '';
126             my $create = shift || 0;
127             my @parts = split '::', lc $class;
128              
129             my $tmpdir = dir( File::Spec->tmpdir, @parts )->cleanup;
130              
131             if ( $create && !-e $tmpdir ) {
132              
133 0   0 0 1 0 eval { $tmpdir->mkpath; 1 }
134 0   0     0 or do {
135 0         0 # don't load Catalyst::Exception as a BEGIN in Utils,
136             # because Utils often gets loaded before MyApp.pm, and if
137 0         0 # Catalyst::Exception is loaded before MyApp.pm, it does
138             # not honor setting
139 0 0 0     0 # $Catalyst::Exception::CATALYST_EXCEPTION_CLASS in
140             # MyApp.pm
141 0         0 require Catalyst::Exception;
  0         0  
142 0 0       0 Catalyst::Exception->throw(
143             message => qq/Couldn't create tmpdir '$tmpdir', "$@"/ );
144             }
145             }
146              
147             return $tmpdir->stringify;
148             }
149 0         0  
150 0         0 =head2 home($class)
151              
152             Returns home directory for given class.
153              
154             =head2 dist_indicator_file_list
155 0         0  
156             Returns a list of files which can be tested to check if you're inside
157             a CPAN distribution which is not yet installed.
158              
159             These are:
160              
161             =over
162              
163             =item Makefile.PL
164              
165             =item Build.PL
166              
167             =item dist.ini
168              
169             =item L<cpanfile>
170              
171             =back
172              
173             =cut
174              
175             qw{Makefile.PL Build.PL dist.ini cpanfile};
176             }
177              
178             my $class = shift;
179              
180             # make an $INC{ $key } style string from the class name
181             (my $file = "$class.pm") =~ s{::}{/}g;
182              
183             if ( my $inc_entry = $INC{$file} ) {
184 259     259 1 1074 {
185             # look for an uninstalled Catalyst app
186              
187             # find the @INC entry in which $file was found
188 329     329 1 13236 (my $path = $inc_entry) =~ s/$file$//;
189             $path ||= cwd() if !defined $path || !length $path;
190             my $home = dir($path)->absolute->cleanup;
191 329         1034  
192             # pop off /lib and /blib if they're there
193 329 100       1203 $home = $home->parent while $home =~ /b?lib$/;
194              
195             # only return the dir if it has a Makefile.PL or Build.PL or dist.ini
196             if (grep { -f $home->file($_) } dist_indicator_file_list()) {
197             # clean up relative path:
198 253         3490 # MyApp/script/.. -> MyApp
199 253 100 33     5724  
      66        
200 253         1316 my $dir;
201             my @dir_list = $home->dir_list();
202             while (($dir = pop(@dir_list)) && $dir eq '..') {
203 253         52012 $home = dir($home)->parent->parent;
204             }
205              
206 253 100       25962 return $home->stringify;
  1012         85218  
207             }
208             }
209              
210 7         677 {
211 7         30 # look for an installed Catalyst app
212 7   66     104  
213 6         425 # trim the .pm off the thing ( Foo/Bar.pm -> Foo/Bar/ )
214             ( my $path = $inc_entry) =~ s/\.pm$//;
215             my $home = dir($path)->absolute->cleanup;
216 7         412  
217             # return if it's a valid directory
218             return $home->stringify if -d $home;
219             }
220             }
221              
222             # we found nothing
223             return 0;
224 253         502 }
  246         23296  
  246         1639  
225 246         996  
226             =head2 prefix($class, $name);
227              
228 246 100       29573 Returns a prefixed action.
229              
230             MyApp::Controller::Foo::Bar, yada becomes foo/bar/yada
231              
232             =cut
233 104         1293  
234             my ( $class, $name ) = @_;
235             my $prefix = &class2prefix($class);
236             $name = "$prefix/$name" if $prefix;
237             return $name;
238             }
239              
240             =head2 request($uri)
241              
242             Returns an L<HTTP::Request> object for a uri.
243              
244             =cut
245 0     0 1 0  
246 0         0 my $request = shift;
247 0 0       0 unless ( ref $request ) {
248 0         0 if ( $request =~ m/^http/i ) {
249             $request = URI->new($request);
250             }
251             else {
252             $request = URI->new( 'http://localhost' . $request );
253             }
254             }
255             unless ( ref $request eq 'HTTP::Request' ) {
256             $request = HTTP::Request->new( 'GET', $request );
257             }
258 913     913 1 4618 return $request;
259 913 100       2422 }
260 775 100       3201  
261 534         2994 =head2 ensure_class_loaded($class_name, \%opts)
262              
263             Loads the class unless it already has been loaded.
264 241         1592  
265             If $opts{ignore_loaded} is true always tries the require whether the package
266             already exists or not. Only pass this if you're either (a) sure you know the
267 913 100       76844 file exists on disk or (b) have code to catch the file not found exception
268 775         4582 that will result if it doesn't.
269              
270 913         55082 =cut
271              
272             my $class = shift;
273             my $opts = shift;
274              
275             croak "Malformed class Name $class"
276             if $class =~ m/(?:\b\:\b|\:{3,})/;
277              
278             croak "Malformed class Name $class"
279             if $class =~ m/[^\w:]/;
280              
281             croak "ensure_class_loaded should be given a classname, not a filename ($class)"
282             if $class =~ m/\.pm$/;
283              
284             # $opts->{ignore_loaded} can be set to true, and this causes the class to be required, even
285 6908     6908 1 20421 # if it already has symbol table entries. This is to support things like Schema::Loader, which
286 6908         9595 # part-generate classes in memory, but then also load some of their contents from disk.
287             return if !$opts->{ ignore_loaded }
288 6908 50       55954 && is_class_loaded($class); # if a symbol entry exists we don't load again
289              
290             # this hack is so we don't overwrite $@ if the load did not generate an error
291 6908 100       19233 my $error;
292             {
293             local $@;
294 6906 50       15592 my $file = $class . '.pm';
295             $file =~ s{::}{/}g;
296             eval { CORE::require($file) };
297             $error = $@;
298             }
299              
300             die $error if $error;
301 6906 100 100     19387  
302             warn "require $class was successful but the package is not defined."
303             unless is_class_loaded($class);
304 6857         9058  
305             return 1;
306 6857         8919 }
  6857         9105  
307 6857         14050  
308 6857         27425 =head2 merge_hashes($hashref, $hashref)
309 6857         12336  
  6857         2317032  
310 6857         88331448 Base code to recursively merge two hashes together with right-hand precedence.
311              
312             =cut
313 6857 100       20876  
314             my ( $lefthash, $righthash ) = @_;
315 6855 100       32916  
316             return $lefthash unless defined $righthash;
317              
318 6855         27116 my %merged = %$lefthash;
319             for my $key ( keys %$righthash ) {
320             my $right_ref = ( ref $righthash->{ $key } || '' ) eq 'HASH';
321             my $left_ref = ( ( exists $lefthash->{ $key } && ref $lefthash->{ $key } ) || '' ) eq 'HASH';
322             if( $right_ref and $left_ref ) {
323             $merged{ $key } = merge_hashes(
324             $lefthash->{ $key }, $righthash->{ $key }
325             );
326             }
327             else {
328 22469     22469 1 35410 $merged{ $key } = $righthash->{ $key };
329             }
330 22469 100       42456 }
331              
332 21732         46278 return \%merged;
333 21732         48483 }
334 8807   100     31556  
335 8807   100     31409 =head2 env_value($class, $key)
336 8807 100 100     21276  
337             Checks for and returns an environment value. For instance, if $key is
338 81         559 'home', then this method will check for and return the first value it finds,
339             looking at $ENV{MYAPP_HOME} and $ENV{CATALYST_HOME}.
340              
341             =cut
342 8726         19861  
343             my ( $class, $key ) = @_;
344              
345             $key = uc($key);
346 21732         68110 my @prefixes = ( class2env($class), 'CATALYST' );
347              
348             for my $prefix (@prefixes) {
349             if ( defined( my $value = $ENV{"${prefix}_${key}"} ) ) {
350             return $value;
351             }
352             }
353              
354             return;
355             }
356              
357             =head2 term_width
358 1055     1055 1 4484  
359             Try to guess terminal width to use with formatting of debug output
360 1055         2578  
361 1055         2937 All you need to get this work, is:
362              
363 1055         2357 1) Install Term::Size::Any, or
364 2102 100       7567  
365 26         368 2) Export $COLUMNS from your shell.
366              
367             (Warning to bash users: 'echo $COLUMNS' may be showing you the bash
368             variable, not $ENV{COLUMNS}. 'export COLUMNS=$COLUMNS' and you should see
369 1029         4505 that 'env' now lists COLUMNS.)
370              
371             As last resort, default value of 80 chars will be used.
372              
373             Calling C<term_width> with a true value will cause it to be recalculated; you
374             can use this to cause it to get recalculated when your terminal is resized like
375             this
376              
377             $SIG{WINCH} = sub { Catalyst::Utils::term_width(1) };
378              
379             =cut
380              
381             my $_term_width;
382             my $_use_term_size_any;
383              
384             my $force_reset = shift;
385              
386             undef $_term_width if $force_reset;
387              
388             return $_term_width if $_term_width;
389              
390             if ($ENV{COLUMNS} && $ENV{COLUMNS} =~ /\A\d+\z/) {
391             return $_term_width = $ENV{COLUMNS};
392             }
393              
394             if (!-t STDOUT && !-t STDERR) {
395             return $_term_width = 80;
396             }
397              
398             if (!defined $_use_term_size_any) {
399             eval {
400 68     68 1 116 require Term::Size::Any;
401             Term::Size::Any->import();
402 68 50       158 $_use_term_size_any = 1;
403             1;
404 68 100       297 } or do {
405             if ( $@ =~ m[Can't locate Term/Size/Any\.pm] ) {
406 8 50 33     68 warn "Term::Size::Any is not installed, can't autodetect terminal column width\n";
407 0         0 }
408             else {
409             warn "There was an error trying to detect your terminal size: $@\n";
410 8 50 33     487 }
411 8         59 $_use_term_size_any = 0;
412             };
413             }
414 0 0       0  
415             my $width;
416 0         0  
417 0         0 if ($_use_term_size_any) {
418 0         0 $width = Term::Size::Any::chars(*STDERR) || Term::Size::Any::chars(*STDOUT);
419 0         0 }
420 0 0       0  
421 0 0       0 if (!$width || $width < 80) {
422 0         0 $width = 80;
423             }
424              
425 0         0 return $_term_width = $width;
426             }
427 0         0  
428              
429             =head2 resolve_namespace
430              
431 0         0 Method which adds the namespace for plugins and actions.
432              
433 0 0       0 __PACKAGE__->setup(qw(MyPlugin));
434 0   0     0  
435             # will load Catalyst::Plugin::MyPlugin
436              
437 0 0 0     0 =cut
438 0         0  
439              
440             my $appnamespace = shift;
441 0         0 my $namespace = shift;
442             my @classes = @_;
443             return String::RewritePrefix->rewrite({
444             q[] => qq[${namespace}::],
445             q[+] => q[],
446             (defined $appnamespace
447             ? (q[~] => qq[${appnamespace}::])
448             : ()
449             ),
450             }, @classes);
451             }
452              
453             =head2 build_middleware (@args)
454              
455             Internal application that converts a single middleware definition (see
456             L<Catalyst/psgi_middleware>) into an actual instance of middleware.
457 2221     2221 1 4090  
458 2221         3252 =cut
459 2221         4418  
460 2221 100       16572 my ($class, $namespace, @init_args) = @_;
461              
462             if(
463             $namespace =~s/^\+// ||
464             $namespace =~/^Plack::Middleware/ ||
465             $namespace =~/^$class/
466             ) { ## the string is a full namespace
467             return Class::Load::try_load_class($namespace) ?
468             $namespace->new(@init_args) :
469             die "Can't load class $namespace";
470             } else { ## the string is a partial namespace
471             if(Class::Load::try_load_class($class .'::Middleware::'. $namespace)) { ## Load Middleware from Project namespace
472             my $ns = $class .'::Middleware::'. $namespace;
473             return $ns->new(@init_args);
474             } elsif(Class::Load::try_load_class("Plack::Middleware::$namespace")) { ## Act like Plack::Builder
475             return "Plack::Middleware::$namespace"->new(@init_args);
476             } else {
477             die "Can't load middleware via '$namespace'. It's not ".$class."::Middleware::".$namespace." or Plack::Middleware::$namespace";
478 10     10 1 29 }
479             }
480 10 100 66     116  
      66        
481             return; ## be sure we can count on a proper return when valid
482             }
483              
484             =head2 apply_registered_middleware ($psgi)
485 3 50       13  
486             Given a $psgi reference, wrap all the L<Catalyst/registered_middlewares>
487             around it and return the wrapped version.
488              
489 7 50       34 This exists to deal with the fact Catalyst registered middleware can be
    100          
490 0         0 either an object with a wrap method or a coderef.
491 0         0  
492             =cut
493 6         3440  
494             my ($class, $psgi) = @_;
495 1         608 my $new_psgi = $psgi;
496             foreach my $middleware ($class->registered_middlewares) {
497             $new_psgi = Scalar::Util::blessed $middleware ?
498             $middleware->wrap($new_psgi) :
499 0         0 $middleware->($new_psgi);
500             }
501             return $new_psgi;
502             }
503              
504             =head2 inject_component
505              
506             Used to add components at runtime:
507              
508             into The Catalyst package to inject into (e.g. My::App)
509             component The component package to inject
510             traits (Optional) ArrayRef of L<Moose::Role>s that the component should consume.
511             as An optional moniker to use as the package name for the derived component
512              
513 133     133 1 499 For example:
514 133         351  
515 133         1047 Catalyst::Utils::inject_component( into => My::App, component => Other::App::Controller::Apple )
516 944 100       37490  
517             The above will create 'My::App::Controller::Other::App::Controller::Apple'
518              
519             Catalyst::Utils::inject_component( into => My::App, component => Other::App::Controller::Apple, as => Apple )
520 133         6633  
521             The above will create 'My::App::Controller::Apple'
522              
523             Catalyst::Utils::inject_component( into => $myapp, component => 'MyRootV', as => 'Controller::Root' );
524              
525             Will inject Controller, Model, and View components into your Catalyst application
526             at setup (run)time. It does this by creating a new package on-the-fly, having that
527             package extend the given component, and then having Catalyst setup the new component
528             (via $app->setup_component).
529              
530             B<NOTE:> This is basically a core version of L<CatalystX::InjectComponent>. If you were using that
531             you can now use this safely instead. Going forward changes required to make this work will be
532             synchronized with the core method.
533              
534             B<NOTE:> The 'traits' option is unique to the L<Catalyst::Utils> version of this feature.
535              
536             B<NOTE:> These injected components really need to be a L<Catalyst::Component> and a L<Moose>
537             based class.
538              
539             =cut
540              
541             my %given = @_;
542             my ($into, $component, $as) = @given{qw/into component as/};
543              
544             croak "No Catalyst (package) given" unless $into;
545             croak "No component (package) given" unless $component;
546              
547             Class::Load::load_class($component);
548              
549             $as ||= $component;
550             unless ( $as =~ m/^(?:Controller|Model|View)::/ || $given{skip_mvc_renaming} ) {
551             my $category;
552             for (qw/ Controller Model View /) {
553             if ( $component->isa( "Catalyst::$_" ) ) {
554             $category = $_;
555             last;
556             }
557             }
558             croak "Don't know what kind of component \"$component\" is" unless $category;
559             $as = "${category}::$as";
560             }
561 11     11 1 95 my $component_package = join '::', $into, $as;
562 11         31  
563             unless ( Class::Load::is_class_loaded $component_package ) {
564 11 50       22 eval "package $component_package; use base qw/$component/; 1;" or
565 11 50       20 croak "Unable to build component package for \"$component_package\": $@";
566             Moose::Util::apply_all_roles($component_package, @{$given{traits}}) if $given{traits};
567 11         34 (my $file = "$component_package.pm") =~ s{::}{/}g;
568             $INC{$file} ||= 1;
569 11   66     13414 }
570 11 50 66     62  
571 5         7 my $_setup_component = sub {
572 5         10 my $into = shift;
573 7 100       39 my $component_package = shift;
574 5         8 $into->components->{$component_package} = $into->delayed_setup_component( $component_package );
575 5         8 };
576              
577             $_setup_component->( $into, $component_package );
578 5 50       10 }
579 5         25  
580             =head1 PSGI Helpers
581 11         34  
582             Utility functions to make it easier to work with PSGI applications under Catalyst
583 11 50       40  
584 11 50   2   850 =head2 env_at_path_prefix
  2     2   16  
  2     2   5  
  2     2   225  
  2     2   13  
  2         4  
  2         185  
  2         13  
  2         5  
  2         171  
  2         15  
  2         12  
  2         149  
  2         12  
  2         8  
  2         131  
585              
586 11 100       46 Localize C<$env> under the current controller path prefix:
  3         18  
587 11         20487  
588 11   50     58 package MyApp::Controller::User;
589              
590             use Catalyst::Utils;
591              
592 11     11   17 use base 'Catalyst::Controller';
593 11         14  
594 11         44 sub name :Local {
595 11         42 my ($self, $c) = @_;
596             my $env = $c->Catalyst::Utils::env_at_path_prefix;
597 11         24 }
598              
599             Assuming you have a request like GET /user/name:
600              
601             In the example case C<$env> will have PATH_INFO of '/name' instead of
602             '/user/name' and SCRIPT_NAME will now be '/user'.
603              
604             =cut
605              
606             my $ctx = shift;
607             my $path_prefix = $ctx->controller->path_prefix;
608             my $env = $ctx->request->env;
609             my $path_info = $env->{PATH_INFO};
610             my $script_name = ($env->{SCRIPT_NAME} || '');
611              
612             $path_info =~ s/(^\/\Q$path_prefix\E)//;
613             $script_name = "$script_name$1";
614              
615             return +{
616             %$env,
617             PATH_INFO => $path_info,
618             SCRIPT_NAME => $script_name };
619             }
620              
621             =head2 env_at_action
622              
623             Localize C<$env> under the current action namespace.
624              
625             package MyApp::Controller::User;
626              
627 8     8 1 165 use Catalyst::Utils;
628 8         44  
629 8         173 use base 'Catalyst::Controller';
630 8         29  
631 8   50     32 sub name :Local {
632             my ($self, $c) = @_;
633 8         54 my $env = $c->Catalyst::Utils::env_at_action;
634 8         18 }
635              
636             Assuming you have a request like GET /user/name:
637 8         179  
638             In the example case C<$env> will have PATH_INFO of '/' instead of
639             '/user/name' and SCRIPT_NAME will now be '/user/name'.
640              
641             Alternatively, assuming you have a request like GET /user/name/foo:
642              
643             In this example case C<$env> will have PATH_INFO of '/foo' instead of
644             '/user/name/foo' and SCRIPT_NAME will now be '/user/name'.
645              
646             This is probably a common case where you want to mount a PSGI application
647             under an action but let the Args fall through to the PSGI app.
648              
649             =cut
650              
651             my $ctx = shift;
652             my $argpath = join '/', @{$ctx->request->arguments};
653             my $path = '/' . $ctx->request->path;
654              
655             $path =~ s/\/?\Q$argpath\E\/?$//;
656              
657             my $env = $ctx->request->env;
658             my $path_info = $env->{PATH_INFO};
659             my $script_name = ($env->{SCRIPT_NAME} || '');
660              
661             $path_info =~ s/(^\Q$path\E)//;
662             $script_name = "$script_name$1";
663              
664             return +{
665             %$env,
666             PATH_INFO => $path_info,
667             SCRIPT_NAME => $script_name };
668             }
669              
670             =head2 env_at_request_uri
671              
672             Localize C<$env> under the current request URI:
673 11     11 1 125  
674 11         18 package MyApp::Controller::User;
  11         223  
675 11         213  
676             use Catalyst::Utils;
677 11         298  
678             use base 'Catalyst::Controller';
679 11         243  
680 11         25 sub name :Local Args(1) {
681 11   50     55 my ($self, $c, $id) = @_;
682             my $env = $c->Catalyst::Utils::env_at_request_uri
683 11         131 }
684 11         33  
685             Assuming you have a request like GET /user/name/hello:
686              
687 11         215 In the example case C<$env> will have PATH_INFO of '/' instead of
688             '/user/name' and SCRIPT_NAME will now be '/user/name/hello'.
689              
690             =cut
691              
692             my $ctx = shift;
693             my $path = '/' . $ctx->request->path;
694             my $env = $ctx->request->env;
695             my $path_info = $env->{PATH_INFO};
696             my $script_name = ($env->{SCRIPT_NAME} || '');
697              
698             $path_info =~ s/(^\Q$path\E)//;
699             $script_name = "$script_name$1";
700              
701             return +{
702             %$env,
703             PATH_INFO => $path_info,
704             SCRIPT_NAME => $script_name };
705             }
706              
707             =head1 AUTHORS
708              
709             Catalyst Contributors, see Catalyst.pm
710              
711             =head1 COPYRIGHT
712              
713             This library is free software. You can redistribute it and/or modify it under
714             the same terms as Perl itself.
715 7     7 1 73  
716 7         142 =cut
717 7         144  
718 7         29 1;