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

Evo::Di - Dependency injection

VERSION

version 0.0252

SYNOPSYS

  use Evo -Di;

  {

    package My::C1;
    use Evo -Class, -Loaded;
    has c2 => inject 'My::C2';

    # dot notation
    has host => inject '.ip';
    has port => inject '.port';

    package My::C2;
    use Evo -Class, -Loaded;
    has c3 => inject 'My::C3';

    package My::C3;
    use Evo -Class, -Loaded;
    has foo => inject 'FOO';

  }

  my $di = Evo::Di->new();

  # provide some value in stash wich will be available as dependency 'FOO'
  $di->provide(FOO => 'FOO value');

  # provide config using dot notation
  $di->provide('My::C1.' => {ip => '127.0.0.1', port => '3000'});

  my $c1 = $di->single('My::C1');
  say $c1 == $di->single('My::C1');
  say $c1 == $di->single('My::C1');
  say $c1->c2->c3 == $di->single('My::C3');
  say $c1->c2->c3->foo;    # FOO value

  say $c1->host;           # 127.0.0.1
  say $c1->port;           # 3000

INJECTION

Injection is a value of inject option in Evo::Class. Use it this way

If you need to describe a dependency of some class, write this class

  has dep => inject 'My::Class';

This class will be build, resolved and injected

If you need to provide a global value, for example, processor cores, you can use UPPER_CASE constants. You need to provide a value for this dependency

  has cores => inject 'CORES';
  $di->provide(CORES => 8);

If you need to provide some constant for class, use it this way

  has limit => inject => 'My::Class/LIMIT';
  $di->provide(My::Class/LIMIT => 8);

For convineince, there is a special "dot notation". inject field should start with dot and dependency in format "Class::Name."(dot at the and) should be a hash reference, containing keys

  has ip => inject '.ip';
  $di->provide('My::C1.' => {ip => '127.0.0.1', port => '3000'});

Usefull for configuration

ATTRIBUTES

di_stash

A hash reference containing our dependencies (single instances)

METHODS

provide($self, $key, $v)

You can put in stash any value as a dependency

  $di->provide('SOME_CONSTANT' => 33);
  say $di->single('SOME_CONSTANT'), 33;

  $di->provide('My::C1.' => {ip => '127.0.0.1', port => '3000'});

single($self, $key)

If there is already a dependency with this key, return it. If not, build it, resolving a dependencies tree. Has a protection from circular dependencies (die if A->B->C->A)

Resolving dependencies tree

Building a class means resolving a dependencies tree. Dependency is a value of inject option if a $key is a Evo::Class

This module will try to load every dependency from the stash which are not dot notations, if it's missing, consider it as a class name, load it and to build it with new method and resolving it's dependency, if it's a Evo::Class too.

If the dependency can't be resolved (no value in stash, package is missing), there are 2 possible situations:

If dependency is dot notation, module will check if it's provided and die, if it's missing and attribute is required.

optional dependency

If an attribute is "optional" in Evo::Class, such attribute will be ignored.

required dependency

If an attribute isrequired, die.

AUTHOR

alexbyk.com

COPYRIGHT AND LICENSE

This software is copyright (c) 2016 by alexbyk.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.