Lost Dart

Lost Dart is Inversion of Control Container implementation for Dart.


Project maintained by akserg Hosted on GitHub Pages — Theme by mattgraham

Lost Dart

Lost Dart is lightweight dependency injection framework for Dart client and server applications.

It helps you split your application into a collection of loosely-coupled pieces and then glue them back together in a flexible manner. Its aim is to make wide range of Dart applications easier to:

Set up

Lost Dart is available under the lost_dart pub package. Simply add a dependency to your pubspec.yaml file:

...
dependencies:
  lost_dart: any

Then run pub install and you’ll have everything you need to get started.

The core concepts of Lost Dart by examples

Instantiation

A simple example of using the Lost Dart is that to construct an instance of an object.

import 'package:lost_dart/lost_dart.dart';

// Class Baz
class Baz{
  String name;
  
  Baz([this.name = ""]);
}

void main() {
  // Create container
  Container container = new Container();
  
  // Bind Baz
  container.bind(Baz);
  container.bindAs("baz2");
  
  // Resolve baz by type
  Baz baz = container.get(Baz);
  Baz baz2 = container.getAs("baz");

  assert(baz.name == "");
  assert(baz2.name == "");
}

Constructor injection: Constant arguments

Constant values are set an constructor argument:

import 'package:lost_dart/lost_dart.dart';

// Class Baz
class Baz{
  String name;
  int number = 22;
  
  Baz([this.name = ""]);
}

void main() {
  // Create IoC container
  Container container = new Container();
  // Bind Baz
  container.bind(Baz).addConstructorConstArg("Test");
  container.bindAs("baz2").to(Baz).addConstructorConstArg("Test2");

  // Resolve baz
  Baz baz = container.get(Baz);
  Baz baz2 = container.getAs("baz2");

  // Test result
  assert(baz.name == "Test");
  assert(baz2.name == "Test2");
}

Constructor injection: Dependencies

A tree of dependencies are instantiated and injected using the constructor argument:

import 'package:lost_dart/lost_dart.dart';

// application code
class Baz{
  String name;
  int number = 22;

  Baz([this.name = "99"]);
}

class Bar{
  Baz baz;
  Bar(this.baz);
}


void main() {
  // Create IoC container
  Container container = new Container();

  container.bind(Baz);
  container.bind(Bar).addConstructorTypeArg(Baz);
  container.bindAs("bar2").to(Bar).addConstructorTypeArg(Baz);

  // Resolve bar
  Bar bar = container.get(Bar);
  Bar bar2 = container.getAs("bar2");

  // Test result of bar
  assert(bar != null);
  assert(bar.baz.name == "99");
  assert(bar2 != null);
  assert(bar2.baz.name == "99");
  assert(bar.baz == bar.baz);
}

Property injection: Constant values

Constant values are set in the property:

import 'package:lost_dart/lost_dart.dart';

// application code
class Baz{
  String name;
  int number = 22;

  Baz([this.name = "99"]);
}

void main() {
  // Create IoC container
  Container container = new Container();

  // Bind Baz
  container.bind(Baz).setConstProperty("number", 33);
  container.bindAs("baz2").to(Baz).setConstProperty("number", 44);

  // Resolve baz
  Baz baz = container.get(Baz);
  Baz baz2 = container.getAs("baz2");
  
  // Test result
  assert(baz.number == 33);
  assert(baz2.number == 44);
}

Property injection: Dependencies

A tree of dependencies are instantiated and injected using the property:

import 'package:lost_dart/lost_dart.dart';

// application code
class Baz{
  String name;

  Baz([this.name = "99"]);
}

class Bar{
  Baz baz;

  Bar();
}

