removed build_root_container()
[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;
b4a6fa62 9
10extends 'Bread::Board::Container';
11
12has config_local_suffix => (
13 is => 'rw',
14 isa => 'Str',
15 default => 'local',
16);
17
18has driver => (
19 is => 'rw',
20 isa => 'HashRef',
21 default => sub { +{} },
22);
23
24has file => (
25 is => 'rw',
26 isa => 'Str',
27 default => '',
28);
29
30has substitutions => (
31 is => 'rw',
32 isa => 'HashRef',
33 default => sub { +{} },
34);
35
36has name => (
37 is => 'rw',
38 isa => 'Str',
39 default => 'TestApp',
40);
41
2bb0da6d 42has sub_container_class => (
43 isa => LoadableClass,
44 is => 'ro',
45 coerce => 1,
46 default => 'Bread::Board::Container',
47);
48
b4a6fa62 49sub BUILD {
50 my $self = shift;
51
7451d1ea 52 $self->${\"build_${_}_service"} for qw/
53 substitutions
54 file
55 driver
56 name
57 prefix
58 extensions
59 path
60 config
61 raw_config
62 global_files
63 local_files
64 global_config
65 local_config
66 config_local_suffix
67 config_path
68 /;
f04816ce 69
70 $self->build_model_subcontainer;
71 $self->build_view_subcontainer;
72 $self->build_controller_subcontainer;
73}
74
75sub build_model_subcontainer {
76 my $self = shift;
77
2bb0da6d 78 $self->add_sub_container(
79 $self->sub_container_class->new( name => 'model' )
80 );
f04816ce 81}
82
83sub build_view_subcontainer {
84 my $self = shift;
85
2bb0da6d 86 $self->add_sub_container(
87 $self->sub_container_class->new( name => 'view' )
88 );
f04816ce 89}
90
91sub build_controller_subcontainer {
92 my $self = shift;
93
2bb0da6d 94 $self->add_sub_container(
95 $self->sub_container_class->new( name => 'controller' )
96 );
f04816ce 97}
98
f04816ce 99sub build_name_service {
100 my $self = shift;
101 $self->add_service(
102 Bread::Board::Literal->new( name => 'name', value => $self->name )
103 );
104}
105
106sub build_driver_service {
107 my $self = shift;
108 $self->add_service(
109 Bread::Board::Literal->new( name => 'driver', value => $self->driver )
110 );
111}
112
113sub build_file_service {
114 my $self = shift;
115 $self->add_service(
116 Bread::Board::Literal->new( name => 'file', value => $self->file )
117 );
118}
119
120sub build_substitutions_service {
121 my $self = shift;
122 $self->add_service(
123 Bread::Board::Literal->new( name => 'substitutions', value => $self->substitutions )
124 );
125}
126
127sub build_extensions_service {
128 my $self = shift;
129 $self->add_service(
130 Bread::Board::BlockInjection->new(
131 name => 'extensions',
b4a6fa62 132 block => sub {
133 return \@{Config::Any->extensions};
134 },
f04816ce 135 )
136 );
137}
b4a6fa62 138
f04816ce 139sub build_prefix_service {
140 my $self = shift;
141 $self->add_service(
142 Bread::Board::BlockInjection->new(
143 name => 'prefix',
b4a6fa62 144 block => sub {
145 return Catalyst::Utils::appprefix( shift->param('name') );
146 },
147 dependencies => [ depends_on('name') ],
f04816ce 148 )
149 );
150}
b4a6fa62 151
f04816ce 152sub build_path_service {
153 my $self = shift;
154 $self->add_service(
155 Bread::Board::BlockInjection->new(
156 name => 'path',
b4a6fa62 157 block => sub {
158 my $s = shift;
159
160 return Catalyst::Utils::env_value( $s->param('name'), 'CONFIG' )
161 || $s->param('file')
162 || $s->param('name')->path_to( $s->param('prefix') );
163 },
164 dependencies => [ depends_on('file'), depends_on('name'), depends_on('prefix') ],
f04816ce 165 )
166 );
167}
b4a6fa62 168
f04816ce 169sub build_config_service {
170 my $self = shift;
171 $self->add_service(
172 Bread::Board::BlockInjection->new(
173 name => 'config',
b4a6fa62 174 block => sub {
175 my $s = shift;
176
177 my $v = Data::Visitor::Callback->new(
178 plain_value => sub {
179 return unless defined $_;
180 return $self->_config_substitutions( $s->param('name'), $s->param('substitutions'), $_ );
181 }
182
183 );
184 $v->visit( $s->param('raw_config') );
185 },
186 dependencies => [ depends_on('name'), depends_on('raw_config'), depends_on('substitutions') ],
f04816ce 187 )
188 );
189}
b4a6fa62 190
f04816ce 191sub build_raw_config_service {
192 my $self = shift;
193 $self->add_service(
194 Bread::Board::BlockInjection->new(
195 name => 'raw_config',
b4a6fa62 196 block => sub {
197 my $s = shift;
198
199 my @global = @{$s->param('global_config')};
200 my @locals = @{$s->param('local_config')};
201
202 my $config = {};
203 for my $cfg (@global, @locals) {
204 for (keys %$cfg) {
205 $config = Catalyst::Utils::merge_hashes( $config, $cfg->{$_} );
206 }
207 }
208 return $config;
209 },
210 dependencies => [ depends_on('global_config'), depends_on('local_config') ],
f04816ce 211 )
212 );
213}
b4a6fa62 214
f04816ce 215sub build_global_files_service {
216 my $self = shift;
217 $self->add_service(
218 Bread::Board::BlockInjection->new(
219 name => 'global_files',
b4a6fa62 220 block => sub {
221 my $s = shift;
222
223 my ( $path, $extension ) = @{$s->param('config_path')};
224
225 my @extensions = @{$s->param('extensions')};
226
227 my @files;
228 if ( $extension ) {
229 die "Unable to handle files with the extension '${extension}'" unless grep { $_ eq $extension } @extensions;
230 push @files, $path;
231 } else {
232 @files = map { "$path.$_" } @extensions;
233 }
234 return \@files;
235 },
236 dependencies => [ depends_on('extensions'), depends_on('config_path') ],
f04816ce 237 )
238 );
239}
b4a6fa62 240
f04816ce 241sub build_local_files_service {
242 my $self = shift;
243 $self->add_service(
244 Bread::Board::BlockInjection->new(
245 name => 'local_files',
b4a6fa62 246 block => sub {
247 my $s = shift;
248
249 my ( $path, $extension ) = @{$s->param('config_path')};
250 my $suffix = $s->param('config_local_suffix');
251
252 my @extensions = @{$s->param('extensions')};
253
254 my @files;
255 if ( $extension ) {
256 die "Unable to handle files with the extension '${extension}'" unless grep { $_ eq $extension } @extensions;
257 $path =~ s{\.$extension}{_$suffix.$extension};
258 push @files, $path;
259 } else {
260 @files = map { "${path}_${suffix}.$_" } @extensions;
261 }
262 return \@files;
263 },
264 dependencies => [ depends_on('extensions'), depends_on('config_path'), depends_on('config_local_suffix') ],
f04816ce 265 )
266 );
267}
b4a6fa62 268
f04816ce 269sub build_global_config_service {
270 my $self = shift;
271 $self->add_service(
272 Bread::Board::BlockInjection->new(
273 name => 'global_config',
b4a6fa62 274 block => sub {
275 my $s = shift;
9ea11efb 276
f228c263 277 return Config::Any->load_files({
278 files => $s->param('global_files'),
b4a6fa62 279 filter => \&_fix_syntax,
280 use_ext => 1,
281 driver_args => $s->param('driver'),
282 });
b4a6fa62 283 },
284 dependencies => [ depends_on('global_files') ],
f04816ce 285 )
286 );
287}
b4a6fa62 288
f04816ce 289sub build_local_config_service {
290 my $self = shift;
291 $self->add_service(
292 Bread::Board::BlockInjection->new(
293 name => 'local_config',
b4a6fa62 294 block => sub {
295 my $s = shift;
296
f228c263 297 return Config::Any->load_files({
298 files => $s->param('local_files'),
b4a6fa62 299 filter => \&_fix_syntax,
300 use_ext => 1,
301 driver_args => $s->param('driver'),
302 });
b4a6fa62 303 },
304 dependencies => [ depends_on('local_files') ],
f04816ce 305 )
306 );
307}
b4a6fa62 308
f04816ce 309sub build_config_path_service {
310 my $self = shift;
311 $self->add_service(
312 Bread::Board::BlockInjection->new(
313 name => 'config_path',
b4a6fa62 314 block => sub {
315 my $s = shift;
316
317 my $path = $s->param('path');
318 my $prefix = $s->param('prefix');
319
320 my ( $extension ) = ( $path =~ m{\.(.{1,4})$} );
321
322 if ( -d $path ) {
323 $path =~ s{[\/\\]$}{};
324 $path .= "/$prefix";
325 }
326
327 return [ $path, $extension ];
328 },
329 dependencies => [ depends_on('prefix'), depends_on('path') ],
f04816ce 330 )
331 );
332}
b4a6fa62 333
f04816ce 334sub build_config_local_suffix_service {
335 my $self = shift;
336 $self->add_service(
337 Bread::Board::BlockInjection->new(
338 name => 'config_local_suffix',
b4a6fa62 339 block => sub {
340 my $s = shift;
341 my $suffix = Catalyst::Utils::env_value( $s->param('name'), 'CONFIG_LOCAL_SUFFIX' ) || $self->config_local_suffix;
342
343 return $suffix;
344 },
345 dependencies => [ depends_on('name') ],
f04816ce 346 )
347 );
b4a6fa62 348}
349
350sub _fix_syntax {
351 my $config = shift;
352 my @components = (
353 map +{
354 prefix => $_ eq 'Component' ? '' : $_ . '::',
355 values => delete $config->{ lc $_ } || delete $config->{ $_ }
356 },
357 grep { ref $config->{ lc $_ } || ref $config->{ $_ } }
358 qw( Component Model M View V Controller C Plugin )
359 );
360
361 foreach my $comp ( @components ) {
362 my $prefix = $comp->{ prefix };
363 foreach my $element ( keys %{ $comp->{ values } } ) {
364 $config->{ "$prefix$element" } = $comp->{ values }->{ $element };
365 }
366 }
367}
368
369sub _config_substitutions {
6682389c 370 my ( $self, $name, $subs, $arg ) = @_;
b4a6fa62 371
372 $subs->{ HOME } ||= sub { shift->path_to( '' ); };
373 $subs->{ ENV } ||=
374 sub {
375 my ( $c, $v ) = @_;
376 if (! defined($ENV{$v})) {
377 Catalyst::Exception->throw( message =>
378 "Missing environment variable: $v" );
379 return "";
380 } else {
381 return $ENV{ $v };
382 }
383 };
384 $subs->{ path_to } ||= sub { shift->path_to( @_ ); };
385 $subs->{ literal } ||= sub { return $_[ 1 ]; };
386 my $subsre = join( '|', keys %$subs );
387
6682389c 388 $arg =~ s{__($subsre)(?:\((.+?)\))?__}{ $subs->{ $1 }->( $name, $2 ? split( /,/, $2 ) : () ) }eg;
389 return $arg;
b4a6fa62 390}
391
c733a6d6 392sub get_component {
393 my ( $self, $type, $name, $args ) = @_;
394 return $self->get_sub_container($type)->resolve( service => $name, parameters => { context => $args } );
395}
396
b4a6fa62 3971;