3

Using Moose and Bread::Board, is it possible to create an object with an attribute that has an ArrayRef[SomeObject] type constraint and have that parameter injected in such a way that:

  • The ArrayRef constraint is maintained,
  • Each object that is a member of that ArrayRef has all of its dependencies met by Bread::Board, and
  • Each object that is a member of that ArrayRef is an object that was created by Bread::Board?

In order to make sure that I'm explaining myself clearly, let's consider an incredibly naive example. Let's say we have a Wheel class:

package Wheel;
use Moose;

has ['size', 'maker'] => (isa => 'Str', is => 'rw', required => 1);

And let's create a Vehicle class where each instance contains a bunch of wheels:

package Vehicle;
use Moose;

has 'wheels' => (
    is => 'rw',
    isa => 'ArrayRef[Wheel]',
    required => 1,
);

Is it then possible to create one or more instances of Wheel and then inject an array reference containing those instances into our new Vehicle instance? This obviously won't work:

my $c = container 'app' => as {
    container 'wheels' => as {
        service 'maker' => "Bob's Tires";
        service 'size' => "195R65/15";
        service 'carTires' => (
            class   => 'Wheel',
            dependencies => [ depends_on('maker'), depends_on('size') ],
        )
    };

    container 'vehicles' => as {
        service 'sedan' => (
            class   => 'Vehicle',
            dependencies => {
                # WON'T WORK
                wheels => depends_on('/wheels/carTires'),
            }
        )
    };
};
my $v = $c->resolve(service => 'vehicles/sedan');

Any ideas? Yes, I am aware that it my Vehicles can conceivably have no wheels and that I'm trying to create a one-wheeled sedan, but I think you get my point. :-) This is intended only to be an incredibly trivial example.

Ether
  • 53,118
  • 13
  • 86
  • 159
  • this is old, and I don't want to type out a long answer, but [my blog post on using providers](http://www.xenoterracide.com/2013/10/providing-with-providers-and-breadboard.html) might help people solving problems like this – xenoterracide Nov 01 '13 at 06:57

1 Answers1

4

You could get the carTires service to return a ArrayRef of Wheels:

container 'wheels' => as {
    service 'carTires' => (
        block => sub {
            return [ map {Wheel->new} 1..4 ];
        },
    )
};

The Vehicle constructor will take care of the rest in terms of the type constraint, since you've already defined it as ArrayRef[Wheel].

So it will die if you did this instead:

container 'wheels' => as {
    service 'carTires' => (
        block => sub {
            return [ map {Window->new} 1..4 ];
        },
    )
};
stevenl
  • 6,736
  • 26
  • 33
  • Thanks for this answer! I've re-phrased my original question to add the additional caveat that `Wheel` also has dependencies that need to be met - would using block injection in a similar manner still be the right solution? – 9numbernine9 Jun 14 '11 at 11:34
  • I would think so since block injection is the most flexible in terms of what you can do with it. The problem with the other injection methods is I can't see where we can use them to create an ArrayRef of multiple object instances. – stevenl Jun 14 '11 at 13:55