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