Trivial cleanup using delegate method
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Container.pm
CommitLineData
b4a6fa62 1package Catalyst::Container;
2use Bread::Board;
3use Moose;
4use Config::Any;
5use Data::Visitor::Callback;
6use Catalyst::Utils ();
2bb0da6d 7use MooseX::Types::LoadableClass qw/ LoadableClass /;
38215fbf 8use Catalyst::BlockInjection;
8b749525 9use namespace::autoclean;
b4a6fa62 10
11extends 'Bread::Board::Container';
12
8b749525 13# FIXME - Why do any of these attributes need to be rw?
b4a6fa62 14has config_local_suffix => (
15 is => 'rw',
16 isa => 'Str',
17 default => 'local',
18);
19
20has driver => (
21 is => 'rw',
22 isa => 'HashRef',
23 default => sub { +{} },
24);
25
26has file => (
27 is => 'rw',
28 isa => 'Str',
29 default => '',
30);
31
32has substitutions => (
33 is => 'rw',
34 isa => 'HashRef',
35 default => sub { +{} },
36);
37
38has name => (
39 is => 'rw',
40 isa => 'Str',
41 default => 'TestApp',
42);
43
2bb0da6d 44has sub_container_class => (
45 isa => LoadableClass,
46 is => 'ro',
47 coerce => 1,
59aacfa7 48 default => 'Catalyst::SubContainer',
8b749525 49 handles => {
50 new_sub_container => 'new',
51 }
2bb0da6d 52);
53
8b749525 54# FIXME - Move all the Pod to the bottom!
55
bf3c8088 56=head1 NAME
57
58Catalyst::Container - IOC for Catalyst components
59
60=head1 METHODS
61
62=cut
63
b4a6fa62 64sub BUILD {
65 my $self = shift;
66
292277c1 67 $self->add_service(
68 $self->${\"build_${_}_service"}
69 ) for qw/
7451d1ea 70 substitutions
71 file
72 driver
73 name
74 prefix
75 extensions
76 path
77 config
78 raw_config
79 global_files
80 local_files
81 global_config
82 local_config
83 config_local_suffix
84 config_path
85 /;
f04816ce 86
292277c1 87 $self->add_sub_container(
88 $self->${ \"build_${_}_subcontainer" }
89 ) for qw/ model view controller /;
f04816ce 90}
91
bf3c8088 92=head2 build_model_subcontainer
93
94=cut
95
f04816ce 96sub build_model_subcontainer {
97 my $self = shift;
98
8b749525 99 return $self->new_sub_container( name => 'model' );
f04816ce 100}
101
bf3c8088 102=head2 build_view_subcontainer
103
104=cut
105
f04816ce 106sub build_view_subcontainer {
107 my $self = shift;
108
8b749525 109 return $self->new_sub_container( name => 'view' );
f04816ce 110}
111
bf3c8088 112=head2 build_controller_subcontainer
113
114=cut
115
f04816ce 116sub build_controller_subcontainer {
117 my $self = shift;
118
8b749525 119 return $self->new_sub_container( name => 'controller' );
f04816ce 120}
121
bf3c8088 122=head2 build_name_service
f04816ce 123
bf3c8088 124=cut
f04816ce 125
126sub build_name_service {
127 my $self = shift;
292277c1 128
129 return Bread::Board::Literal->new( name => 'name', value => $self->name );
f04816ce 130}
131
bf3c8088 132=head2 build_driver_service
133
134=cut
135
f04816ce 136sub build_driver_service {
137 my $self = shift;
292277c1 138
139 return Bread::Board::Literal->new( name => 'driver', value => $self->driver );
f04816ce 140}
141
bf3c8088 142=head2 build_file_service
143
144=cut
145
f04816ce 146sub build_file_service {
147 my $self = shift;
292277c1 148
149 return Bread::Board::Literal->new( name => 'file', value => $self->file );
f04816ce 150}
151
bf3c8088 152=head2 build_substitutions_service
153
154=cut
155
f04816ce 156sub build_substitutions_service {
157 my $self = shift;
292277c1 158
159 return Bread::Board::Literal->new( name => 'substitutions', value => $self->substitutions );
f04816ce 160}
161
bf3c8088 162=head2 build_extensions_service
163
164=cut
165
f04816ce 166sub build_extensions_service {
167 my $self = shift;
292277c1 168
169 return Bread::Board::BlockInjection->new(
170 name => 'extensions',
171 block => sub {
172 return \@{Config::Any->extensions};
173 },
f04816ce 174 );
175}
b4a6fa62 176
bf3c8088 177=head2 build_prefix_service
178
179=cut
180
f04816ce 181sub build_prefix_service {
182 my $self = shift;
292277c1 183
184 return Bread::Board::BlockInjection->new(
185 name => 'prefix',
186 block => sub {
187 return Catalyst::Utils::appprefix( shift->param('name') );
188 },
189 dependencies => [ depends_on('name') ],
f04816ce 190 );
191}
b4a6fa62 192
bf3c8088 193=head2 build_path_service
194
195=cut
196
f04816ce 197sub build_path_service {
198 my $self = shift;
292277c1 199
200 return Bread::Board::BlockInjection->new(
201 name => 'path',
202 block => sub {
203 my $s = shift;
204
205 return Catalyst::Utils::env_value( $s->param('name'), 'CONFIG' )
206 || $s->param('file')
207 || $s->param('name')->path_to( $s->param('prefix') );
208 },
209 dependencies => [ depends_on('file'), depends_on('name'), depends_on('prefix') ],
f04816ce 210 );
211}
b4a6fa62 212
bf3c8088 213=head2 build_config_service
214
215=cut
216
f04816ce 217sub build_config_service {
218 my $self = shift;
292277c1 219
220 return Bread::Board::BlockInjection->new(
221 name => 'config',
222 block => sub {
223 my $s = shift;
224
225 my $v = Data::Visitor::Callback->new(
226 plain_value => sub {
227 return unless defined $_;
228 return $self->_config_substitutions( $s->param('name'), $s->param('substitutions'), $_ );
229 }
230
231 );
232 $v->visit( $s->param('raw_config') );
233 },
234 dependencies => [ depends_on('name'), depends_on('raw_config'), depends_on('substitutions') ],
f04816ce 235 );
236}
b4a6fa62 237
bf3c8088 238=head2 build_raw_config_service
239
240=cut
241
f04816ce 242sub build_raw_config_service {
243 my $self = shift;
292277c1 244
245 return Bread::Board::BlockInjection->new(
246 name => 'raw_config',
247 block => sub {
248 my $s = shift;
249
250 my @global = @{$s->param('global_config')};
251 my @locals = @{$s->param('local_config')};
252
253 my $config = {};
254 for my $cfg (@global, @locals) {
255 for (keys %$cfg) {
256 $config = Catalyst::Utils::merge_hashes( $config, $cfg->{$_} );
b4a6fa62 257 }
292277c1 258 }
259 return $config;
260 },
261 dependencies => [ depends_on('global_config'), depends_on('local_config') ],
f04816ce 262 );
263}
b4a6fa62 264
bf3c8088 265=head2 build_global_files_service
266
267=cut
268
f04816ce 269sub build_global_files_service {
270 my $self = shift;
b4a6fa62 271
292277c1 272 return Bread::Board::BlockInjection->new(
273 name => 'global_files',
274 block => sub {
275 my $s = shift;
b4a6fa62 276
292277c1 277 my ( $path, $extension ) = @{$s->param('config_path')};
b4a6fa62 278
292277c1 279 my @extensions = @{$s->param('extensions')};
280
281 my @files;
282 if ( $extension ) {
283 die "Unable to handle files with the extension '${extension}'" unless grep { $_ eq $extension } @extensions;
284 push @files, $path;
285 } else {
286 @files = map { "$path.$_" } @extensions;
287 }
288 return \@files;
289 },
290 dependencies => [ depends_on('extensions'), depends_on('config_path') ],
f04816ce 291 );
292}
b4a6fa62 293
bf3c8088 294=head2 build_local_files_service
295
296=cut
297
f04816ce 298sub build_local_files_service {
299 my $self = shift;
292277c1 300
301 return Bread::Board::BlockInjection->new(
302 name => 'local_files',
303 block => sub {
304 my $s = shift;
305
306 my ( $path, $extension ) = @{$s->param('config_path')};
307 my $suffix = $s->param('config_local_suffix');
308
309 my @extensions = @{$s->param('extensions')};
310
311 my @files;
312 if ( $extension ) {
313 die "Unable to handle files with the extension '${extension}'" unless grep { $_ eq $extension } @extensions;
314 $path =~ s{\.$extension}{_$suffix.$extension};
315 push @files, $path;
316 } else {
317 @files = map { "${path}_${suffix}.$_" } @extensions;
318 }
319 return \@files;
320 },
321 dependencies => [ depends_on('extensions'), depends_on('config_path'), depends_on('config_local_suffix') ],
f04816ce 322 );
323}
b4a6fa62 324
bf3c8088 325=head2 build_global_config_service
326
327=cut
328
f04816ce 329sub build_global_config_service {
330 my $self = shift;
292277c1 331
332 return Bread::Board::BlockInjection->new(
333 name => 'global_config',
334 block => sub {
335 my $s = shift;
336
337 return Config::Any->load_files({
338 files => $s->param('global_files'),
339 filter => \&_fix_syntax,
340 use_ext => 1,
341 driver_args => $s->param('driver'),
342 });
343 },
344 dependencies => [ depends_on('global_files') ],
f04816ce 345 );
346}
b4a6fa62 347
bf3c8088 348=head2 build_local_config_service
349
350=cut
351
f04816ce 352sub build_local_config_service {
353 my $self = shift;
292277c1 354
355 return Bread::Board::BlockInjection->new(
356 name => 'local_config',
357 block => sub {
358 my $s = shift;
359
360 return Config::Any->load_files({
361 files => $s->param('local_files'),
362 filter => \&_fix_syntax,
363 use_ext => 1,
364 driver_args => $s->param('driver'),
365 });
366 },
367 dependencies => [ depends_on('local_files') ],
f04816ce 368 );
369}
b4a6fa62 370
bf3c8088 371=head2 build_config_path_service
372
373=cut
374
f04816ce 375sub build_config_path_service {
376 my $self = shift;
b4a6fa62 377
292277c1 378 return Bread::Board::BlockInjection->new(
379 name => 'config_path',
380 block => sub {
381 my $s = shift;
b4a6fa62 382
292277c1 383 my $path = $s->param('path');
384 my $prefix = $s->param('prefix');
b4a6fa62 385
292277c1 386 my ( $extension ) = ( $path =~ m{\.(.{1,4})$} );
387
388 if ( -d $path ) {
389 $path =~ s{[\/\\]$}{};
390 $path .= "/$prefix";
391 }
b4a6fa62 392
292277c1 393 return [ $path, $extension ];
394 },
395 dependencies => [ depends_on('prefix'), depends_on('path') ],
f04816ce 396 );
397}
b4a6fa62 398
bf3c8088 399=head2 build_config_local_suffix_service
400
401=cut
402
f04816ce 403sub build_config_local_suffix_service {
404 my $self = shift;
292277c1 405
406 return Bread::Board::BlockInjection->new(
407 name => 'config_local_suffix',
408 block => sub {
409 my $s = shift;
410 my $suffix = Catalyst::Utils::env_value( $s->param('name'), 'CONFIG_LOCAL_SUFFIX' ) || $self->config_local_suffix;
411
412 return $suffix;
413 },
414 dependencies => [ depends_on('name') ],
f04816ce 415 );
b4a6fa62 416}
417
bf3c8088 418=head2 _fix_syntax
419
420=cut
421
b4a6fa62 422sub _fix_syntax {
423 my $config = shift;
424 my @components = (
425 map +{
426 prefix => $_ eq 'Component' ? '' : $_ . '::',
427 values => delete $config->{ lc $_ } || delete $config->{ $_ }
428 },
429 grep { ref $config->{ lc $_ } || ref $config->{ $_ } }
430 qw( Component Model M View V Controller C Plugin )
431 );
432
433 foreach my $comp ( @components ) {
434 my $prefix = $comp->{ prefix };
435 foreach my $element ( keys %{ $comp->{ values } } ) {
436 $config->{ "$prefix$element" } = $comp->{ values }->{ $element };
437 }
438 }
439}
440
bf3c8088 441=head2 _config_substitutions
442
443=cut
444
b4a6fa62 445sub _config_substitutions {
6682389c 446 my ( $self, $name, $subs, $arg ) = @_;
b4a6fa62 447
448 $subs->{ HOME } ||= sub { shift->path_to( '' ); };
449 $subs->{ ENV } ||=
450 sub {
451 my ( $c, $v ) = @_;
452 if (! defined($ENV{$v})) {
453 Catalyst::Exception->throw( message =>
454 "Missing environment variable: $v" );
455 return "";
456 } else {
457 return $ENV{ $v };
458 }
459 };
460 $subs->{ path_to } ||= sub { shift->path_to( @_ ); };
461 $subs->{ literal } ||= sub { return $_[ 1 ]; };
462 my $subsre = join( '|', keys %$subs );
463
6682389c 464 $arg =~ s{__($subsre)(?:\((.+?)\))?__}{ $subs->{ $1 }->( $name, $2 ? split( /,/, $2 ) : () ) }eg;
465 return $arg;
b4a6fa62 466}
467
bf3c8088 468=head1 AUTHORS
469
e8ed391e 470Catalyst Contributors, see Catalyst.pm
bf3c8088 471
e8ed391e 472=head1 COPYRIGHT
bf3c8088 473
474This library is free software. You can redistribute it and/or modify it under
475the same terms as Perl itself.
476
477=cut
478
b4a6fa62 4791;