updated test to look for exception, not warning
[catagits/Catalyst-Runtime.git] / lib / Catalyst / IOC / Container.pm
CommitLineData
a6c13ff4 1package Catalyst::IOC::Container;
b4a6fa62 2use Bread::Board;
3use Moose;
4use Config::Any;
5use Data::Visitor::Callback;
6use Catalyst::Utils ();
d3742403 7use Devel::InnerPackage ();
b4410fc3 8use Hash::Util qw/lock_hash/;
2bb0da6d 9use MooseX::Types::LoadableClass qw/ LoadableClass /;
0dff29e2 10use Moose::Util;
b7da37bd 11use Catalyst::IOC::ConstructorInjection;
2f32de9a 12use Module::Pluggable::Object ();
8b749525 13use namespace::autoclean;
b4a6fa62 14
15extends 'Bread::Board::Container';
16
17has config_local_suffix => (
442ab13e 18 is => 'ro',
b4a6fa62 19 isa => 'Str',
20 default => 'local',
21);
22
23has driver => (
442ab13e 24 is => 'ro',
b4a6fa62 25 isa => 'HashRef',
26 default => sub { +{} },
27);
28
29has file => (
442ab13e 30 is => 'ro',
b4a6fa62 31 isa => 'Str',
32 default => '',
33);
34
35has substitutions => (
442ab13e 36 is => 'ro',
b4a6fa62 37 isa => 'HashRef',
38 default => sub { +{} },
39);
40
6c743f02 41has application_name => (
442ab13e 42 is => 'ro',
b4a6fa62 43 isa => 'Str',
a0146296 44 default => 'MyApp',
b4a6fa62 45);
46
2bb0da6d 47has sub_container_class => (
48 isa => LoadableClass,
49 is => 'ro',
50 coerce => 1,
a6c13ff4 51 default => 'Catalyst::IOC::SubContainer',
8b749525 52 handles => {
53 new_sub_container => 'new',
54 }
2bb0da6d 55);
56
b4a6fa62 57sub BUILD {
a2c0d071 58 my ( $self, $params ) = @_;
b4a6fa62 59
292277c1 60 $self->add_service(
61 $self->${\"build_${_}_service"}
62 ) for qw/
7451d1ea 63 substitutions
64 file
65 driver
6c743f02 66 application_name
7451d1ea 67 prefix
68 extensions
69 path
70 config
71 raw_config
72 global_files
73 local_files
74 global_config
75 local_config
0fcf9a51 76 class_config
7451d1ea 77 config_local_suffix
78 config_path
3e4f5406 79 locate_components
7451d1ea 80 /;
f04816ce 81
0fcf9a51 82 my $config = $self->resolve( service => 'config' );
83
292277c1 84 $self->add_sub_container(
a2c0d071 85 $self->build_controller_subcontainer
86 );
87
88 $self->add_sub_container(
89 $self->build_view_subcontainer(
0fcf9a51 90 default_component => $config->{default_view},
a2c0d071 91 )
92 );
93
94 $self->add_sub_container(
95 $self->build_model_subcontainer(
0fcf9a51 96 default_component => $config->{default_model},
a2c0d071 97 )
98 );
f04816ce 99}
100
101sub build_model_subcontainer {
102 my $self = shift;
103
a2c0d071 104 return $self->new_sub_container( @_,
5a53ef3d 105 name => 'model',
b06ded69 106 );
f04816ce 107}
108
109sub build_view_subcontainer {
110 my $self = shift;
111
a2c0d071 112 return $self->new_sub_container( @_,
5a53ef3d 113 name => 'view',
b06ded69 114 );
f04816ce 115}
116
117sub build_controller_subcontainer {
118 my $self = shift;
119
b06ded69 120 return $self->new_sub_container(
5a53ef3d 121 name => 'controller',
b06ded69 122 );
f04816ce 123}
124
5b47e4a9 125sub build_application_name_service {
f04816ce 126 my $self = shift;
292277c1 127
6c743f02 128 return Bread::Board::Literal->new( name => 'application_name', value => $self->application_name );
f04816ce 129}
130
131sub build_driver_service {
132 my $self = shift;
292277c1 133
134 return Bread::Board::Literal->new( name => 'driver', value => $self->driver );
f04816ce 135}
136
137sub build_file_service {
138 my $self = shift;
292277c1 139
140 return Bread::Board::Literal->new( name => 'file', value => $self->file );
f04816ce 141}
142
143sub build_substitutions_service {
144 my $self = shift;
292277c1 145
146 return Bread::Board::Literal->new( name => 'substitutions', value => $self->substitutions );
f04816ce 147}
148
149sub build_extensions_service {
150 my $self = shift;
292277c1 151
152 return Bread::Board::BlockInjection->new(
7a267bb5 153 lifecycle => 'Singleton',
292277c1 154 name => 'extensions',
155 block => sub {
156 return \@{Config::Any->extensions};
157 },
f04816ce 158 );
159}
b4a6fa62 160
f04816ce 161sub build_prefix_service {
162 my $self = shift;
292277c1 163
164 return Bread::Board::BlockInjection->new(
7a267bb5 165 lifecycle => 'Singleton',
292277c1 166 name => 'prefix',
167 block => sub {
dca40344 168 return Catalyst::Utils::appprefix( shift->param('application_name') );
292277c1 169 },
dca40344 170 dependencies => [ depends_on('application_name') ],
f04816ce 171 );
172}
b4a6fa62 173
f04816ce 174sub build_path_service {
175 my $self = shift;
292277c1 176
177 return Bread::Board::BlockInjection->new(
7a267bb5 178 lifecycle => 'Singleton',
292277c1 179 name => 'path',
180 block => sub {
181 my $s = shift;
182
dca40344 183 return Catalyst::Utils::env_value( $s->param('application_name'), 'CONFIG' )
292277c1 184 || $s->param('file')
6c743f02 185 || $s->param('application_name')->path_to( $s->param('prefix') );
292277c1 186 },
6c743f02 187 dependencies => [ depends_on('file'), depends_on('application_name'), depends_on('prefix') ],
f04816ce 188 );
189}
b4a6fa62 190
f04816ce 191sub build_config_service {
192 my $self = shift;
292277c1 193
194 return Bread::Board::BlockInjection->new(
7a267bb5 195 lifecycle => 'Singleton',
292277c1 196 name => 'config',
197 block => sub {
198 my $s = shift;
199
200 my $v = Data::Visitor::Callback->new(
201 plain_value => sub {
202 return unless defined $_;
6c743f02 203 return $self->_config_substitutions( $s->param('application_name'), $s->param('substitutions'), $_ );
292277c1 204 }
205
206 );
207 $v->visit( $s->param('raw_config') );
208 },
6c743f02 209 dependencies => [ depends_on('application_name'), depends_on('raw_config'), depends_on('substitutions') ],
f04816ce 210 );
211}
b4a6fa62 212
f04816ce 213sub build_raw_config_service {
214 my $self = shift;
292277c1 215
216 return Bread::Board::BlockInjection->new(
7a267bb5 217 lifecycle => 'Singleton',
292277c1 218 name => 'raw_config',
219 block => sub {
220 my $s = shift;
221
222 my @global = @{$s->param('global_config')};
223 my @locals = @{$s->param('local_config')};
224
0fcf9a51 225 my $config = $s->param('class_config');
226
292277c1 227 for my $cfg (@global, @locals) {
228 for (keys %$cfg) {
229 $config = Catalyst::Utils::merge_hashes( $config, $cfg->{$_} );
b4a6fa62 230 }
292277c1 231 }
0fcf9a51 232
292277c1 233 return $config;
234 },
0fcf9a51 235 dependencies => [ depends_on('global_config'), depends_on('local_config'), depends_on('class_config') ],
f04816ce 236 );
237}
b4a6fa62 238
f04816ce 239sub build_global_files_service {
240 my $self = shift;
b4a6fa62 241
292277c1 242 return Bread::Board::BlockInjection->new(
7a267bb5 243 lifecycle => 'Singleton',
292277c1 244 name => 'global_files',
245 block => sub {
246 my $s = shift;
b4a6fa62 247
292277c1 248 my ( $path, $extension ) = @{$s->param('config_path')};
b4a6fa62 249
292277c1 250 my @extensions = @{$s->param('extensions')};
251
252 my @files;
253 if ( $extension ) {
254 die "Unable to handle files with the extension '${extension}'" unless grep { $_ eq $extension } @extensions;
255 push @files, $path;
256 } else {
257 @files = map { "$path.$_" } @extensions;
258 }
259 return \@files;
260 },
261 dependencies => [ depends_on('extensions'), depends_on('config_path') ],
f04816ce 262 );
263}
b4a6fa62 264
f04816ce 265sub build_local_files_service {
266 my $self = shift;
292277c1 267
268 return Bread::Board::BlockInjection->new(
7a267bb5 269 lifecycle => 'Singleton',
292277c1 270 name => 'local_files',
271 block => sub {
272 my $s = shift;
273
274 my ( $path, $extension ) = @{$s->param('config_path')};
275 my $suffix = $s->param('config_local_suffix');
276
277 my @extensions = @{$s->param('extensions')};
278
279 my @files;
280 if ( $extension ) {
281 die "Unable to handle files with the extension '${extension}'" unless grep { $_ eq $extension } @extensions;
282 $path =~ s{\.$extension}{_$suffix.$extension};
283 push @files, $path;
284 } else {
285 @files = map { "${path}_${suffix}.$_" } @extensions;
286 }
287 return \@files;
288 },
289 dependencies => [ depends_on('extensions'), depends_on('config_path'), depends_on('config_local_suffix') ],
f04816ce 290 );
291}
b4a6fa62 292
0fcf9a51 293sub build_class_config_service {
294 my $self = shift;
295
296 return Bread::Board::BlockInjection->new(
297 lifecycle => 'Singleton',
298 name => 'class_config',
299 block => sub {
300 my $s = shift;
301 my $app = $s->param('application_name');
302
303 # Container might be called outside Catalyst context
304 return {} unless Class::MOP::is_class_loaded($app);
305
306 # config might not have been defined
307 return $app->config || {};
308 },
309 dependencies => [ depends_on('application_name') ],
310 );
311}
312
f04816ce 313sub build_global_config_service {
314 my $self = shift;
292277c1 315
316 return Bread::Board::BlockInjection->new(
7a267bb5 317 lifecycle => 'Singleton',
292277c1 318 name => 'global_config',
319 block => sub {
320 my $s = shift;
321
322 return Config::Any->load_files({
323 files => $s->param('global_files'),
324 filter => \&_fix_syntax,
325 use_ext => 1,
326 driver_args => $s->param('driver'),
327 });
328 },
329 dependencies => [ depends_on('global_files') ],
f04816ce 330 );
331}
b4a6fa62 332
f04816ce 333sub build_local_config_service {
334 my $self = shift;
292277c1 335
336 return Bread::Board::BlockInjection->new(
7a267bb5 337 lifecycle => 'Singleton',
292277c1 338 name => 'local_config',
339 block => sub {
340 my $s = shift;
341
342 return Config::Any->load_files({
343 files => $s->param('local_files'),
344 filter => \&_fix_syntax,
345 use_ext => 1,
346 driver_args => $s->param('driver'),
347 });
348 },
349 dependencies => [ depends_on('local_files') ],
f04816ce 350 );
351}
b4a6fa62 352
f04816ce 353sub build_config_path_service {
354 my $self = shift;
b4a6fa62 355
292277c1 356 return Bread::Board::BlockInjection->new(
7a267bb5 357 lifecycle => 'Singleton',
292277c1 358 name => 'config_path',
359 block => sub {
360 my $s = shift;
b4a6fa62 361
292277c1 362 my $path = $s->param('path');
363 my $prefix = $s->param('prefix');
b4a6fa62 364
292277c1 365 my ( $extension ) = ( $path =~ m{\.(.{1,4})$} );
366
367 if ( -d $path ) {
368 $path =~ s{[\/\\]$}{};
369 $path .= "/$prefix";
370 }
b4a6fa62 371
292277c1 372 return [ $path, $extension ];
373 },
374 dependencies => [ depends_on('prefix'), depends_on('path') ],
f04816ce 375 );
376}
b4a6fa62 377
f04816ce 378sub build_config_local_suffix_service {
379 my $self = shift;
292277c1 380
381 return Bread::Board::BlockInjection->new(
7a267bb5 382 lifecycle => 'Singleton',
292277c1 383 name => 'config_local_suffix',
384 block => sub {
385 my $s = shift;
6c743f02 386 my $suffix = Catalyst::Utils::env_value( $s->param('application_name'), 'CONFIG_LOCAL_SUFFIX' ) || $self->config_local_suffix;
292277c1 387
388 return $suffix;
389 },
6c743f02 390 dependencies => [ depends_on('application_name') ],
f04816ce 391 );
b4a6fa62 392}
393
3e4f5406 394sub build_locate_components_service {
395 my $self = shift;
396
397 return Bread::Board::BlockInjection->new(
398 lifecycle => 'Singleton',
399 name => 'locate_components',
400 block => sub {
401 my $s = shift;
402 my $class = $s->param('application_name');
403 my $config = $s->param('config')->{ setup_components };
404
405 Catalyst::Exception->throw(
406 qq{You are using search_extra config option. That option is\n} .
407 qq{deprecated, please refer to the documentation for\n} .
408 qq{other ways of achieving the same results.\n}
409 ) if delete $config->{ search_extra };
410
411 my @paths = qw( ::Controller ::C ::Model ::M ::View ::V );
412
413 my $locator = Module::Pluggable::Object->new(
414 search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
415 %$config
416 );
417
b47ed80b 418 return [ $locator->plugins ];
3e4f5406 419 },
420 dependencies => [ depends_on('application_name'), depends_on('config') ],
421 );
422}
423
88d81c1b 424sub setup_components {
fa6607ec 425 my $self = shift;
88d81c1b 426 my $class = $self->resolve( service => 'application_name' );
427 my @comps = @{ $self->resolve( service => 'locate_components' ) };
428 my %comps = map { $_ => 1 } @comps;
429 my $deprecatedcatalyst_component_names = 0;
fa6607ec 430
88d81c1b 431 for my $component ( @comps ) {
fa6607ec 432
88d81c1b 433 # We pass ignore_loaded here so that overlay files for (e.g.)
434 # Model::DBI::Schema sub-classes are loaded - if it's in @comps
435 # we know M::P::O found a file on disk so this is safe
fa6607ec 436
88d81c1b 437 Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
438 }
fa6607ec 439
88d81c1b 440 for my $component (@comps) {
6e2a1222 441 $self->add_component( $component );
88d81c1b 442 # FIXME - $instance->expand_modules() is broken
443 my @expanded_components = $self->expand_component_module( $component );
444
445 if (
446 !$deprecatedcatalyst_component_names &&
447 ($deprecatedcatalyst_component_names = $component =~ m/::[CMV]::/) ||
448 ($deprecatedcatalyst_component_names = grep { /::[CMV]::/ } @expanded_components)
449 ) {
450 # FIXME - should I be calling warn here?
6e2a1222 451 # Maybe it's time to remove it, or become fatal
88d81c1b 452 $class->log->warn(qq{Your application is using the deprecated ::[MVC]:: type naming scheme.\n}.
453 qq{Please switch your class names to ::Model::, ::View:: and ::Controller: as appropriate.\n}
454 );
455 }
fa6607ec 456
88d81c1b 457 for my $component (@expanded_components) {
6e2a1222 458 $self->add_component( $component )
88d81c1b 459 unless $comps{$component};
460 }
461 }
fa6607ec 462
88d81c1b 463 $self->get_sub_container('model')->make_single_default;
464 $self->get_sub_container('view')->make_single_default;
fa6607ec 465}
466
b4a6fa62 467sub _fix_syntax {
468 my $config = shift;
469 my @components = (
470 map +{
471 prefix => $_ eq 'Component' ? '' : $_ . '::',
472 values => delete $config->{ lc $_ } || delete $config->{ $_ }
473 },
474 grep { ref $config->{ lc $_ } || ref $config->{ $_ } }
475 qw( Component Model M View V Controller C Plugin )
476 );
477
478 foreach my $comp ( @components ) {
479 my $prefix = $comp->{ prefix };
480 foreach my $element ( keys %{ $comp->{ values } } ) {
481 $config->{ "$prefix$element" } = $comp->{ values }->{ $element };
482 }
483 }
484}
485
486sub _config_substitutions {
6682389c 487 my ( $self, $name, $subs, $arg ) = @_;
b4a6fa62 488
489 $subs->{ HOME } ||= sub { shift->path_to( '' ); };
490 $subs->{ ENV } ||=
491 sub {
492 my ( $c, $v ) = @_;
493 if (! defined($ENV{$v})) {
494 Catalyst::Exception->throw( message =>
495 "Missing environment variable: $v" );
496 return "";
497 } else {
498 return $ENV{ $v };
499 }
500 };
501 $subs->{ path_to } ||= sub { shift->path_to( @_ ); };
502 $subs->{ literal } ||= sub { return $_[ 1 ]; };
503 my $subsre = join( '|', keys %$subs );
504
6682389c 505 $arg =~ s{__($subsre)(?:\((.+?)\))?__}{ $subs->{ $1 }->( $name, $2 ? split( /,/, $2 ) : () ) }eg;
506 return $arg;
b4a6fa62 507}
508
a17e0ff8 509sub get_component_from_sub_container {
510 my ( $self, $sub_container_name, $name, $c, @args ) = @_;
511
512 my $sub_container = $self->get_sub_container( $sub_container_name );
513
0e747f0c 514 if (!$name) {
a2c0d071 515 my $default = $sub_container->default_component;
0e747f0c 516
517 return $sub_container->get_component( $default, $c, @args )
518 if $default && $sub_container->has_service( $default );
519
a0146296 520 # FIXME - should I be calling $c->log->warn here?
0e747f0c 521 # this is never a controller, so this is safe
522 $c->log->warn( "Calling \$c->$sub_container_name() is not supported unless you specify one of:" );
523 $c->log->warn( "* \$c->config(default_$sub_container_name => 'the name of the default $sub_container_name to use')" );
524 $c->log->warn( "* \$c->stash->{current_$sub_container_name} # the name of the view to use for this request" );
525 $c->log->warn( "* \$c->stash->{current_${sub_container_name}_instance} # the instance of the $sub_container_name to use for this request" );
a2c0d071 526
527 return;
0e747f0c 528 }
529
a17e0ff8 530 return $sub_container->get_component_regexp( $name, $c, @args )
531 if ref $name;
532
533 return $sub_container->get_component( $name, $c, @args )
534 if $sub_container->has_service( $name );
535
536 $c->log->warn(
537 "Attempted to use $sub_container_name '$name', " .
538 "but it does not exist"
539 );
540
541 return;
542}
543
c4aedec7 544sub find_component {
d0f954b4 545 my ( $self, $component, $c, @args ) = @_;
f147e6c2 546 my ( $type, $name ) = _get_component_type_name($component);
c4aedec7 547 my @result;
548
d0f954b4 549 return $self->get_component_from_sub_container(
550 $type, $name, $c, @args
551 ) if $type;
552
c4aedec7 553 my $query = ref $component
554 ? $component
555 : qr{^$component$}
556 ;
557
558 for my $subcontainer_name (qw/model view controller/) {
a0146296 559 my $subcontainer = $self->get_sub_container( $subcontainer_name );
c4aedec7 560 my @components = $subcontainer->get_service_list;
561 @result = grep { m{$component} } @components;
562
d0f954b4 563 return map { $subcontainer->get_component( $_, $c, @args ) } @result
c4aedec7 564 if @result;
565 }
566
a0146296 567 # FIXME - I guess I shouldn't be calling $c->components here
d0f954b4 568 # one last search for things like $c->comp(qr/::M::/)
569 @result = $self->find_component_regexp(
570 $c->components, $component, $c, @args
571 ) if !@result and ref $component;
572
c4aedec7 573 # it expects an empty list on failed searches
574 return @result;
575}
576
4e2b302e 577sub find_component_regexp {
578 my ( $self, $components, $component, @args ) = @_;
579 my @result;
580
581 my @components = grep { m{$component} } keys %{ $components };
582
583 for (@components) {
f147e6c2 584 my ($type, $name) = _get_component_type_name($_);
4e2b302e 585
586 push @result, $self->get_component_from_sub_container(
587 $type, $name, @args
588 ) if $type;
589 }
590
591 return @result;
592}
593
9f4997cf 594# FIXME - t0m, how do you feel about this name?
595# also, do you think I should draw it here, or just return the data structure?
596sub get_components_names_types {
be80b0a5 597 my ( $self ) = @_;
9f4997cf 598 my @comps_names_types;
be80b0a5 599
600 for my $sub_container_name (qw/model view controller/) {
601 my $sub_container = $self->get_sub_container($sub_container_name);
602 for my $service ( $sub_container->get_service_list ) {
603 my $comp = $self->resolve(service => $service);
604 my $compname = ref $comp || $comp;
605 my $type = ref $comp ? 'instance' : 'class';
9f4997cf 606 push @comps_names_types, [ $compname, $type ];
be80b0a5 607 }
608 }
609
9f4997cf 610 return @comps_names_types;
be80b0a5 611}
c4aedec7 612
b4410fc3 613sub get_all_components {
614 my $self = shift;
615 my %components;
616
617 my $containers = {
618 map { $_ => $self->get_sub_container($_) } qw(model view controller)
619 };
620
621 for my $container (keys %$containers) {
622 for my $component ($containers->{$container}->get_service_list) {
623 my $comp = $containers->{$container}->resolve(
624 service => $component
625 );
626 my $comp_name = ref $comp || $comp;
627 $components{$comp_name} = $comp;
628 }
629 }
630
631 return lock_hash %components;
632}
633
f147e6c2 634sub add_component {
6e2a1222 635 my ( $self, $component ) = @_;
f147e6c2 636 my ( $type, $name ) = _get_component_type_name($component);
637
638 return unless $type;
639
640 $self->get_sub_container($type)->add_service(
b7da37bd 641 Catalyst::IOC::ConstructorInjection->new(
7a267bb5 642 name => $name,
b7da37bd 643 class => $component,
bf142143 644 dependencies => [
645 depends_on( '/application_name' ),
646 depends_on( '/config' ),
647 ],
648 parameters => {
649 suffix => {
650 isa => 'Str',
651 default => Catalyst::Utils::class2classsuffix( $component ),
652 },
b1afa6e2 653 accept_context_args => {
4156b727 654 isa => 'ArrayRef|Undef',
655 required => 0,
656 default => undef,
b1afa6e2 657 },
b7da37bd 658 },
f147e6c2 659 )
660 );
661}
662
663# FIXME: should this sub exist?
664# should it be moved to Catalyst::Utils,
665# or replaced by something already existing there?
666sub _get_component_type_name {
667 my ( $component ) = @_;
668
669 my @parts = split /::/, $component;
670
671 while (my $type = shift @parts) {
672 return ('controller', join '::', @parts)
673 if $type =~ /^(c|controller)$/i;
674
675 return ('model', join '::', @parts)
676 if $type =~ /^(m|model)$/i;
677
678 return ('view', join '::', @parts)
679 if $type =~ /^(v|view)$/i;
680 }
681
682 return (undef, $component);
683}
684
d3742403 685sub expand_component_module {
686 my ( $class, $module ) = @_;
687 return Devel::InnerPackage::list_packages( $module );
688}
0dff29e2 689
d057ddb9 6901;
691
692__END__
693
694=pod
695
696=head1 NAME
697
698Catalyst::Container - IOC for Catalyst components
699
2c2ed473 700=head1 SYNOPSIS
701
702=head1 DESCRIPTION
703
d057ddb9 704=head1 METHODS
705
bbb306a9 706=head1 Building Containers
a0146296 707
d057ddb9 708=head2 build_model_subcontainer
709
a0146296 710Container that stores all models.
711
d057ddb9 712=head2 build_view_subcontainer
713
a0146296 714Container that stores all views.
715
d057ddb9 716=head2 build_controller_subcontainer
717
a0146296 718Container that stores all controllers.
719
bbb306a9 720=head1 Building Services
a0146296 721
a4541222 722=head2 build_application_name_service
d057ddb9 723
a4541222 724Name of the application (such as MyApp).
a0146296 725
d057ddb9 726=head2 build_driver_service
727
a0146296 728Config options passed directly to the driver being used.
729
d057ddb9 730=head2 build_file_service
731
a0146296 732?
733
d057ddb9 734=head2 build_substitutions_service
735
bbb306a9 736This method substitutes macros found with calls to a function. There are a
737number of default macros:
738
739=over
740
741=item * C<__HOME__> - replaced with C<$c-E<gt>path_to('')>
742
743=item * C<__ENV(foo)__> - replaced with the value of C<$ENV{foo}>
744
745=item * C<__path_to(foo/bar)__> - replaced with C<$c-E<gt>path_to('foo/bar')>
746
747=item * C<__literal(__FOO__)__> - leaves __FOO__ alone (allows you to use
748C<__DATA__> as a config value, for example)
749
750=back
751
752The parameter list is split on comma (C<,>). You can override this method to
753do your own string munging, or you can define your own macros in
754C<MyApp-E<gt>config-E<gt>{ 'Plugin::ConfigLoader' }-E<gt>{ substitutions }>.
755Example:
756
757 MyApp->config->{ 'Plugin::ConfigLoader' }->{ substitutions } = {
758 baz => sub { my $c = shift; qux( @_ ); }
759 }
760
761The above will respond to C<__baz(x,y)__> in config strings.
a0146296 762
d057ddb9 763=head2 build_extensions_service
764
bbb306a9 765Config::Any's available config file extensions (e.g. xml, json, pl, etc).
766
d057ddb9 767=head2 build_prefix_service
768
bbb306a9 769The prefix, based on the application name, that will be used to lookup the
770config files (which will be in the format $prefix.$extension). If the app is
771MyApp::Foo, the prefix will be myapp_foo.
772
d057ddb9 773=head2 build_path_service
774
bbb306a9 775The path to the config file (or environment variable, if defined).
776
d057ddb9 777=head2 build_config_service
778
bbb306a9 779The resulting configuration for the application, after it has successfully
780been loaded, and all substitutions have been made.
781
d057ddb9 782=head2 build_raw_config_service
783
bbb306a9 784The merge of local_config and global_config hashes, before substitutions.
785
d057ddb9 786=head2 build_global_files_service
787
bbb306a9 788Gets all files for config that don't have the local_suffix, such as myapp.conf.
789
d057ddb9 790=head2 build_local_files_service
791
bbb306a9 792Gets all files for config that have the local_suffix, such as myapp_local.conf.
793
d057ddb9 794=head2 build_global_config_service
795
bbb306a9 796Reads config from global_files.
797
d057ddb9 798=head2 build_local_config_service
799
bbb306a9 800Reads config from local_files.
801
800a31b0 802=head2 build_class_config_service
803
804Reads config set from the application's class attribute config,
805i.e. MyApp->config( name => 'MyApp', ... )
806
d057ddb9 807=head2 build_config_path_service
808
bbb306a9 809Splits the path to the config file, and returns on array ref containing
810the path to the config file minus the extension in the first position,
811and the extension in the second.
812
d057ddb9 813=head2 build_config_local_suffix_service
814
a0146296 815Determines the suffix of files used to override the main config. By default
816this value is C<local>, which will load C<myapp_local.conf>. The suffix can
817be specified in the following order of preference:
818
819=over
820
821=item * C<$ENV{ MYAPP_CONFIG_LOCAL_SUFFIX }>
822
823=item * C<$ENV{ CATALYST_CONFIG_LOCAL_SUFFIX }>
824
825=back
826
827The first one of these values found replaces the default of C<local> in the
828name of the local config file to be loaded.
829
830For example, if C< $ENV{ MYAPP_CONFIG_LOCAL_SUFFIX }> is set to C<testing>,
831ConfigLoader will try and load C<myapp_testing.conf> instead of
832C<myapp_local.conf>.
833
bbb306a9 834=head2 build_locate_components_service
835
836This method is meant to provide a list of component modules that should be
837setup for the application. By default, it will use L<Module::Pluggable>.
838
839Specify a C<setup_components> config option to pass additional options directly
840to L<Module::Pluggable>.
841
842=head1 Other methods
843
a0146296 844=head2 get_component_from_sub_container($sub_container, $name, $c, @args)
845
164a0b2b 846Looks for components in a given subcontainer (such as controller, model or
847view), and returns the searched component. If $name is undef, it returns the
848default component (such as default_view, if $sub_container is 'view'). If
849$name is a regexp, it returns an array of matching components. Otherwise, it
850looks for the component with name $name.
8dc2fca3 851
9f4997cf 852=head2 get_components_names_types
853
164a0b2b 854Gets all components from all containers and returns them as an array of
855arrayrefs containing the component name and the component type (i.e., whether
856it's an instance or a class).
409db9cb 857
b4410fc3 858=head2 get_all_components
859
164a0b2b 860Fetches all the components, in each of the sub_containers model, view and
861controller, and returns a readonly hash. The keys are the class names, and
862the values are the blessed objects. This is what is returned by $c->components.
a0146296 863
f147e6c2 864=head2 add_component
865
164a0b2b 866Adds a component to the appropriate subcontainer. The subcontainer is guessed
867by the component name given.
a0146296 868
c4aedec7 869=head2 find_component
870
164a0b2b 871Searches for components in all containers. If $component is the full class
872name, the subcontainer is guessed, and it gets the searched component in there.
873Otherwise, it looks for a component with that name in all subcontainers. If
874$component is a regexp, it calls the method below, find_component_regexp,
875and matches all components against that regexp.
a0146296 876
4e2b302e 877=head2 find_component_regexp
878
a0146296 879Finds components that match a given regexp. Used internally, by find_component.
880
6e2a1222 881=head2 expand_component_module
d3742403 882
883Components found by C<locate_components> will be passed to this method, which
884is expected to return a list of component (package) names to be set up.
885
ebf7f0a5 886=head2 setup_components
fa6607ec 887
bf3c8088 888=head1 AUTHORS
889
e8ed391e 890Catalyst Contributors, see Catalyst.pm
bf3c8088 891
e8ed391e 892=head1 COPYRIGHT
bf3c8088 893
894This library is free software. You can redistribute it and/or modify it under
895the same terms as Perl itself.
896
897=cut