xerum

IoC / DI framework for Dart

This is a lightweight, mirrors-bassed, DI framework for any kind of Dart application, with support for both singleton and transient instances, as well as a couple of extra-perks.

Installing xerum

From Pub

dependencies:
  xerum: any

From GitHub (master) - most recent stable builds

dependencies:
  xerum:
    git: git://github.com/UizzUW/xerum.git

From Github (dev) - bleeding edge builds

dependencies:
  xerum:
    git:
      url: git://github.com/UizzUW/xerum.git
      ref: dev

Usage

Basic IoC registering / resolving

// contract
abstract class IFuel {
  int quantity;
  String get type;
}

// concrete
class Gasoline implements IFuel {
  @override
  int quantity = 50;
  
  @override
  String get type => "gasoline";
}

// register and resolve

main() {
    var xerum = new XerumContainer();
    xerum.register(new XerumBinding<IFuel, Gasoline>());
    print(xerum.resolve(IFuel)).type);
}

Transient vs Singleton

Transient

main() {
    var xerum = new XerumContainer();
    xerum.register(new XerumBinding<IFuel, Gasoline>());

    var fuel = xerum.resolve(IFuel);
    print(fuel.quantity); // 50
    fuel.quantity--;

    var fuel = xerum.resolve(IFuel);
    print(fuel.quantity); // different instance so still 50
}

Singleton

main() {
    var xerum = new XerumContainer();
    xerum.register(new XerumBinding<IFuel, Gasoline>(), asSingleton: true);

    var fuel = xerum.resolve(IFuel);
    print(fuel.quantity); // 50
    fuel.quantity--;

    var fuel = xerum.resolve(IFuel);
    print(fuel.quantity); // same instance, so 49
}

Specific constructor injection

Out of the box, xerum will use reflection on your concretes to scan all constructors and see if it can find one to use based on the already-registered services (or throw an exception if it doesn't find any).

While it is not required for the process to work, if you would like to have multiple constructors on your concretes for some reason, you can speed up the registration process by annotating the constructor you would like to be used by xerum with @xerumInject. Keep in mind that this only speeds up the registration process. When you resolve a service, xerum already has a reference (if any) to the required constructor.

// contract
abstract class IEngine {
  void go();
}

// concrete with no specific constructor
class ElectricEngine implements IEngine {
  IFuel _fuel;

  ElectricEngine(this._fuel);

  @override
  void go() {
    print("Hum... just hum I guess.");
  }
}

// concrete with specific constructor
class V8Engine implements IEngine {
  IFuel _fuel;

  @xerumInject
  V8Engine(this._fuel);

  @override
  void go() {
    print("Vroom, here comes dat ${_fuel.type}!!");
  }
}

Multiple containers support

xerum can create as many containers as your RAM can hold. Each individual container has its own dependencies tree and service instances.

main() {
    var xerum1 = new XerumContainer();
    var xerum2 = new XerumContainer();
    xerum1.register(new XerumBinding<IFuel, Gasoline>(), asSingleton: true);
    xerum2.register(new XerumBinding<IFuel, Gasoline>(), asSingleton: true);
    print(identical(xerum1.resolve(IFuel), xerum2.resolve(IFuel))); // false
}

Experimental Replacing registered instances

main() {
  var xerum = new XerumContainer();
  xerum.register(new XerumBinding<IFuel, Gasoline>(), asSingleton: true);
  xerum.register(new XerumBinding<IEngine, V8Engine>());
  xerum.register(new XerumBinding<ICar, GenericCar>());
  xerum.resolve(ICar).drive(); // Vroom, here comes dat gasoline!!
  xerum.register(new XerumBinding<IEngine, ElectricEngine>(), replace: true);
  xerum.resolve(ICar).drive(); // Hum... just hum I guess.
}

Libraries

xerum