NAME
Beam::Wire - A Dependency Injection Container
VERSION
version 0.009
SYNOPSIS
# wire.yml
dbh:
class: 'DBI'
method: connect
args:
- 'dbi:mysql:dbname'
- {
PrintError: 1
}
# myscript.pl
use Beam::Wire;
my $wire = Beam::Wire->new( file => 'wire.yml' );
my $dbh = $wire->get( 'dbh' );
$wire->set( 'dbh' => DBI->new( 'dbi:pgsql:dbname' ) );
DESCRIPTION
Beam::Wire is a dependency injection (DI) container. A DI (dependency injection) container is a framework/mechanism where dependency creation and instantiation is handled automatically (e.g. creates instances of classes that implement a given dependency interface on request). DI does not require a container, in-fact, DI without a container is possible and simply infers that dependency creation isn't automatically handled for you (i.e. you have to write code to instantiate the dependencies manually).
Dependency injection (DI) at it's core is about creating loosely coupled code by separating construction logic from application logic. This is done by pushing the creation of services (dependencies) to the entry point(s) and writing the application logic so that dependencies are provided for its components. The application logic doesn't know or care how it is supplied with its dependencies; it just requires them and therefore receives them.
OVERVIEW
Beam::Wire loads a configuration file and stores the specified configuration in the config attribute which is used to resolve it's services. This section will give you an overview of how to declare dependencies and services, and shape your configuration file.
WHAT IS A DEPENDENCY?
A dependency is a declaration of a component requirement. In layman's terms, a dependency is a class attribute (or any value required for class construction) which will likely be used to define services.
WHAT IS A SERVICE?
A service is a resolvable interface which may be selected and implemented on behalf of a dependent component, or instantiated and returned per request. In layman's terms, a service is a class configuration which can be used independently or as a dependent of other services.
HOW ARE SERVICES CONFIGURED?
# databases.yml
production_db:
class: 'DBI'
method: connect
args:
- 'dbi:mysql:master'
- { PrintError: 0, RaiseError: 0 }
production_cache:
class: 'CHI'
args:
driver: 'DBI'
dbh: { ref: 'production_db' }
development_db:
class: 'DBI'
method: connect
args:
- 'dbi:mysql:slave'
- { PrintError: 1, RaiseError: 1 }
development_cache:
class: 'CHI'
args:
driver: 'DBI'
dbh: { ref: 'development_db' }
Service Attributes
class
The class to instantiate. The class will be loaded and the method
(below) method called.
method
The class method to call to construct the object. Defaults to new
.
args
The arguments to the method
method. This can be either an array or a hash, like so:
# array
dbh:
class: DBI
method: connect
args:
- 'dbi:mysql:dbname'
# hash
cache:
class: CHI
args:
driver: Memory
max_size: 16MB
Using the array of arguments, you can give arrayrefs or hashrefs:
# arrayref of arrayrefs
names:
class: 'Set::CrossProduct'
args:
-
- [ 'Foo', 'Barkowictz' ]
- [ 'Bar', 'Foosmith' ]
- [ 'Baz', 'Bazleton' ]
# arrayrefs of hashrefs
cache:
class: CHI
args:
- driver: Memory
max_size: 16MB
extends
Inherit and override attributes from another service.
dbh:
class: DBI
method: connect
args:
- 'dbi:mysql:dbname'
dbh_dev:
extends: 'dbh'
args:
- 'dbi:mysql:devdb'
Hash args
will be merged seperately, like so:
activemq:
class: My::ActiveMQ
args:
host: example.com
port: 61312
user: root
password: 12345
activemq_dev:
extends: 'activemq'
args:
host: dev.example.com
activemq_dev
will get the port
, user
, and password
arguments from the base service activemq
.
Inner Containers
Beam::Wire objects can hold other Beam::Wire objects!
inner:
class: Beam::Wire
args:
config:
dbh:
class: DBI
method: connect
args:
- 'dbi:mysql:dbname'
cache:
class: CHI
args:
driver: Memory
max_size: 16MB
Inner containers' contents can be reached from outer containers by separating the names with a slash character:
my $dbh = $wire->get( 'inner/dbh' );
Inner Files
inner:
class: Beam::Wire
args:
file: inner.yml
Inner containers can be created by reading files just like the main container. If the file
attribute is relative, the parent's dir
attribute will be added:
# share/parent.yml
inner:
class: Beam::Wire
args:
file: inner.yml
# share/inner.yml
dbh:
class: DBI
method: connect
args:
- 'dbi:sqlite:data.db'
# myscript.pl
use Beam::Wire;
my $container = Beam::Wire->new(
file => 'share/parent.yml',
);
my $dbh = $container->get( 'inner/dbh' );
If more control is needed, you can set the dir attribute on the parent container. If even more control is needed, you can make a subclass of Beam::Wire.
Service/Configuration References
chi:
class: CHI
args:
driver: 'DBI'
dbh: { ref: 'dbh' }
dbh:
class: DBI
method: connect
args:
- { ref: dsn }
- { ref: usr }
- { ref: pwd }
dsn:
value: "dbi:SQLite:memory:"
usr:
value: "admin"
pwd:
value: "s3cret"
The reuse of service and configuration containers as arguments for other services is encouraged so we have provided a means of referencing those objects within your configuration. A reference is an arugment (a service argument) in the form of a hashref with a ref
key whose value is the name of another service. Optionally, this hashref may contain a path
key whose value is a Data::DPath search string which should return the found data structure from within the referenced service.
It is also possible to use raw-values as services, this is done by configuring a service using a single key/value pair with a value
key whose value contains the raw-value you wish to reuse.
ATTRIBUTES
file
The file attribute contains the file path of the file where Beam::Wire container services are configured (typically a YAML file). The file's contents should form a single hashref. The keys will become the service names.
dir
The dir attribute contains the directory path to use when searching for inner container files. Defaults to the directory which contains the file specified by the file attribute.
config
The config attribute contains a hashref of service configurations. This data is loaded by Config::Any using the file specified by the file attribute.
services
A hashref of services. If you have any services already built, add them here.
METHODS
get
The get method resolves and returns the specified service.
set
The set method configures and stores the specified service.
new
Create a new container.
AUTHORS
Doug Bell <preaction@cpan.org>
Al Newkirk <anewkirk@ana.io>
COPYRIGHT AND LICENSE
This software is copyright (c) 2013 by Doug Bell.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.