File Coverage

blib/lib/Bread/Board.pm
Criterion Covered Total %
statement 125 125 100.0
branch 60 62 96.7
condition 11 12 91.6
subroutine 27 27 100.0
pod 11 11 100.0
total 234 237 98.7


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