The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Beam::Wire - A Dependency Injection Container

SYNOPSIS

    # wire.yml
    dbh:
        class: 'DBI'
        method: connect
        args:
            - 'dbi:mysql:dbname'
            - {
                PrintError: 1
              }
    cache:
        class: 'CHI'
        args:
            driver: 'DBI'
            dbh: { ref: 'dbh' }

    # myscript.pl
    use Beam::Wire;
    my $wire  = Beam::Wire->new( file => 'wire.yml' );
    my $dbh   = $wire->get( 'dbh' );
    my $cache = $wire->get( 'cache' );

    $wire->set( 'dbh', DBI->new( 'dbi:pgsql:dbname' ) );

DESCRIPTION

Beam::Wire is a dependency injection container.

TODO: Explain what a DI container does and why you want it

ATTRIBUTES

file

Read the list of services from the given file. The file is described below in the FILE section.

dir

A directory to use when searching for inner container files. Defaults to the directory that contains the file.

config

A hashref of service configurations. This is normally filled in by reading the FILE.

services

A hashref of services. If you have any services already built, add them here.

METHODS

new

Create a new container.

FILE

Beam::Wire can read a YAML file to fill a container with services. The file should be a single hashref. The keys will be the service names.

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' ]

    # hashref
    cache:
        class: CHI
        args:
            -   driver: Memory
                max_size: 16MB

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.