Initial commit of Moosified Catalyst parts.
[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;
d9183506 9use Class::Inspector;
5e5bd6df 10use Carp qw/croak/;
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$//;
163 my $home = dir($path)->absolute->cleanup;
164
165 # pop off /lib and /blib if they're there
166 $home = $home->parent while $home =~ /b?lib$/;
167
168 # only return the dir if it has a Makefile.PL or Build.PL
c09c6cd7 169 if (-f $home->file("Makefile.PL") or -f $home->file("Build.PL")) {
170
171 # clean up relative path:
172 # MyApp/script/.. -> MyApp
173
059c085b 174 my $dir;
175 my @dir_list = $home->dir_list();
176 while (($dir = pop(@dir_list)) && $dir eq '..') {
c09c6cd7 177 $home = dir($home)->parent->parent;
178 }
179
180 return $home->stringify;
181 }
51452916 182 }
4be535b1 183
51f412bd 184 {
185 # look for an installed Catalyst app
186
187 # trim the .pm off the thing ( Foo/Bar.pm -> Foo/Bar/ )
188 ( my $path = $inc_entry) =~ s/\.pm$//;
189 my $home = dir($path)->absolute->cleanup;
190
191 # return if if it's a valid directory
192 return $home->stringify if -d $home;
62459712 193 }
812a28c9 194 }
51f412bd 195
196 # we found nothing
197 return 0;
812a28c9 198}
199
b5ecfcf0 200=head2 prefix($class, $name);
812a28c9 201
202Returns a prefixed action.
203
0ef447d8 204 MyApp::Controller::Foo::Bar, yada becomes foo/bar/yada
812a28c9 205
206=cut
207
208sub prefix {
209 my ( $class, $name ) = @_;
210 my $prefix = &class2prefix($class);
211 $name = "$prefix/$name" if $prefix;
212 return $name;
213}
214
b5ecfcf0 215=head2 request($uri)
4d60aa90 216
e2cc89a9 217Returns an L<HTTP::Request> object for a uri.
4d60aa90 218
219=cut
220
221sub request {
222 my $request = shift;
223 unless ( ref $request ) {
a88c7ec8 224 if ( $request =~ m/^http/i ) {
f4c0f6f7 225 $request = URI->new($request);
4d60aa90 226 }
227 else {
f4c0f6f7 228 $request = URI->new( 'http://localhost' . $request );
4d60aa90 229 }
230 }
231 unless ( ref $request eq 'HTTP::Request' ) {
232 $request = HTTP::Request->new( 'GET', $request );
233 }
4d60aa90 234 return $request;
235}
236
dd91afb5 237=head2 ensure_class_loaded($class_name, \%opts)
d9183506 238
239Loads the class unless it already has been loaded.
240
dd91afb5 241If $opts{ignore_loaded} is true always tries the require whether the package
242already exists or not. Only pass this if you're either (a) sure you know the
243file exists on disk or (b) have code to catch the file not found exception
244that will result if it doesn't.
245
d9183506 246=cut
247
248sub ensure_class_loaded {
249 my $class = shift;
d06051f7 250 my $opts = shift;
d9183506 251
5e5bd6df 252 croak "Malformed class Name $class"
253 if $class =~ m/(?:\b\:\b|\:{3,})/;
254
59ede84e 255 croak "Malformed class Name $class"
256 if $class =~ m/[^\w:]/;
257
258 croak "ensure_class_loaded should be given a classname, not a filename ($class)"
259 if $class =~ m/\.pm$/;
260
d06051f7 261 return if !$opts->{ ignore_loaded }
262 && Class::Inspector->loaded( $class ); # if a symbol entry exists we don't load again
d9183506 263
264 # this hack is so we don't overwrite $@ if the load did not generate an error
265 my $error;
266 {
267 local $@;
7a1958eb 268 my $file = $class . '.pm';
269 $file =~ s{::}{/}g;
270 eval { CORE::require($file) };
d9183506 271 $error = $@;
272 }
6bfff75e 273
d9183506 274 die $error if $error;
6bfff75e 275 die "require $class was successful but the package is not defined"
276 unless Class::Inspector->loaded($class);
277
278 return 1;
d9183506 279}
280
358e1592 281=head2 merge_hashes($hashref, $hashref)
282
283Base code to recursively merge two hashes together with right-hand precedence.
284
285=cut
286
287sub merge_hashes {
288 my ( $lefthash, $righthash ) = @_;
289
290 return $lefthash unless defined $righthash;
291
292 my %merged = %$lefthash;
0ef447d8 293 for my $key ( keys %$righthash ) {
294 my $right_ref = ( ref $righthash->{ $key } || '' ) eq 'HASH';
295 my $left_ref = ( ( exists $lefthash->{ $key } && ref $lefthash->{ $key } ) || '' ) eq 'HASH';
296 if( $right_ref and $left_ref ) {
358e1592 297 $merged{ $key } = merge_hashes(
298 $lefthash->{ $key }, $righthash->{ $key }
0ef447d8 299 );
358e1592 300 }
301 else {
302 $merged{ $key } = $righthash->{ $key };
0ef447d8 303 }
358e1592 304 }
305
306 return \%merged;
307}
308
cb69249e 309=head2 env_value($class, $key)
310
311Checks for and returns an environment value. For instance, if $key is
312'home', then this method will check for and return the first value it finds,
313looking at $ENV{MYAPP_HOME} and $ENV{CATALYST_HOME}.
314
315=cut
316
317sub env_value {
318 my ( $class, $key ) = @_;
319
320 $key = uc($key);
321 my @prefixes = ( class2env($class), 'CATALYST' );
322
323 for my $prefix (@prefixes) {
324 if ( defined( my $value = $ENV{"${prefix}_${key}"} ) ) {
325 return $value;
326 }
327 }
328
329 return;
330}
d9183506 331
f05af9ba 332=head1 AUTHOR
333
334Sebastian Riedel, C<sri@cpan.org>
d9183506 335Yuval Kogman, C<nothingmuch@woobling.org>
f05af9ba 336
337=head1 COPYRIGHT
338
339This program is free software, you can redistribute it and/or modify it under
340the same terms as Perl itself.
341
342=cut
343
3441;