The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
NAME
    Beam::Wire - A Dependency Injection Container

VERSION
    version 1.003

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 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".

    If multiple methods are needed to initialize an object, "method" can be
    an arrayref of hashrefs, like so:

        my_service:
            class: My::Service
            method:
                - method: new
                  args:
                    foo: bar
                - method: set_baz
                  args:
                    - Fizz

    In this example, first we call "My::Service-"new( foo => "bar" );> to
    get our object, then we call "$obj-"set_baz( "Fizz" );> as a further
    initialization step.

    To chain methods together, add "return: chain":

        my_service:
            class: My::Service
            method:
                - method: new
                  args:
                    foo: bar
                - method: set_baz
                  return: chain
                  args:
                    - Fizz
                - method: set_buzz
                  return: chain
                  args:
                    - Bork

    This example is equivalent to the following code:

        my $service = My::Service->new( foo => "bar" )->set_baz( "Fizz" )
                    ->set_buzz( "Bork" );

   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".

   lifecycle
    Control how your service is created. The default value, "singleton",
    will cache the resulting service and return it for every call to
    "get()". The other value, "factory", will create a new instance of the
    service every time:

        today:
            class: DateTime
            method: today
            lifecycle: factory
            args:
                time_zone: US/Chicago
        report_yesterday:
            class: My::Report
            args:
                date: { $ref: today, $method: add, $args: [ "days", "-1" ] }
        report_today:
            class: My::Report
            args:
                date: { $ref: today }

    "DateTime-"add> modifies the object and returns the newly-modified
    object (to allow for method chaining.) Without "lifecycle: factory", the
    "today" service would become yesterday, making it hard to know what
    "report_today" would report on.

    An "eager" value will be created as soon as the container is created. If
    you have an object that registers itself upon instantiation, you can
    make sure your object is created as soon as possible by doing
    "lifecycle: eager".

   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 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.

  config
    The config attribute contains a hashref of service configurations. This
    data is loaded by Config::Any using the file specified by the file.

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

  meta_prefix
    The character that begins a meta-property inside of a service's "args".
    This includes $ref, $path, $method, and etc...

    The default value is '$'. The empty string is allowed.

METHODS
  get( name, [ overrides ] )
    The get method resolves and returns the service named "name".

    "overrides" may be a list of name-value pairs. If specified, get() will
    create an anonymous service that extends the "name" service with the
    given config overrides:

        # test.pl
        use Beam::Wire;
        my $wire = Beam::Wire->new(
            config => {
                foo => {
                    args => {
                        text => 'Hello, World!',
                    },
                },
            },
        );
        my $foo = $wire->get( 'foo', args => { text => 'Hello, Chicago!' } );
        print $foo; # prints "Hello, Chicago!"

    This allows you to create factories out of any service, overriding
    service configuration at run-time.

  set
    The set method configures and stores the specified service.

  get_config
    Get the config with the given name, searching inner containers if
    required

  new
    Create a new container.

EXCEPTIONS
    If there is an error internal to Beam::Wire, an exception will be
    thrown. If there is an error with creating a service or calling a
    method, the exception thrown will be passed- through unaltered.

  Beam::Wire::Exception
    The base exception class

  Beam::Wire::Exception::Service
    An exception with service information inside

  Beam::Wire::Exception::NotFound
    The requested service or configuration was not found.

  Beam::Wire::Exception::InvalidConfig
    The configuration is invalid:

    *   Both "value" and "class" or "extends" are defined. These are
        mutually-exclusive.

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.