2.0.0 • Published 6 years ago

cider-di v2.0.0

Weekly downloads
2
License
MIT
Repository
github
Last release
6 years ago

Build Status

cider

Super simple dependency inversion/injection for javascript.

Installation

npm install --save cider-di

Use

const service = require('./service');
const database = require('./database');
const cider = require('cider-di');
const injector = cider.createInjector({
  service: cider.singleton(
    ({database}) => new service(database)
  ),
  database: cider.singleton(
    () => new database()
  )
});
const my_service = injector.dependencies.service;

Cider uses named bindings to create a map of name to binding function. Each binding function is supplied 3 values.

  • dependencies - an object where each key corresponds to provided value.
  • providers - an object where each key corresponds to a provider.
  • context - a javascript object that can be used for providers to communicate with each other.

Components

cider.createInjector(module)

Returns injector

Takes 0 or more functions which act as module definitions, each module is passed an argument bind which is used to declare dependencies.

cider.singleton(binding)

Returns binding

Given a binding function ensures that the function is only called once for each injector instance that it's used from.

my_service: cider.singleton(
  ({dependency}) => new service(dependency)
)

cider.instance(value)

  • value any

Returns binding

Given a value create a binding that will provide that value.

should_run: cider.instance(false)

cider.alias(name)

  • name string

Returns binding

Given a name creates a binding that provides the value bound to that name. This acts as a way to alias bindings. Note that tags won't be transferred.

database: cider.alias('postgres')

cider.tagged(tags, binding)

Returns binding

Given a set of tags and a binding, returns a binding with the given set of tags appended to the tags on the given binding.

  stripe_processor: cider.tagged(
    ['payment_processor'],
    cider.singleton(
      () => new Stripe()
    )
  )

Module

properties

A module is a standard javascript object with a name mapped to a binding.

module.exports = {
  database: () => new Database(),
  service: cider.singleton(
    ({database}) => new Service(database)
  )
}

Binding(dependencies,providers,context)

properties

  • tags optional string[]

Returns any

A binding is given 3 values that can be used to get dependencies, and retuns the value of the dependency.

 some_binding: ({database},{query}, context) => {
   if (context.should_run_query) {
     return database.execute(query());
   }
   return null;
 }

Dependencies

properties

Map of binding name to value;

Providers

properties

Map of binding name to provider;

Injector

properties

Injectors hold all the dependency mappings.

const db = injector.dependencies.database;

provider()

properties

  • tags string[]

Returns any

A function that when called supplies the value as a result of invoking the corresponding binding. The tags (if any) that were defined by the corresponding binding will be available on the provider

Philosophy

While cider borrowers some terminology from popular Java DI frameworks like Guice it's designed from the ground up to take advantage of javascript features. Primarily this takes the form of using object destructuring in function arguments rather than attempting to provide some form of function annotation.

The dependencies parameter that is passed to a binding uses property getters to lazily resolve the dependency chain. Cider does simple cycle detection whenever a dependency is being resolved, this prevents cases of circular dependencies.

The providers parameter contains the same keys as dependencies however each value is a function. The result of invoking the function is the same as getting the value of a property on dependencies. A Provider should be used whenever possible to lazily initialize a dependency, doing so allows for what would otherwise be unacceptable circular references.