Bump MX::E::CAF dep
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Utils.pm
CommitLineData
f05af9ba 1package Catalyst::Utils;
2
3use strict;
a2f2cde9 4use Catalyst::Exception;
37a3ac5c 5use File::Spec;
d837e1a7 6use HTTP::Request;
812a28c9 7use Path::Class;
d837e1a7 8use URI;
5e5bd6df 9use Carp qw/croak/;
2f381252 10use Cwd;
f05af9ba 11
12=head1 NAME
13
14Catalyst::Utils - The Catalyst Utils
15
16=head1 SYNOPSIS
17
18See L<Catalyst>.
19
20=head1 DESCRIPTION
21
22=head1 METHODS
23
b5ecfcf0 24=head2 appprefix($class)
41ca9ba7 25
85d9fce6 26 MyApp::Foo becomes myapp_foo
41ca9ba7 27
28=cut
29
30sub appprefix {
31 my $class = shift;
0ef447d8 32 $class =~ s/::/_/g;
41ca9ba7 33 $class = lc($class);
34 return $class;
35}
36
b5ecfcf0 37=head2 class2appclass($class);
84cf74e7 38
0ef447d8 39 MyApp::Controller::Foo::Bar becomes MyApp
40 My::App::Controller::Foo::Bar becomes My::App
2d90477f 41
84cf74e7 42=cut
43
44sub class2appclass {
45 my $class = shift || '';
46 my $appname = '';
0ef447d8 47 if ( $class =~ /^(.+?)::([MVC]|Model|View|Controller)::.+$/ ) {
84cf74e7 48 $appname = $1;
49 }
50 return $appname;
51}
52
b5ecfcf0 53=head2 class2classprefix($class);
2930d610 54
0ef447d8 55 MyApp::Controller::Foo::Bar becomes MyApp::Controller
56 My::App::Controller::Foo::Bar becomes My::App::Controller
2d90477f 57
2930d610 58=cut
59
60sub class2classprefix {
61 my $class = shift || '';
62 my $prefix;
0ef447d8 63 if ( $class =~ /^(.+?::([MVC]|Model|View|Controller))::.+$/ ) {
2930d610 64 $prefix = $1;
65 }
66 return $prefix;
67}
68
b5ecfcf0 69=head2 class2classsuffix($class);
84cf74e7 70
0ef447d8 71 MyApp::Controller::Foo::Bar becomes Controller::Foo::Bar
2d90477f 72
84cf74e7 73=cut
74
75sub class2classsuffix {
76 my $class = shift || '';
77 my $prefix = class2appclass($class) || '';
0ef447d8 78 $class =~ s/$prefix\:://;
84cf74e7 79 return $class;
80}
81
b5ecfcf0 82=head2 class2env($class);
3ad654e0 83
26e73131 84Returns the environment name for class.
3ad654e0 85
86 MyApp becomes MYAPP
87 My::App becomes MY_APP
88
89=cut
90
91sub class2env {
92 my $class = shift || '';
0ef447d8 93 $class =~ s/::/_/g;
3ad654e0 94 return uc($class);
95}
96
b5ecfcf0 97=head2 class2prefix( $class, $case );
f05af9ba 98
e2cc89a9 99Returns the uri prefix for a class. If case is false the prefix is converted to lowercase.
f05af9ba 100
0ef447d8 101 My::App::Controller::Foo::Bar becomes foo/bar
2d90477f 102
f05af9ba 103=cut
104
105sub class2prefix {
106 my $class = shift || '';
e494bd6b 107 my $case = shift || 0;
f05af9ba 108 my $prefix;
0ef447d8 109 if ( $class =~ /^.+?::([MVC]|Model|View|Controller)::(.+)$/ ) {
e494bd6b 110 $prefix = $case ? $2 : lc $2;
0ef447d8 111 $prefix =~ s{::}{/}g;
f05af9ba 112 }
113 return $prefix;
114}
115
b5ecfcf0 116=head2 class2tempdir( $class [, $create ] );
37a3ac5c 117
e2cc89a9 118Returns a tempdir for a class. If create is true it will try to create the path.
37a3ac5c 119
120 My::App becomes /tmp/my/app
121 My::App::C::Foo::Bar becomes /tmp/my/app/c/foo/bar
122
123=cut
124
125sub class2tempdir {
126 my $class = shift || '';
127 my $create = shift || 0;
4be535b1 128 my @parts = split '::', lc $class;
37a3ac5c 129
130 my $tmpdir = dir( File::Spec->tmpdir, @parts )->cleanup;
131
4be535b1 132 if ( $create && !-e $tmpdir ) {
37a3ac5c 133
134 eval { $tmpdir->mkpath };
135
4be535b1 136 if ($@) {
37a3ac5c 137 Catalyst::Exception->throw(
4be535b1 138 message => qq/Couldn't create tmpdir '$tmpdir', "$@"/ );
37a3ac5c 139 }
140 }
141
142 return $tmpdir->stringify;
143}
144
b5ecfcf0 145=head2 home($class)
812a28c9 146
147Returns home directory for given class.
148
149=cut
150
151sub home {
51f412bd 152 my $class = shift;
153
154 # make an $INC{ $key } style string from the class name
155 (my $file = "$class.pm") =~ s{::}{/}g;
156
157 if ( my $inc_entry = $INC{$file} ) {
51452916 158 {
51f412bd 159 # look for an uninstalled Catalyst app
160
161 # find the @INC entry in which $file was found
162 (my $path = $inc_entry) =~ s/$file$//;
2f381252 163 $path ||= cwd() if !defined $path || !length $path;
51f412bd 164 my $home = dir($path)->absolute->cleanup;
165
166 # pop off /lib and /blib if they're there
167 $home = $home->parent while $home =~ /b?lib$/;
168
169 # only return the dir if it has a Makefile.PL or Build.PL
c09c6cd7 170 if (-f $home->file("Makefile.PL") or -f $home->file("Build.PL")) {
171
172 # clean up relative path:
173 # MyApp/script/.. -> MyApp
174
059c085b 175 my $dir;
176 my @dir_list = $home->dir_list();
177 while (($dir = pop(@dir_list)) && $dir eq '..') {
c09c6cd7 178 $home = dir($home)->parent->parent;
179 }
180
181 return $home->stringify;
182 }
51452916 183 }
4be535b1 184
51f412bd 185 {
186 # look for an installed Catalyst app
187
188 # trim the .pm off the thing ( Foo/Bar.pm -> Foo/Bar/ )
189 ( my $path = $inc_entry) =~ s/\.pm$//;
190 my $home = dir($path)->absolute->cleanup;
191
192 # return if if it's a valid directory
193 return $home->stringify if -d $home;
62459712 194 }
812a28c9 195 }
51f412bd 196
197 # we found nothing
198 return 0;
812a28c9 199}
200
b5ecfcf0 201=head2 prefix($class, $name);
812a28c9 202
203Returns a prefixed action.
204
0ef447d8 205 MyApp::Controller::Foo::Bar, yada becomes foo/bar/yada
812a28c9 206
207=cut
208
209sub prefix {
210 my ( $class, $name ) = @_;
211 my $prefix = &class2prefix($class);
212 $name = "$prefix/$name" if $prefix;
213 return $name;
214}
215
b5ecfcf0 216=head2 request($uri)
4d60aa90 217
e2cc89a9 218Returns an L<HTTP::Request> object for a uri.
4d60aa90 219
220=cut
221
222sub request {
223 my $request = shift;
224 unless ( ref $request ) {
a88c7ec8 225 if ( $request =~ m/^http/i ) {
f4c0f6f7 226 $request = URI->new($request);
4d60aa90 227 }
228 else {
f4c0f6f7 229 $request = URI->new( 'http://localhost' . $request );
4d60aa90 230 }
231 }
232 unless ( ref $request eq 'HTTP::Request' ) {
233 $request = HTTP::Request->new( 'GET', $request );
234 }
4d60aa90 235 return $request;
236}
237
dd91afb5 238=head2 ensure_class_loaded($class_name, \%opts)
d9183506 239
240Loads the class unless it already has been loaded.
241
dd91afb5 242If $opts{ignore_loaded} is true always tries the require whether the package
243already exists or not. Only pass this if you're either (a) sure you know the
244file exists on disk or (b) have code to catch the file not found exception
245that will result if it doesn't.
246
d9183506 247=cut
248
249sub ensure_class_loaded {
250 my $class = shift;
d06051f7 251 my $opts = shift;
d9183506 252
5e5bd6df 253 croak "Malformed class Name $class"
254 if $class =~ m/(?:\b\:\b|\:{3,})/;
255
59ede84e 256 croak "Malformed class Name $class"
257 if $class =~ m/[^\w:]/;
258
259 croak "ensure_class_loaded should be given a classname, not a filename ($class)"
260 if $class =~ m/\.pm$/;
261
d06051f7 262 return if !$opts->{ ignore_loaded }
fbedfd6b 263 && Class::MOP::is_class_loaded($class); # if a symbol entry exists we don't load again
264
265 # as soon as Class::MOP 0.67 + 1 is released Class::MOP::load_class($class) can be used instead
d9183506 266
267 # this hack is so we don't overwrite $@ if the load did not generate an error
268 my $error;
269 {
270 local $@;
7a1958eb 271 my $file = $class . '.pm';
272 $file =~ s{::}{/}g;
273 eval { CORE::require($file) };
d9183506 274 $error = $@;
275 }
6bfff75e 276
d9183506 277 die $error if $error;
fbedfd6b 278
6bfff75e 279 die "require $class was successful but the package is not defined"
fbedfd6b 280 unless Class::MOP::is_class_loaded($class);
6bfff75e 281
282 return 1;
d9183506 283}
284
358e1592 285=head2 merge_hashes($hashref, $hashref)
286
287Base code to recursively merge two hashes together with right-hand precedence.
288
289=cut
290
291sub merge_hashes {
292 my ( $lefthash, $righthash ) = @_;
293
294 return $lefthash unless defined $righthash;
295
296 my %merged = %$lefthash;
0ef447d8 297 for my $key ( keys %$righthash ) {
298 my $right_ref = ( ref $righthash->{ $key } || '' ) eq 'HASH';
299 my $left_ref = ( ( exists $lefthash->{ $key } && ref $lefthash->{ $key } ) || '' ) eq 'HASH';
300 if( $right_ref and $left_ref ) {
358e1592 301 $merged{ $key } = merge_hashes(
302 $lefthash->{ $key }, $righthash->{ $key }
0ef447d8 303 );
358e1592 304 }
305 else {
306 $merged{ $key } = $righthash->{ $key };
0ef447d8 307 }
358e1592 308 }
309
310 return \%merged;
311}
312
cb69249e 313=head2 env_value($class, $key)
314
315Checks for and returns an environment value. For instance, if $key is
316'home', then this method will check for and return the first value it finds,
317looking at $ENV{MYAPP_HOME} and $ENV{CATALYST_HOME}.
318
319=cut
320
321sub env_value {
322 my ( $class, $key ) = @_;
323
324 $key = uc($key);
325 my @prefixes = ( class2env($class), 'CATALYST' );
326
327 for my $prefix (@prefixes) {
328 if ( defined( my $value = $ENV{"${prefix}_${key}"} ) ) {
329 return $value;
330 }
331 }
332
333 return;
334}
d9183506 335
2f381252 336=head1 AUTHORS
f05af9ba 337
2f381252 338Catalyst Contributors, see Catalyst.pm
f05af9ba 339
340=head1 COPYRIGHT
341
342This program is free software, you can redistribute it and/or modify it under
343the same terms as Perl itself.
344
345=cut
346
3471;