package Bread::Board::Types; our $AUTHORITY = 'cpan:STEVAN'; # ABSTRACT: types and coercions for Bread::Board $Bread::Board::Types::VERSION = '0.37'; use Moose::Util::TypeConstraints; use Scalar::Util qw(blessed); use Bread::Board::Service; use Bread::Board::Dependency; ## for Bread::Board::Container class_type 'Bread::Board::Container'; class_type 'Bread::Board::Container::Parameterized'; subtype 'Bread::Board::Container::SubContainerList' => as 'HashRef[Bread::Board::Container|Bread::Board::Container::Parameterized]'; coerce 'Bread::Board::Container::SubContainerList' => from 'ArrayRef[Bread::Board::Container]' => via { +{ map { $_->name => $_ } @$_ } }; subtype 'Bread::Board::Container::ServiceList' => as 'HashRef[Bread::Board::Service]'; coerce 'Bread::Board::Container::ServiceList' => from 'ArrayRef[Bread::Board::Service]' => via { +{ map { $_->name => $_ } @$_ } }; ## for Bread::Board::Service::WithDependencies ... subtype 'Bread::Board::Service::Dependencies' => as 'HashRef[Bread::Board::Dependency]'; my $ANON_INDEX = 1; sub _coerce_to_dependency { my ($dep) = @_; if (!blessed($dep)) { if (ref $dep eq 'HASH') { my ($service_path) = keys %$dep; my ($service_params) = values %$dep; $dep = Bread::Board::Dependency->new( service_path => $service_path, service_params => $service_params ); } elsif (ref $dep eq 'ARRAY') { require Bread::Board::BlockInjection; my $name = '_ANON_COERCE_' . $ANON_INDEX++ . '_'; my @deps = map { _coerce_to_dependency($_) } @$dep; my @dep_names = map { "${name}DEP_$_" } 0..$#deps; $dep = Bread::Board::Dependency->new( service_name => $name, service => Bread::Board::BlockInjection->new( name => $name, dependencies => { map { $dep_names[$_] => $deps[$_]->[1] } 0..$#deps }, block => sub { my ($s) = @_; return [ map { $s->param($_) } @dep_names ]; }, ), ); $dep->service->parent($dep); } else { $dep = Bread::Board::Dependency->new(service_path => $dep); } } if ($dep->isa('Bread::Board::Dependency')) { return [$dep->service_name => $dep]; } else { return [$dep->name => Bread::Board::Dependency->new(service => $dep)]; } } coerce 'Bread::Board::Service::Dependencies' => from 'HashRef[Bread::Board::Service | Bread::Board::Dependency | Str | HashRef | ArrayRef]' => via { +{ map { $_ => _coerce_to_dependency($_[0]->{$_})->[1] } keys %{$_[0]} } } => from 'ArrayRef[Bread::Board::Service | Bread::Board::Dependency | Str | HashRef]' => via { +{ map { @{ _coerce_to_dependency($_) } } @{$_[0]} } }; ## for Bread::Board::Service::WithParameters ... subtype 'Bread::Board::Service::Parameters' => as 'HashRef'; coerce 'Bread::Board::Service::Parameters' => from 'ArrayRef' => via { +{ map { $_ => { optional => 0 } } @$_ } }; no Moose::Util::TypeConstraints; 1; __END__ =pod =encoding UTF-8 =head1 NAME Bread::Board::Types - types and coercions for Bread::Board =head1 VERSION version 0.37 =head1 DESCRIPTION This package defines types and coercions for L. =head1 TYPES =head2 C A hashref mapping strings to instances of L or L. Can be coerced from an arrayref of containers: the keys will be the containers' names. =head2 C A hashref mapping strings to instances of L. Can be coerced from an arrayref of services: the keys will be the services' names. =head2 C Hashref mapping strings to instances of L. The values of the hashref can be coerced in several different ways: =over 4 =item a string will be interpreted as the L<< C|Bread::Board::Dependency/service_path >> =item a hashref with a single key the key will be interpreted as a L<< C|Bread::Board::Dependency/service_path >>, and the value as a hashref for L<< C|Bread::Board::Dependency/service_params >> =item an arrayref each element will be interpreted as a dependency (possibly through all the coercions listed here); see below for an example =item a L object will be interpreted as a dependency on that service =item a L object will be taken as-is =back Instead of a hashref of any of the above things, you can use an arrayref: it will be coerced to hashref, using the (coerced) dependencies' names as keys. =head3 Examples service foo => ( class => 'Foo', dependencies => { { bar => { attribute => 12 } }, }, ); The service C depends on the parameterized service C, and C will be instantiated passing the hashref C<< { attribute => 12 } >> to its L<< C|Bread::Board::Service::WithParameters/get >> method. service foo => ( class => 'Foo', dependencies => { things => [ 'bar', 'baz' ], }, ); The service C depends on the services C and C, and when instantiating C, its constructor will receive something like C<< things => [ $instance_of_bar, $instance_of_baz ] >>. service foo => ( class => 'Foo', dependencies => { things => [ { bar => { attribute => 12 } }, { bar => { attribute => 27 } }, ], }, ); You can mix&match the coercions! This C will get two different instances of C in its C attribute, each C instantiated with a different value. =head2 C Hashref mapping strings to L specifications. Can be coerced from an arrayref of strings: [qw(a b c)] becomes: { a => { optional => 0 }, b => { optional => 0 }, c => { optional => 0 }, } =head1 AUTHOR Stevan Little =head1 BUGS Please report any bugs or feature requests on the bugtracker website https://github.com/stevan/BreadBoard/issues When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2019, 2017, 2016, 2015, 2014, 2013, 2011, 2009 by Infinity Interactive. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut