File Coverage

blib/lib/Bread/Board.pm
Criterion Covered Total %
statement 137 137 100.0
branch 62 66 93.9
condition 11 12 91.6
subroutine 29 29 100.0
pod 11 11 100.0
total 250 255 98.0


line stmt bran cond sub pod time code
1             package Bread::Board;
2             our $AUTHORITY = 'cpan:STEVAN';
3             $Bread::Board::VERSION = '0.35';
4 53     53   5753984 use strict;
  53         149  
  53         1770  
5 53     53   331 use warnings;
  53         115  
  53         1791  
6 53     53   302 use Carp qw(confess);
  53         109  
  53         2886  
7 53     53   327 use Scalar::Util qw(blessed);
  53         117  
  53         2486  
8             # ABSTRACT: A solderless way to wire up your application components
9              
10 53     53   17070 use Bread::Board::Types;
  53         194  
  53         2636  
11 53     53   24681 use Bread::Board::ConstructorInjection;
  53         222  
  53         2244  
12 53     53   21965 use Bread::Board::SetterInjection;
  53         203  
  53         2211  
13 53     53   22569 use Bread::Board::BlockInjection;
  53         242  
  53         2390  
14 53     53   22914 use Bread::Board::Literal;
  53         222  
  53         2412  
15 53     53   25719 use Bread::Board::Container;
  53         249  
  53         2443  
16 53     53   24618 use Bread::Board::Container::Parameterized;
  53         243  
  53         2398  
17 53     53   500 use Bread::Board::Dependency;
  53         125  
  53         1383  
18 53     53   22986 use Bread::Board::LifeCycle::Singleton;
  53         218  
  53         2282  
19 53     53   20791 use Bread::Board::Service::Inferred;
  53         246  
  53         2257  
20 53     53   23356 use Bread::Board::Service::Alias;
  53         227  
  53         2483  
21              
22 53     53   469 use Exporter qw( import );
  53         119  
  53         4512  
