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 188     188   515883 use File::Spec;
  188         526  
  188         6215  
4 187     187   1097 use HTTP::Request;
  187         411  
  187         5325  
5 187     187   71648 use Path::Class;
  187         2622121  
  187         6032  
6 187     187   77487 use URI;
  187         6142809  
  187         11953  
7 187     187   1644 use Carp qw/croak/;
  187         452  
  187         5458  
8 187     187   1052 use Cwd;
  187         443  
  187         7642  
9 187     187   1161 use Class::Load 'is_class_loaded';
  187         439  
  187         10450  
10 187     187   4362 use String::RewritePrefix;
  187         112976  
  187         8621  
11 187     187   66206 use Class::Load ();
  187         208916  
  187         1590  
12 187     187   39948 use namespace::clean;
  187         465  
  187         3228  
13 187     187   8819 use Devel::InnerPackage;
  187         135690  
  187         1837  
14 187     187   136172 use Moose::Util;
  187         345128  
  187         8248  
15 187     187   5359  
  187         842211  
  187         1908  
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 311 $class = lc($class);
39 91         362 return $class;
40 91         383 }
41 91         721  
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 7039   50 7039 1 14081 $appname = $1;
53 7039         11346 }
54 7039 100       46285 return $appname;
55 7038         20887 }
56              
57 7039         19530 =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 7 }
69 1         2 return $prefix;
70 1 50       13 }
71 1         4  
72             =head2 class2classsuffix($class);
73 1         6  
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 6954   50 6954 1 18309  
84 6954   100     13952 =head2 class2env($class);
85 6954         37305  
86 6954         21143 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 1062   50 1062 1 3712  
100 1062         3064 Returns the uri prefix for a class. If case is false the prefix is converted to lowercase.
101 1062         3765  
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 6174   50 6174 1 19000 return $prefix;
114 6174   50     24216 }
115 6174         10425  
116 6174 100       40839 =head2 class2tempdir( $class [, $create ] );
117 6018 50       28451  
118 6018         24709 Returns a tempdir for a class. If create is true it will try to create the path.
119              
120 6174         30735 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 1269 {
185             # look for an uninstalled Catalyst app
186              
187             # find the @INC entry in which $file was found
188 331     331 1 14823 (my $path = $inc_entry) =~ s/$file$//;
189             $path ||= cwd() if !defined $path || !length $path;
190             my $home = dir($path)->absolute->cleanup;
191 331         1251  
192             # pop off /lib and /blib if they're there
193 331 100       1452 $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         4127 # MyApp/script/.. -> MyApp
199 253 100 33     5387  
      66        
200 253         1656 my $dir;
201             my @dir_list = $home->dir_list();
202             while (($dir = pop(@dir_list)) && $dir eq '..') {
203 253         62360 $home = dir($home)->parent->parent;
204             }
205              
206 253 100       30481 return $home->stringify;
  1012         100749  
207             }
208             }
209              
210 7         757 {
211 7         27 # look for an installed Catalyst app
212 7   66     118  
213 6         568 # 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         520  
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         540 }
  246         27592  
  246         1856  
225 246         1151  
226             =head2 prefix($class, $name);
227              
228 246 100       34602 Returns a prefixed action.
229              
230             MyApp::Controller::Foo::Bar, yada becomes foo/bar/yada
231              
232             =cut
233 106         1462  
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 915     915 1 6965 return $request;
259 915 100       3586 }
260 775 100       4462  
261 534         4577 =head2 ensure_class_loaded($class_name, \%opts)
262              
263             Loads the class unless it already has been loaded.
264 241         2213  
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 915 100       103657 file exists on disk or (b) have code to catch the file not found exception
268 775         6701 that will result if it doesn't.
269              
270 915         72373 =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 6911     6911 1 24196 # if it already has symbol table entries. This is to support things like Schema::Loader, which
286 6911         12294 # part-generate classes in memory, but then also load some of their contents from disk.
287             return if !$opts->{ ignore_loaded }
288 6911 50       69040 && 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 6911 100       26734 my $error;
292             {
293             local $@;
294 6909 50       22044 my $file = $class . '.pm';
295             $file =~ s{::}{/}g;
296             eval { CORE::require($file) };
297             $error = $@;
298             }
299              
300             die $error if $error;
301 6909 100 100     28275  
302             warn "require $class was successful but the package is not defined."
303             unless is_class_loaded($class);
304 6860         11850  
305             return 1;
306 6860         11420 }
  6860         11887  
307 6860         18445  
308 6860         34544 =head2 merge_hashes($hashref, $hashref)
309 6860         16234  
  6860         2873792  