void main() {

  // Create IoC container
  Container container = new Container();

  // Bind Bar
  container.bind(Bar).setTypeProperty("baz", Bar);
  container.bindAs("bar2").to(Bar).setTypeProperty("baz", Bar);

  // Bind Baz
  container.bind(Baz);

  // Resolve bar
  Bar bar = container.get(Bar);
  Bar bar2 = container.getAs("bar2");
  
  // Test result
  assert(bar.baz.name == bar2.baz.name);
}

Factory methods

The Factory methods have maximum flexibility to generate any type of injected values

import 'package:lost_dart/lost_dart.dart';

//application code
class Network{
  String uri;
  
  Network(this.uri);
}

class User {
  String name;
}

class Manager{
  Network network;
  User user;

  Manager(this.user);
}

void main() {
  // Create IoC container
  Container container = new Container();

  // Add host
  container.bindAs("host").toFactory((){
    return "http://127.0.0.1";
  });
  
  // Add Network
  container.bind(Network).addConstructorRefArg("host");
  
  // Add User
  container.bind(User).setConstProperty("name", "Admin");
  
  // Add Manager
  container.bind(Manager).toFactory((){
    Manager bar = new Manager(container.get(User));
    bar.network = container.get(Network);
    return bar;
  });
  
  // Resolve Manager
  Manager manager = container.get(Manager);

  // Test result
  assert(manager.network.uri == "http://127.0.0.1");
  assert(manager.user.name == "Admin");
}

Object scopes

Lost Dart supports two scopes: singleton and prototype. The first is used by default and does not need to be explicitly specified in binding.

import 'package:lost_dart/lost_dart.dart';

//application code
class Baz{
}

void main() {
  // Create IoC container
  Container container = new Container();
  
  // Add Baz
  container.bind(Baz).asPrototype();
  
  // Resolve baz - "prototype" scope.
  Baz baz = container.get(Baz);
  Baz baz1 = container.get(Baz);
  // Test prototype result
  assert(baz != baz1);
}

Batch binding

To add an array of types in a Container you can use the bindAll method.

import 'package:lost_dart/lost_dart.dart';

class Baz{
}

class Bar{
}

class Foo{
}

void main() {
  Container container = new Container();

  container.bindAll([
    Baz,
    Bar,
    Foo
  ]);

  Foo foo = container.get(Foo);

  assert(foo != null);
}

Multi injection

Lost Dart allows you to inject multiple objects bound to a particular type or interface. There are Weapon interface, and two implementations, Sword and Dagger. The constructor of Samurai class takes an array of Weapon. The toFactory method of Binder return the list of Weapons to be used in Samurai constructor.

import 'package:lost_dart/lost_dart.dart';

/**
 * Asbtract class Weapon
 */
abstract class Weapon
{
  /**
   * Hit the [target].
   */
  String Hit(String target);
}

/**
 * Sword Weapon
 */
class Sword implements Weapon 
{
  /**
   * Hit the [target].
   */
  String Hit(String target) 
  {
    return "Slice " + target + " in half";
  }
}

/**
 * Dagger Weapon
 */
class Dagger implements Weapon 
{
  /**
   * Hit the [target].
   */
  String Hit(String target) 
  {
    return "Stab " + target + " to death";
  }
}

/**
 * Samurai fully equipped.
 */
class Samurai 
{
  List allWeapons;

  Samurai(List this.allWeapons); 

  /**
   * Just attack the [target].
   */
  void Attack(String target) 
  {
    for (Weapon weapon in this.allWeapons) {
      print(weapon.Hit(target));
    }
  }
}

void main() {
  Container container = new Container();
  
  // Bind Sword
  container.bind(Sword);
  // Bind Sword
  container.bind(Dagger);
  // Bind weapons as list
  container.bindAs("weapons").toFactory(() {
    return [container.get(Sword), container.get(Dagger)];
  });
  
  
  // Bind Samurai with list of weapons
  container.bind(Samurai).addConstructorRefArg("weapons");
  
  
  // Get samurai 
  Samurai samurai = container.get(Samurai);
  // Atack
  samurai.Attack("your enemy");
}