23              
24             our @EXPORT = qw[
25             as
26             container
27             depends_on
28             service
29             alias
30             wire_names
31             include
32             typemap
33             infer
34             literal
35             ];
36              
37             # This is a chopped down version of what's in Moose::Exporter. It'd be nice if
38             # there was something on CPAN that implemented this without all the additional
39             # Moose::Exporter baggage (particularly the enabling of strict & warnings).
40             sub unimport {
41 1     1   328 my $package = caller();
42              
43 1         3 foreach my $name (@EXPORT) {
44 53     53   364 no strict 'refs';
  53         116  
  53         63212  
45 10 50       11 next unless defined &{ $package . '::' . $name };
  10         21  
46              
47 10         10 my $sub = \&{ $package . '::' . $name };
  10         17  
48              
49 10 50       35 next unless $sub eq __PACKAGE__->can($name);
50              
51 10         12 delete ${ $package . '::' }{$name};
  10         2514  
52             }
53             }
54              
55 116     116 1 406051 sub as (&) { $_[0] }
56              
57             our $CC;
58             our $in_container;
59              
60             sub set_root_container {
61 5 100   5 1 1654 confess "Can't set the root container when we're already in a container"
62             if $in_container;
63 4         13 $CC = shift;
64             }
65              
66             sub container ($;$$) {
67 124     124 1 10853 my $name = shift;
68              
69 124         263 my $c;
70 124 100       551 if (blessed $name) {
71 15 100 100     263 confess 'an object used as a container must inherit from Bread::Board::Container or Bread::Board::Container::Parameterized'
72             unless $name->isa('Bread::Board::Container') || $name->isa('Bread::Board::Container::Parameterized');
73              
74 14 100       161 confess 'container($object, ...) is not supported for parameterized containers'
75             if scalar @_ > 1;
76              
77             # this is basically:
78             # container( A::Bread::Board::Container->new, ... )
79             # or someone using &container as a constructor
80 13         27 $c = $name;
81              
82             # if we're in the context of another container
83             # then we're a subcontainer of it
84 13 50       41 $CC->add_sub_container($c) if defined $CC;
85             }
86             else {
87 109         438 my $is_inheriting = $name =~ s/^\+//;
88 109 100 100     622 confess "Inheriting containers isn't possible outside of the context of a container"
89             if $is_inheriting && !defined $CC;
90              
91             # if we have more than 1 argument, then we are a parameterized
92             # container, so we need to act accordingly
93 108 100       370 if (scalar @_ > 1) {
94 11 100       123 confess 'Declaring container parameters when inheriting is not supported'
95             if $is_inheriting;
96              
97 10         23 my $param_names = shift;
98 10         463 $c = Bread::Board::Container::Parameterized->new({
99             name => $name,
100             allowed_parameter_names => $param_names,
101             });
102             }
103             else {
104 97 100       3641 $c = $is_inheriting
105             ? $CC->fetch($name)
106             : Bread::Board::Container->new({ name => $name });
107             }
108              
109             # if we're in the context of another container
110             # then we're a subcontainer of it, unless we're inheriting,
111             # in which case we already got a parent
112 106 100 100     712 $CC->add_sub_container($c) if !$is_inheriting && defined $CC;
113             }
114              
115 119         312 my $body = shift;
116             # if we have more arguments
117             # then they are likely a body
118             # and so we should execute it
119 119 100       454 if (defined $body) {
120 113         261 local $_ = $c;
121 113         215 local $CC = $c;
122 113         243 local $in_container = 1;
123 113         372 $body->($c);
124             }
125              
126 107         2401 return $c;
127             }
128              
129             sub include ($) {
130 6     6 1 6863 my $file = shift;
131 6 100       959 if (my $ret = do $file) {
132 3         15 return $ret;
133             }
134             else {
135 3 100       351 confess "Couldn't compile $file: $@" if $@;
136 2 100       170 confess "Couldn't open $file for reading: $!" if $!;
137 1         195 confess "Unknown error when compiling $file "
138             . "(or $file doesn't return a true value)";
139             }
140             }
141              
142             sub service ($@) {
143 167     167 1 6207 my $name = shift;
144 167         293 my $s;
145              
146 167         492 my $is_inheriting = ($name =~ s/^\+//);
147              
148 167 100       727 if (scalar @_ == 1) {
    100          
149 56 100       408 confess "Service inheritance doesn't make sense for literal services"
150             if $is_inheriting;
151              
152 55         2158 $s = Bread::Board::Literal->new(name => $name, value => $_[0]);
153             }
154             elsif (scalar(@_) % 2 == 0) {
155 110         466 my %params = @_;
156              
157 110         300 my $class = $params{service_class};
158             $class ||= defined $params{service_type} ? "Bread::Board::$params{service_type}Injection"
159 110 100 66     1035 : exists $params{block} ? 'Bread::Board::BlockInjection'
    100          
160             : 'Bread::Board::ConstructorInjection';
161              
162 110 100       861 $class->does('Bread::Board::Service')
163             or confess "The service class must do the Bread::Board::Service role";
164              
165 109 100       57730 if ($is_inheriting) {
166 9 50       20 confess "Inheriting services isn't possible outside of the context of a container"
167             unless defined $CC;
168              
169 9 100       70 my $container = ($CC->isa('Bread::Board::Container::Parameterized') ? $CC->container : $CC);
170 9         28 my $prototype_service = $container->fetch($name);
171              
172 9 100       27 confess sprintf(
173             "Trying to inherit from service '%s', but found a %s",
174             $name, blessed $prototype_service,
175             ) unless $prototype_service->does('Bread::Board::Service');
176              
177 8         339 $s = $prototype_service->clone_and_inherit_params(
178             service_class => $class,
179             %params,
180             );
181             }
182             else {
183 100         3993 $s = $class->new(name => $name, %params);
184             }
185             }
186             else {
187 1         111 confess "A service is defined by a name and either a single value or hash of parameters; you have supplied neither";
188             }
189 158 100       3563 return $s unless defined $CC;
190 155         797 $CC->add_service($s);
191             }
192              
193             sub alias ($$@) {
194 24     24 1 443 my $name = shift;
195 24         47 my $path = shift;
196 24         54 my %params = @_;
197              
198 24         901 my $s = Bread::Board::Service::Alias->new(
199             name => $name,
200             aliased_from_path => $path,
201             %params,
202             );
203 24 100       64 return $s unless defined $CC;
204 23         98 $CC->add_service($s);
205             }
206              
207             sub typemap ($@) {
208 33     33 1 1634 my $type = shift;
209              
210 33 100       270 (scalar @_ == 1)
211             || confess "typemap takes a single argument";
212              
213 32         57 my $service;
214 32 100       149 if (blessed $_[0]) {
215 26 100       141 if ($_[0]->does('Bread::Board::Service')) {
    100          
216 1         44 $service = $_[0];
217             }
218             elsif ($_[0]->isa('Bread::Board::Service::Inferred')) {
219 24         3670 $service = $_[0]->infer_service( $type );
220             }
221             else {
222 1         295 confess $_[0] . " isn't a service";
223             }
224             }
225             else {
226 6         44 $service = $CC->fetch( $_[0] );
227             }
228              
229 29         135 $CC->add_type_mapping_for( $type, $service );
230             }
231              
232             sub infer {
233 24 100   24 1 1481 if (@_ == 1) {
234 1         27 return Bread::Board::Service::Inferred->new(
235             current_container => $CC,
236             service => $_[0],
237             infer_params => 1,
238             );
239             }
240             else {
241 23         70 my %params = @_;
242 23         888 return Bread::Board::Service::Inferred->new(
243             current_container => $CC,
244             service_args => \%params,
245             infer_params => 1,
246             );
247             }
248             }
249              
250 2     2 1 23 sub wire_names { +{ map { $_ => depends_on($_) } @_ }; }
  4         16  
251              
252             sub depends_on ($) {
253 65     65 1 2244 my $path = shift;
254 65         2443 Bread::Board::Dependency->new(service_path => $path);
255             }
256              
257             my $LITERAL_ANON = 0;
258             sub literal($) {
259 2     2 1 12 my $value = shift;
260 2         59 Bread::Board::Literal->new(
261             name => 'LITERAL_ANON_' . $LITERAL_ANON++,
262             value => $value,
263             );
264             }
265              
266             1;
267              
268             __END__
269              
270             =pod
271              
272             =encoding UTF-8
273              
274             =head1 NAME
275              
276             Bread::Board - A solderless way to wire up your application components
277              
278             =head1 VERSION
279              
280             version 0.35
281              
282             =head1 SYNOPSIS
283              
284             use Bread::Board;
285              
286             my $c = container 'MyApp' => as {
287              
288             service 'log_file_name' => "logfile.log";
289              
290             service 'logger' => (
291             class => 'FileLogger',
292             lifecycle => 'Singleton',
293             dependencies => [ 'log_file_name' ],
294             ]
295             );
296              
297             container 'Database' => as {
298             service 'dsn' => "dbi:SQLite:dbname=my-app.db";
299             service 'username' => "user234";
300             service 'password' => "****";
301              
302             service 'dbh' => (
303             block => sub {
304             my $s = shift;
305             require DBI;
306             DBI->connect(
307             $s->param('dsn'),
308             $s->param('username'),
309             $s->param('password'),
310             ) || die "Could not connect";
311             },
312             dependencies => [ 'dsn', 'username', 'password' ]
313             );
314             };
315              
316             service 'application' => (
317             class => 'MyApplication',
318             dependencies => {
319             logger => 'logger',
320             dbh => 'Database/dbh',
321             }
322             );
323              
324             };
325              
326             no Bread::Board; # removes keywords
327              
328             # get an instance of MyApplication
329             # from the container
330             my $app = $c->resolve( service => 'application' );
331              
332             # now user your MyApplication
333             # as you normally would ...
334             $app->run;
335              
336             =head1 DESCRIPTION
337              
338             Bread::Board is an inversion of control framework with a focus on
339             dependency injection and lifecycle management. It's goal is to
340             help you write more decoupled objects and components by removing
341             the need for you to manually wire those objects/components together.
342              
343             Want to know more? See the L<Bread::Board::Manual>.
344              
345             +-----------------------------------------+
346             | A B C D E F G H I J |
347             |-----------------------------------------|
348             | o o | 1 o-o-o-o-o v o-o-o-o-o 1 | o o |
349             | o o | 2 o-o-o-o-o o-o-o-o-o 2 | o o |
350             | o o | 3 o-o-o-o-o o-o-o-o-o 3 | o o |
351             | o o | 4 o-o-o-o-o o-o-o-o-o 4 | o o |
352             | o o | 5 o-o-o-o-o o-o-o-o-o 5 | o o |
353             | | 6 o-o-o-o-o o-o-o-o-o 6 | |
354             | o o | 7 o-o-o-o-o o-o-o-o-o 7 | o o |
355             | o o | 8 o-o-o-o-o o-o-o-o-o 8 | o o |
356             | o o | 9 o-o-o-o-o o-o-o-o-o 9 | o o |
357             | o o | 10 o-o-o-o-o o-o-o-o-o 10 | o o |
358             | o o | 11 o-o-o-o-o o-o-o-o-o 11 | o o |
359             | | 12 o-o-o-o-o o-o-o-o-o 12 | |
360             | o o | 13 o-o-o-o-o o-o-o-o-o 13 | o o |
361             | o o | 14 o-o-o-o-o o-o-o-o-o 14 | o o |
362             | o o | 15 o-o-o-o-o o-o-o-o-o 15 | o o |
363             | o o | 16 o-o-o-o-o o-o-o-o-o 16 | o o |
364             | o o | 17 o-o-o-o-o o-o-o-o-o 17 | o o |
365             | | 18 o-o-o-o-o o-o-o-o-o 18 | |
366             | o o | 19 o-o-o-o-o o-o-o-o-o 19 | o o |
367             | o o | 20 o-o-o-o-o o-o-o-o-o 20 | o o |
368             | o o | 21 o-o-o-o-o o-o-o-o-o 21 | o o |
369             | o o | 22 o-o-o-o-o o-o-o-o-o 22 | o o |
370             | o o | 22 o-o-o-o-o o-o-o-o-o 22 | o o |
371             | | 23 o-o-o-o-o o-o-o-o-o 23 | |
372             | o o | 24 o-o-o-o-o o-o-o-o-o 24 | o o |
373             | o o | 25 o-o-o-o-o o-o-o-o-o 25 | o o |
374             | o o | 26 o-o-o-o-o o-o-o-o-o 26 | o o |
375             | o o | 27 o-o-o-o-o o-o-o-o-o 27 | o o |
376             | o o | 28 o-o-o-o-o ^ o-o-o-o-o 28 | o o |
377             +-----------------------------------------+
378              
379             Loading this package will automatically load the rest of the packages needed by
380             your Bread::Board configuration.
381              
382             =head1 EXPORTED FUNCTIONS
383              
384             The functions of this package provide syntactic sugar to help you build your
385             Bread::Board configuration. You can build such a configuration by constructing
386             the objects manually instead, but your code may be more difficult to
387             understand.
388              
389             =head2 C<container>
390              
391             =head3 simple case
392              
393             container $name, \&body;
394              
395             This function constructs and returns an instance of L<Bread::Board::Container>.
396             The (optional) C<&body> block may be used to add services or sub-containers
397             within the newly constructed container. Usually, the block is not passed
398             directly, but passed using the C<as> function.
399              
400             For example,
401              
402             container 'MyWebApp' => as {
403             service my_dispatcher => (
404             class => 'MyWebApp::Dispatcher',
405             );
406             };
407              
408             If C<$name> starts with C<'+'>, and the container is being declared inside
409             another container, then this declaration will instead extend an existing
410             container with the name C<$name> (without the C<'+'>).
411              
412             =head3 from an instance
413              
414             container $container_instance, \&body
415              
416             In many cases, subclassing L<Bread::Board::Container> is the easiest route to
417             getting access to this framework. You can do this and still get all the
418             benefits of the syntactic sugar for configuring that class by passing an
419             instance of your container subclass to C<container>.
420              
421             You could, for example, configure your container inside the C<BUILD> method of
422             your class:
423              
424             package MyWebApp;
425             use Moose;
426              
427             extends 'Bread::Board::Container';
428              
429             sub BUILD {
430             my $self = shift;
431              
432             container $self => as {
433             service dbh => ( ... );
434             };
435             }
436              
437             =head3 with parameters
438              
439             container $name, \@parameters, \&body
440              
441             A third way of using the C<container> function is to build a parameterized
442             container. These are useful as a way of providing a placeholder for parts of
443             the configuration that may be provided later. You may not use an instance
444             object in place of the C<$name> in this case.
445              
446             For more detail on how you might use parameterized containers, see
447             L<Bread::Board::Manual::Concepts::Advanced/Parameterized Containers>.
448              
449             =head2 C<as>
450              
451             as { some_code() };
452              
453             This is just a replacement for the C<sub> keyword that is easier to read when
454             defining containers.
455              
456             =head2 C<service>
457              
458             service $name, $literal;
459             service $name, %service_description;
460              
461             Within the C<as> blocks for your containers, you may construct services using
462             the C<service> function. This can construct several different kinds of services
463             based upon how it is called.
464              
465             =head3 literal services
466              
467             To build a literal service (a L<Bread::Board::Literal> object), just specify a
468             scalar value or reference you want to use as the literal value:
469              
470             # In case you need to adjust the gravitational constant of the Universe
471             service gravitational_constant => 6.673E-11;
472              
473             =head3 using injections
474              
475             To build a service using one of the injection services, just fill in all the
476             details required to use that sort of injection:
477              
478             service search_service => (
479             class => 'MyApp::Search',
480             block => sub {
481             my $s = shift;
482             MyApp::Search->new($s->param('url'), $s->param('type'));
483             },
484             dependencies => {
485             url => 'search_url',
486             },
487             parameters => {
488             type => { isa => 'Str', default => 'text' },
489             },
490             );
491              
492             The type of injection performed depends on the parameters used. You may use
493             the C<service_class> parameter to pick a specific injector class. For
494             instance, this is useful if you need to use L<Bread::Board::SetterInjection>
495             or have defined a custom injection service. If you specify a C<block>, block
496             injection will be performed using L<Bread::Board::BlockInjection>. If neither
497             of these is present, constructor injection will be used with
498             L<Bread::Board::ConstructorInjection> (and you must provide the C<class>
499             option).
500              
501             =head3 service dependencies
502              
503             The C<dependencies> parameter takes a hashref of dependency names mapped to
504             L<Bread::Board::Dependency> objects, but there are several coercions and sugar
505             functions available to make specifying dependencies as easy as possible. The
506             simplest case is when the names of the services you're depending on are the
507             same as the names that the service you're defining will be accessing them with.
508             In this case, you can just specify an arrayref of service names:
509              
510             service foo => (
511             dependencies => [ 'bar', 'baz' ],
512             # ...
513             );
514              
515             If you need to use a different name, you can specify the dependencies as a
516             hashref instead:
517              
518             service foo => (
519             dependencies => {
520             dbh => 'foo_dbh',
521             },
522             # ...
523             );
524              
525             You can also specify parameters when depending on a parameterized service:
526              
527             service foo => (
528             dependencies => [
529             { bar => { bar_param => 1 } },
530             'baz',
531             ],
532             # ...
533             );
534              
535             Finally, services themselves can also be specified as dependencies, in which
536             case they will just be resolved directly:
537              
538             service foo => (
539             dependencies => {
540             dsn => Bread::Board::Literal->new(
541             name => 'dsn',
542             value => 'dbi:mysql:mydb',
543             ),
544             },
545             # ...
546             );
547              
548             As a special case, an arrayref of dependencies will be interpreted as a service
549             which returns an arrayref containing the resolved values of those dependencies:
550              
551             service foo => (
552             dependencies => {
553             # items will resolve to [ $bar_service->get, $baz_service->get ]
554             items => [
555             'bar',
556             Bread::Board::Literal->new(name => 'baz', value => 'BAZ'),
557             ],
558             },
559             # ...
560             );
561              
562             =head3 inheriting and extending services
563              
564             If the C<$name> starts with a C<'+'>, the service definition will instead
565             extend an existing service with the given C<$name> (without the C<'+'>). This
566             works similarly to the C<has '+foo'> syntax in Moose. It is most useful when
567             defining a container class where the container is built up in C<BUILD> methods,
568             as each class in the inheritance hierarchy can modify services defined in
569             superclasses. The C<dependencies> and C<parameters> options will be merged with
570             the existing values, rather than overridden. Note that literal services can't
571             be extended, because there's nothing to extend. You can still override them
572             entirely by declaring the service name without a leading C<'+'>.
573              
574             =head2 C<literal>
575              
576             literal($value);
577              
578             Creates an anonymous L<Bread::Board::Literal> object with the given value.
579              
580             service 'dbh' => (
581             block => sub {
582             my $s = shift;
583             require DBI;
584             DBI->connect(
585             $s->param('dsn'),
586             $s->param('username'),
587             $s->param('password'),
588             ) || die "Could not connect";
589             },
590             dependencies => {
591             dsn => literal 'dbi:SQLite:somedb',
592             username => literal 'foo',
593             password => literal 'password',
594              
595             },
596             );
597              
598             =head2 C<depends_on>
599              
600             depends_on($service_path);
601              
602             The C<depends_on> function creates a L<Bread::Board::Dependency> object for the
603             named C<$service_path> and returns it.
604              
605             =head2 C<wire_names>
606              
607             wire_names(@service_names);
608              
609             This function is just a shortcut for passing a hash reference of dependencies
610             into the service. It is not typically needed, since Bread::Board can usually
611             understand what you mean - these declarations are all equivalent:
612              
613             service foo => (
614             class => 'Pity::TheFoo',
615             dependencies => {
616             foo => depends_on('foo'),
617             bar => depends_on('bar'),
618             baz => depends_on('baz'),
619             },
620             );
621              
622             service foo => (
623             class => 'Pity::TheFoo',
624             dependencies => wire_names(qw( foo bar baz )),
625             );
626              
627             service foo => (
628             class => 'Pity::TheFoo',
629             dependencies => {
630             foo => 'foo',
631             bar => 'bar',
632             baz => 'baz',
633             },
634             );
635              
636             service foo => (
637             class => 'Pity::TheFoo',
638             dependencies => [ qw(foo bar baz ) ],
639             );
640              
641             =head2 C<typemap>
642              
643             typemap $type, $service;
644             typemap $type, $service_path;
645              
646             This creates a type mapping for the named type. Typically, it is paired with
647             the C<infer> call like so:
648              
649             typemap 'MyApp::Model::UserAccount' => infer;
650              
651             For more details on what type mapping is and how it works, see
652             L<Bread::Board::Manual::Concepts::Typemap>.
653              
654             =head2 C<infer>
655              
656             infer;
657             infer(%hints);
658              
659             This is used with C<typemap> to help create the typemap inference. It can be
660             used with no arguments to do everything automatically. However, in some cases,
661             you may want to pass a service instance as the argument or a hash of service
662             arguments to change how the type map works. For example, if your type needs to
663             be constructed using a setter injection, you can use an inference similar to
664             this:
665              
666             typemap 'MyApp::Model::UserPassword' => infer(
667             service_class => 'Bread::Board::SetterInjection',
668             );
669              
670             For more details on what type mapping is and how it works, see
671             L<Bread::Board::Manual::Concepts::Typemap>.
672              
673             =head2 C<include>
674              
675             include $file;
676              
677             This is a shortcut for loading a Bread::Board configuration from another file.
678              
679             include "filename.pl";
680              
681             The above is pretty much identical to running:
682              
683             do "filename.pl";
684              
685             However, you might find it more readable to use C<include>.
686              
687             =head2 C<alias>
688              
689             alias $service_name, $service_path, %service_description;
690              
691             This helper allows for the creation of L<service
692             aliases|Bread::Board::Service::Alias>, which allows you to define a
693             service in one place and then reuse that service with a different name
694             somewhere else. This is sort of like a symbolic link for
695             services. Aliases will be L<resolved
696             recursively|Bread::Board::Traversable/fetch>, so an alias can alias an
697             alias.
698              
699             For example,
700              
701             service file_logger => (
702             class => 'MyApp::Logger::File',
703             );
704              
705             alias my_logger => 'file_logger';
706              
707             =head1 OTHER FUNCTIONS
708              
709             These are not exported, but might be helpful to you.
710              
711             =head2 C<set_root_container>
712              
713             set_root_container $container;
714              
715             You may use this to set a top-level root container for all container
716             definitions.
717              
718             For example,
719              
720             my $app = container MyApp => as { ... };
721              
722             Bread::Board::set_root_container($app);
723              
724             my $config = container Config => as { ... };
725              
726             Here the C<$config> container would be created as a sub-container of C<$app>.
727              
728             =head1 ACKNOWLEDGEMENTS
729              
730             Thanks to Daisuke Maki for his contributions and for really
731             pushing the development of this module along.
732              
733             Chuck "sprongie" Adams, for testing/using early (pre-release)
734             versions of this module, and some good suggestions for naming
735             it.
736              
737             Matt "mst" Trout, for finally coming up with the best name
738             for this module.
739              
740             Gianni "dakkar" Ceccarelli for writing lots of documentation, and
741             Net-a-Porter.com for paying his salary while he was doing it.
742              
743             =head1 ARTICLES
744              
745             L<Bread::Board is the right tool for this job|http://domm.plix.at/perl/2013_04_bread_board_is_the_right_rool_for_this_job.html>
746             Thomas Klausner showing a use-case for Bread::Board.
747              
748             =head1 SEE ALSO
749              
750             =over 4
751              
752             =item L<Bread::Board::Declare>
753              
754             This provides more powerful syntax for writing Bread::Board container classes.
755              
756             =item L<IOC>
757              
758             Bread::Board is basically my re-write of IOC.
759              
760             =item L<http://en.wikipedia.org/wiki/Breadboard>
761              
762             =back
763              
764             =head1 AUTHOR
765              
766             Stevan Little <stevan@iinteractive.com>
767              
768             =head1 BUGS
769              
770             Please report any bugs or feature requests on the bugtracker website
771             https://github.com/stevan/BreadBoard/issues
772              
773             When submitting a bug or request, please include a test-file or a
774             patch to an existing test-file that illustrates the bug or desired
775             feature.
776              
777             =head1 COPYRIGHT AND LICENSE
778              
779             This software is copyright (c) 2017, 2016, 2015, 2014, 2013, 2011, 2009 by Infinity Interactive.
780              
781             This is free software; you can redistribute it and/or modify it under
782             the same terms as the Perl 5 programming language system itself.
783              
784             =cut