310 6860         106005060 Base code to recursively merge two hashes together with right-hand precedence.
311              
312             =cut
313 6860 100       25613  
314             my ( $lefthash, $righthash ) = @_;
315 6858 100       41026  
316             return $lefthash unless defined $righthash;
317              
318 6858         36813 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 22486     22486 1 42866 $merged{ $key } = $righthash->{ $key };
329             }
330 22486 100       51119 }
331              
332 21744         54417 return \%merged;
333 21744         60175 }
334 8809   100     40035  
335 8809   100     38388 =head2 env_value($class, $key)
336 8809 100 100     26203  
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 8728         23871  
343             my ( $class, $key ) = @_;
344              
345             $key = uc($key);
346 21744         80990 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 1061     1061 1 6197  
359             Try to guess terminal width to use with formatting of debug output
360 1061         3320  
361 1061         3735 All you need to get this work, is:
362              
363 1061         2953 1) Install Term::Size::Any, or
364 2114 100       8916  
365 26         448 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 1035         5543 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 161 require Term::Size::Any;
401             Term::Size::Any->import();
402 68 50       175 $_use_term_size_any = 1;
403             1;
404 68 100       409 } or do {
405             if ( $@ =~ m[Can't locate Term/Size/Any\.pm] ) {
406 8 50 33     80 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     150 }
411 8         80 $_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 2224     2224 1 4724  
458 2224         6322 =cut
459 2224         5457  
460 2224 100       20601 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 31 }
479             }
480 10 100 66     123  
      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       19  
486             Given a $psgi reference, wrap all the L<Catalyst/registered_middlewares>
487             around it and return the wrapped version.
488              
489 7 50       38 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         3516  
494             my ($class, $psgi) = @_;
495 1         579 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 134     134 1 528 For example:
514 134         368  
515 134         1249 Catalyst::Utils::inject_component( into => My::App, component => Other::App::Controller::Apple )
516 951 100       43303  
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 134         7340  
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 85 my $component_package = join '::', $into, $as;
562 11         39  
563             unless ( Class::Load::is_class_loaded $component_package ) {
564 11 50       26 eval "package $component_package; use base qw/$component/; 1;" or
565 11 50       24 croak "Unable to build component package for \"$component_package\": $@";
566             Moose::Util::apply_all_roles($component_package, @{$given{traits}}) if $given{traits};
567 11         46 (my $file = "$component_package.pm") =~ s{::}{/}g;
568             $INC{$file} ||= 1;
569 11   66     16530 }
570 11 50 66     58  
571 5         10 my $_setup_component = sub {
572 5         13 my $into = shift;
573 7 100       49 my $component_package = shift;
574 5         11 $into->components->{$component_package} = $into->delayed_setup_component( $component_package );
575 5         9 };
576              
577             $_setup_component->( $into, $component_package );
578 5 50       13 }
579 5         13  
580             =head1 PSGI Helpers
581 11         53  
582             Utility functions to make it easier to work with PSGI applications under Catalyst
583 11 50       62  
584 11 50   2   1015 =head2 env_at_path_prefix
  2     2   16  
  2     2   5  
  2     2   310  
  2     2   17  
  2         6  
  2         188  
  2         19  
  2         7  
  2         156  
  2         26  
  2         5  
  2         167  
  2         18  
  2         6  
  2         192  
585              
586 11 100       49 Localize C<$env> under the current controller path prefix:
  3         16  
587 11         25088  
588 11   50     70 package MyApp::Controller::User;
589              
590             use Catalyst::Utils;
591              
592 11     11   23 use base 'Catalyst::Controller';
593 11         17  
594 11         52 sub name :Local {
595 11         48 my ($self, $c) = @_;
596             my $env = $c->Catalyst::Utils::env_at_path_prefix;
597 11         34 }
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 79 use Catalyst::Utils;
628 8         37  
629 8         160 use base 'Catalyst::Controller';
630 8         19  
631 8   50     35 sub name :Local {
632             my ($self, $c) = @_;
633 8         56 my $env = $c->Catalyst::Utils::env_at_action;
634 8         20 }
635              
636             Assuming you have a request like GET /user/name:
637 8         172  
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 108  
674 11         22 package MyApp::Controller::User;
  11         203  
675 11         207  
676             use Catalyst::Utils;
677 11         392  
678             use base 'Catalyst::Controller';
679 11         238  
680 11         29 sub name :Local Args(1) {
681 11   50     44 my ($self, $c, $id) = @_;
682             my $env = $c->Catalyst::Utils::env_at_request_uri
683 11         140 }
684 11         41  
685             Assuming you have a request like GET /user/name/hello:
686              
687 11         230 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 68  
716 7         140 =cut
717 7         145  
718 7         18 1;