• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

lib/Bread/H28-Jun-2019-5,7412,524

t/H28-Jun-2019-5,7764,275

xt/release/H28-Jun-2019-1510

CODE_OF_CONDUCT.mdH A D28-Jun-20193.2 KiB7555

CONTRIBUTORSH A D28-Jun-2019747 3630

ChangesH A D28-Jun-201912.9 KiB305257

INSTALLH A D28-Jun-2019946 4424

LICENSEH A D28-Jun-201918.1 KiB380292

MANIFESTH A D28-Jun-20193.1 KiB118117

META.jsonH A D28-Jun-20196.6 KiB210208

META.ymlH A D28-Jun-20194.6 KiB149148

Makefile.PLH A D28-Jun-20192.1 KiB9079

README.mkdnH A D28-Jun-201915.3 KiB569432

SIGNATUREH A D28-Jun-20199 KiB139132

cpanfileH A D28-Jun-20191 KiB4136

doap.xmlH A D28-Jun-201913.3 KiB395394

README.mkdn

1# NAME
2
3Bread::Board - A solderless way to wire up your application components
4
5# VERSION
6
7version 0.37
8
9# SYNOPSIS
10
11```perl
12use Bread::Board;
13
14my $c = container 'MyApp' => as {
15
16    service 'log_file_name' => "logfile.log";
17
18    service 'logger' => (
19        class        => 'FileLogger',
20        lifecycle    => 'Singleton',
21        dependencies => [ 'log_file_name' ],
22    );
23
24    container 'Database' => as {
25        service 'dsn'      => "dbi:SQLite:dbname=my-app.db";
26        service 'username' => "user234";
27        service 'password' => "****";
28
29        service 'dbh' => (
30            block => sub {
31                my $s = shift;
32                require DBI;
33                DBI->connect(
34                    $s->param('dsn'),
35                    $s->param('username'),
36                    $s->param('password'),
37                ) || die "Could not connect";
38            },
39            dependencies => [ 'dsn', 'username', 'password' ]
40        );
41    };
42
43    service 'application' => (
44        class        => 'MyApplication',
45        dependencies => {
46            logger => 'logger',
47            dbh    => 'Database/dbh',
48        }
49    );
50
51};
52
53no Bread::Board; # removes keywords
54
55# get an instance of MyApplication
56# from the container
57my $app = $c->resolve( service => 'application' );
58
59# now user your MyApplication
60# as you normally would ...
61$app->run;
62```
63
64# DESCRIPTION
65
66Bread::Board is an inversion of control framework with a focus on
67dependency injection and lifecycle management. It's goal is to
68help you write more decoupled objects and components by removing
69the need for you to manually wire those objects/components together.
70
71Want to know more? See the [Bread::Board::Manual](https://metacpan.org/pod/Bread::Board::Manual).
72
73```
74+-----------------------------------------+
75|          A B C D E   F G H I J          |
76|-----------------------------------------|
77| o o |  1 o-o-o-o-o v o-o-o-o-o 1  | o o |
78| o o |  2 o-o-o-o-o   o-o-o-o-o 2  | o o |
79| o o |  3 o-o-o-o-o   o-o-o-o-o 3  | o o |
80| o o |  4 o-o-o-o-o   o-o-o-o-o 4  | o o |
81| o o |  5 o-o-o-o-o   o-o-o-o-o 5  | o o |
82|     |  6 o-o-o-o-o   o-o-o-o-o 6  |     |
83| o o |  7 o-o-o-o-o   o-o-o-o-o 7  | o o |
84| o o |  8 o-o-o-o-o   o-o-o-o-o 8  | o o |
85| o o |  9 o-o-o-o-o   o-o-o-o-o 9  | o o |
86| o o | 10 o-o-o-o-o   o-o-o-o-o 10 | o o |
87| o o | 11 o-o-o-o-o   o-o-o-o-o 11 | o o |
88|     | 12 o-o-o-o-o   o-o-o-o-o 12 |     |
89| o o | 13 o-o-o-o-o   o-o-o-o-o 13 | o o |
90| o o | 14 o-o-o-o-o   o-o-o-o-o 14 | o o |
91| o o | 15 o-o-o-o-o   o-o-o-o-o 15 | o o |
92| o o | 16 o-o-o-o-o   o-o-o-o-o 16 | o o |
93| o o | 17 o-o-o-o-o   o-o-o-o-o 17 | o o |
94|     | 18 o-o-o-o-o   o-o-o-o-o 18 |     |
95| o o | 19 o-o-o-o-o   o-o-o-o-o 19 | o o |
96| o o | 20 o-o-o-o-o   o-o-o-o-o 20 | o o |
97| o o | 21 o-o-o-o-o   o-o-o-o-o 21 | o o |
98| o o | 22 o-o-o-o-o   o-o-o-o-o 22 | o o |
99| o o | 22 o-o-o-o-o   o-o-o-o-o 22 | o o |
100|     | 23 o-o-o-o-o   o-o-o-o-o 23 |     |
101| o o | 24 o-o-o-o-o   o-o-o-o-o 24 | o o |
102| o o | 25 o-o-o-o-o   o-o-o-o-o 25 | o o |
103| o o | 26 o-o-o-o-o   o-o-o-o-o 26 | o o |
104| o o | 27 o-o-o-o-o   o-o-o-o-o 27 | o o |
105| o o | 28 o-o-o-o-o ^ o-o-o-o-o 28 | o o |
106+-----------------------------------------+
107```
108
109Loading this package will automatically load the rest of the packages needed by
110your Bread::Board configuration.
111
112# EXPORTED FUNCTIONS
113
114The functions of this package provide syntactic sugar to help you build your
115Bread::Board configuration. You can build such a configuration by constructing
116the objects manually instead, but your code may be more difficult to
117understand.
118
119## `container`
120
121### simple case
122
123```
124container $name, \&body;
125```
126
127This function constructs and returns an instance of [Bread::Board::Container](https://metacpan.org/pod/Bread::Board::Container).
128The (optional) `&body` block may be used to add services or sub-containers
129within the newly constructed container. Usually, the block is not passed
130directly, but passed using the `as` function.
131
132For example,
133
134```perl
135container 'MyWebApp' => as {
136    service my_dispatcher => (
137        class => 'MyWebApp::Dispatcher',
138    );
139};
140```
141
142If `$name` starts with `'+'`, and the container is being declared inside
143another container, then this declaration will instead extend an existing
144container with the name `$name` (without the `'+'`).
145
146### from an instance
147
148```
149container $container_instance, \&body
150```
151
152In many cases, subclassing [Bread::Board::Container](https://metacpan.org/pod/Bread::Board::Container) is the easiest route to
153getting access to this framework. You can do this and still get all the
154benefits of the syntactic sugar for configuring that class by passing an
155instance of your container subclass to `container`.
156
157You could, for example, configure your container inside the `BUILD` method of
158your class:
159
160```perl
161package MyWebApp;
162use Moose;
163
164extends 'Bread::Board::Container';
165
166sub BUILD {
167    my $self = shift;
168
169    container $self => as {
170        service dbh => ( ... );
171    };
172}
173```
174
175### with parameters
176
177```
178container $name, \@parameters, \&body
179```
180
181A third way of using the `container` function is to build a parameterized
182container. These are useful as a way of providing a placeholder for parts of
183the configuration that may be provided later. You may not use an instance
184object in place of the `$name` in this case.
185
186For more detail on how you might use parameterized containers, see
187["Parameterized Containers" in Bread::Board::Manual::Concepts::Advanced](https://metacpan.org/pod/Bread::Board::Manual::Concepts::Advanced#Parameterized-Containers).
188
189## `as`
190
191```
192as { some_code() };
193```
194
195This is just a replacement for the `sub` keyword that is easier to read when
196defining containers.
197
198## `service`
199
200```
201service $name, $literal;
202service $name, %service_description;
203```
204
205Within the `as` blocks for your containers, you may construct services using
206the `service` function. This can construct several different kinds of services
207based upon how it is called.
208
209### literal services
210
211To build a literal service (a [Bread::Board::Literal](https://metacpan.org/pod/Bread::Board::Literal) object), just specify a
212scalar value or reference you want to use as the literal value:
213
214```perl
215# In case you need to adjust the gravitational constant of the Universe
216service gravitational_constant => 6.673E-11;
217```
218
219### using injections
220
221To build a service using one of the injection services, just fill in all the
222details required to use that sort of injection:
223
224```perl
225service search_service => (
226    class => 'MyApp::Search',
227    block => sub {
228        my $s = shift;
229        MyApp::Search->new($s->param('url'), $s->param('type'));
230    },
231    dependencies => {
232        url => 'search_url',
233    },
234    parameters => {
235        type => { isa => 'Str', default => 'text' },
236    },
237);
238```
239
240The type of injection performed depends on the parameters used. You may use
241the `service_class` parameter to pick a specific injector class. For
242instance, this is useful if you need to use [Bread::Board::SetterInjection](https://metacpan.org/pod/Bread::Board::SetterInjection)
243or have defined a custom injection service.  If you specify a `block`, block
244injection will be performed using [Bread::Board::BlockInjection](https://metacpan.org/pod/Bread::Board::BlockInjection). If neither
245of these is present, constructor injection will be used with
246[Bread::Board::ConstructorInjection](https://metacpan.org/pod/Bread::Board::ConstructorInjection) (and you must provide the `class`
247option).
248
249### service dependencies
250
251The `dependencies` parameter takes a hashref of dependency names mapped to
252[Bread::Board::Dependency](https://metacpan.org/pod/Bread::Board::Dependency) objects, but there are several coercions and sugar
253functions available to make specifying dependencies as easy as possible. The
254simplest case is when the names of the services you're depending on are the
255same as the names that the service you're defining will be accessing them with.
256In this case, you can just specify an arrayref of service names:
257
258```perl
259service foo => (
260    dependencies => [ 'bar', 'baz' ],
261    # ...
262);
263```
264
265If you need to use a different name, you can specify the dependencies as a
266hashref instead:
267
268```perl
269service foo => (
270    dependencies => {
271        dbh => 'foo_dbh',
272    },
273    # ...
274);
275```
276
277You can also specify parameters when depending on a parameterized service:
278
279```perl
280service foo => (
281    dependencies => [
282        { bar => { bar_param => 1 } },
283        'baz',
284    ],
285    # ...
286);
287```
288
289Finally, services themselves can also be specified as dependencies, in which
290case they will just be resolved directly:
291
292```perl
293service foo => (
294    dependencies => {
295        dsn => Bread::Board::Literal->new(
296            name  => 'dsn',
297            value => 'dbi:mysql:mydb',
298        ),
299    },
300    # ...
301);
302```
303
304As a special case, an arrayref of dependencies will be interpreted as a service
305which returns an arrayref containing the resolved values of those dependencies:
306
307```perl
308service foo => (
309    dependencies => {
310        # items will resolve to [ $bar_service->get, $baz_service->get ]
311        items => [
312            'bar',
313            Bread::Board::Literal->new(name => 'baz', value => 'BAZ'),
314        ],
315    },
316    # ...
317);
318```
319
320### inheriting and extending services
321
322If the `$name` starts with a `'+'`, the service definition will instead
323extend an existing service with the given `$name` (without the `'+'`). This
324works similarly to the `has '+foo'` syntax in Moose. It is most useful when
325defining a container class where the container is built up in `BUILD` methods,
326as each class in the inheritance hierarchy can modify services defined in
327superclasses. The `dependencies` and `parameters` options will be merged with
328the existing values, rather than overridden. Note that literal services can't
329be extended, because there's nothing to extend. You can still override them
330entirely by declaring the service name without a leading `'+'`.
331
332## `literal`
333
334```
335literal($value);
336```
337
338Creates an anonymous [Bread::Board::Literal](https://metacpan.org/pod/Bread::Board::Literal) object with the given value.
339
340```perl
341      service 'dbh' => (
342          block => sub {
343              my $s = shift;
344              require DBI;
345              DBI->connect(
346                  $s->param('dsn'),
347                  $s->param('username'),
348                  $s->param('password'),
349              ) || die "Could not connect";
350          },
351          dependencies => {
352            dsn      => literal 'dbi:SQLite:somedb',
353            username => literal 'foo',
354            password => literal 'password',
355
356          },
357      );
358```
359
360## `depends_on`
361
362```
363depends_on($service_path);
364```
365
366The `depends_on` function creates a [Bread::Board::Dependency](https://metacpan.org/pod/Bread::Board::Dependency) object for the
367named `$service_path` and returns it.
368
369## `wire_names`
370
371```
372wire_names(@service_names);
373```
374
375This function is just a shortcut for passing a hash reference of dependencies
376into the service. It is not typically needed, since Bread::Board can usually
377understand what you mean - these declarations are all equivalent:
378
379```perl
380service foo => (
381    class => 'Pity::TheFoo',
382    dependencies => {
383        foo => depends_on('foo'),
384        bar => depends_on('bar'),
385        baz => depends_on('baz'),
386    },
387);
388
389service foo => (
390    class => 'Pity::TheFoo',
391    dependencies => wire_names(qw( foo bar baz )),
392);
393
394service foo => (
395    class => 'Pity::TheFoo',
396    dependencies => {
397        foo => 'foo',
398        bar => 'bar',
399        baz => 'baz',
400    },
401);
402
403service foo => (
404    class => 'Pity::TheFoo',
405    dependencies => [ qw(foo bar baz ) ],
406);
407```
408
409## `typemap`
410
411```
412typemap $type, $service;
413typemap $type, $service_path;
414```
415
416This creates a type mapping for the named type. Typically, it is paired with
417the `infer` call like so:
418
419```perl
420typemap 'MyApp::Model::UserAccount' => infer;
421```
422
423For more details on what type mapping is and how it works, see
424[Bread::Board::Manual::Concepts::Typemap](https://metacpan.org/pod/Bread::Board::Manual::Concepts::Typemap).
425
426## `infer`
427
428```
429infer;
430infer(%hints);
431```
432
433This is used with `typemap` to help create the typemap inference. It can be
434used with no arguments to do everything automatically. However, in some cases,
435you may want to pass a service instance as the argument or a hash of service
436arguments to change how the type map works. For example, if your type needs to
437be constructed using a setter injection, you can use an inference similar to
438this:
439
440```perl
441typemap 'MyApp::Model::UserPassword' => infer(
442    service_class => 'Bread::Board::SetterInjection',
443);
444```
445
446For more details on what type mapping is and how it works, see
447[Bread::Board::Manual::Concepts::Typemap](https://metacpan.org/pod/Bread::Board::Manual::Concepts::Typemap).
448
449## `include`
450
451```
452include $file;
453```
454
455This is a shortcut for loading a Bread::Board configuration from another file.
456
457```
458include "filename.pl";
459```
460
461The above is pretty much identical to running:
462
463```
464do "filename.pl";
465```
466
467However, you might find it more readable to use `include`.
468
469## `alias`
470
471```
472alias $service_name, $service_path, %service_description;
473```
474
475This helper allows for the creation of [service
476aliases](https://metacpan.org/pod/Bread::Board::Service::Alias), which allows you to define a
477service in one place and then reuse that service with a different name
478somewhere else. This is sort of like a symbolic link for
479services. Aliases will be [resolved
480recursively](https://metacpan.org/pod/Bread::Board::Traversable#fetch), so an alias can alias an
481alias.
482
483For example,
484
485```perl
486service file_logger => (
487    class => 'MyApp::Logger::File',
488);
489
490alias my_logger => 'file_logger';
491```
492
493# OTHER FUNCTIONS
494
495These are not exported, but might be helpful to you.
496
497## `set_root_container`
498
499```
500set_root_container $container;
501```
502
503You may use this to set a top-level root container for all container
504definitions.
505
506For example,
507
508```perl
509my $app = container MyApp => as { ... };
510
511Bread::Board::set_root_container($app);
512
513my $config = container Config => as { ... };
514```
515
516Here the `$config` container would be created as a sub-container of `$app`.
517
518# ACKNOWLEDGEMENTS
519
520Thanks to Daisuke Maki for his contributions and for really
521pushing the development of this module along.
522
523Chuck "sprongie" Adams, for testing/using early (pre-release)
524versions of this module, and some good suggestions for naming
525it.
526
527Matt "mst" Trout, for finally coming up with the best name
528for this module.
529
530Gianni "dakkar" Ceccarelli for writing lots of documentation, and
531Net-a-Porter.com for paying his salary while he was doing it.
532
533# ARTICLES
534
535[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)
536Thomas Klausner showing a use-case for Bread::Board.
537
538# SEE ALSO
539
540- [Bread::Board::Declare](https://metacpan.org/pod/Bread::Board::Declare)
541
542    This provides more powerful syntax for writing Bread::Board container classes.
543
544- [IOC](https://metacpan.org/pod/IOC)
545
546    Bread::Board is basically my re-write of IOC.
547
548- [http://en.wikipedia.org/wiki/Breadboard](http://en.wikipedia.org/wiki/Breadboard)
549
550# AUTHOR
551
552Stevan Little <stevan@iinteractive.com>
553
554# BUGS
555
556Please report any bugs or feature requests on the bugtracker website
557https://github.com/stevan/BreadBoard/issues
558
559When submitting a bug or request, please include a test-file or a
560patch to an existing test-file that illustrates the bug or desired
561feature.
562
563# COPYRIGHT AND LICENSE
564
565This software is copyright (c) 2019, 2017, 2016, 2015, 2014, 2013, 2011, 2009 by Infinity Interactive.
566
567This is free software; you can redistribute it and/or modify it under
568the same terms as the Perl 5 programming language system itself.
569