A new (read: experimental) feature of Bread::Board is typemapped services. These are services which are
mapped to a particular type rather then just a name. This feature has the potential to make obsolete a
large amount of the Bread::Board configuration by simply asking Bread::Board to figure things out on its
own. Here is a small example of how this works.
# define the classes making sure
# to specify required items and
# their types
{
package Stapler;
use Moose;
package Desk;
use Moose;
package Chair;
use Moose;
package Cubicle;
use Moose;
has 'desk' => ( is => 'ro', isa => 'Desk', required => 1 );
has 'chair' => ( is => 'ro', isa => 'Chair', required => 1 );
package Employee;
use Moose;
has [ 'first_name', 'last_name' ] => (
is => 'ro',
isa => 'Str',
required => 1,
);
has 'stapler' => ( is => 'rw', isa => 'Stapler', predicate => 'has_stapler' );
has 'work_area' => ( is => 'ro', isa => 'Cubicle', required => 1 );
}
# now create the container, and
# map the Employee type and ask
# Bread::Board to infer all the
# other relationships
my $c = container 'Initech' => as {
typemap 'Employee' => infer;
};
# now you can create new Employee objects
# by calling ->resolve with the type and
# supplying the required parameters (see
# below for details).
my $micheal = $c->resolve(
type => 'Employee',
parameters => {
first_name => 'Micheal',
last_name => 'Bolton'
}
);
my $cube = $micheal->work_area; # this will be a Cubicle object
$cube->desk; # this will be a Desk object
$cube->chair; # this will be a Chair object
$micheal->has_stapler; # this is false
# We can create another Employee object
# and this time we pass in the optional
# parameter for the non-required 'stapler'
# attribute
my $milton = $c->resolve(
type => 'Employee',
parameters => {
first_name => 'Milton',
last_name => 'Waddams',
stapler => Stapler->new
}
);
$milton->has_stapler; # this is true
In the above example, we created a number of Moose classes that had specific required relationships. When
we called "infer" for the Employee object, Bread::Board figured out those relationships and set up
dependencies and parameters accordingly.
For the "work_area" object, we saw the Cubicle type and then basically called "infer" on the Cubicle
object. We then saw the Desk and Chair objects and called "infer" on those as well. The result of this
recursive inference was that the Employee, Cubicle, Desk and Chair relationships were modeled in
Bread::Board as dependent services.
Bread::Board also took it one step further.
We were able to resolve the Cubicle, Desk and Chair types automatically because they were already defined
by Moose as subtypes of the Object type. We knew that it could introspect those classes and get more
information. However, this was not the case with the first_name and last_name attributes of the Employee
object. In that case, we determined that we couldn't resolve those objects and (because it was a top-
level inference) instead turned them into required parameters for the inferred Employee service.
And lastly, with a top-level inference (not one caused by recursion) Bread::Board will also look at all
the remaining non-required attributes and turn them into optional parameters. In this case we have a
"stapler" attribute that is not required and so is listed as an optional parameter, meaning that it is
not required, but still subject to type checking.