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