{"_id":"@dflowng/di","_rev":"5-f6088f87a98b468d577f2996f6b8f6c0","name":"@dflowng/di","time":{"modified":"2022-06-12T17:03:02.041Z","created":"2016-06-09T11:11:46.367Z","0.1.0":"2016-06-09T11:11:46.367Z","0.1.1":"2016-06-09T12:22:34.647Z"},"maintainers":[{"name":"dflowng","email":"dflowng@gmail.com"}],"dist-tags":{"latest":"0.1.1"},"description":"DI container and service locator for Data Flow eNGine","readme":"# @dflowng/di - DI container and service locator for the Data Flow eNGine\n\nThis package is a part of the *Data Flow eNGine* project.\n\n## Usage\n\n### Getting root container\n\nTo get the root container just import `@dflowng/di` package:\n\n```JavaScript\nconst DI = require('@dflowng/di');\n```\n\nIt also would be useful to call `#configure(Module)` method. This method will look for [`package.json`](https://docs.npmjs.com/files/package.json) of the current module and load all the dependencies (using [`Module#require(id)`](https://nodejs.org/api/modules.html#modules_module_require_id) call):\n\n```JavaScript\nDI.configure(module);\n```\n\nIf any of packages current package depends on will define any services then they will be available after call to `#configure(Module)`. There also is a version of `#configure(Module)` method called `#configureDev(Module)`. This method will load dependencies listed in `\"devDependencies\"` section of `package.json` too:\n\n```JavaScript\nDI.configureDev(module);\n```\n\n### Object lifecycle management\n\nThere is a class (`Referenced`) of objects that have a reference counter. This class is defined in `@dflowng/di` package as there is a dependency loop between DI container and this class.\n\nMethods `Referenced#retain()` and `Referenced#release()` increment and decrement a internal reference counter of the object. When after call of `Referenced#release()` method the reference counter reaches zero (or negative value) the `Referenced#destructor()` method (destructor) is called and if after destructor execution the reference counter remains non-positive number then the object is recognized as not-alive (the property `Referenced#isAlive` tells if object is alive).\n\nMethods `Referenced#referTo(obj)` and `Referenced#noReferTo(obj)` register and destroy a references from the object to another. When a `Referenced#referTo(obj)` method is called with object that is instance of `Referenced` then the reference counter of that object is incremented and reference to that object is saved. When destructor of a object is called all of the references (and probably referred objects) are destroyed.\n\nMethod `Referenced#do(callback)` performs (possibly asynchronous) operation keeping the object alive.\n\n### Creating child containers\n\nChild (local) container of a DI container is a container that (at any moment of time) has defined all services defined in it's parent container. Services defined in child container will override the services defined in it's parent.\n\nThere are two ways to get a child container. The first one is to use `#for(obj)` method of parent container:\n\n```JavaScript\nconst x = {};\nconst di = DI.for(x);\n```\n\nEvery call to `#for(obj)` method will return the same object for the same argument if the argument is a object (even if called on different containers).\n\nIf the object passed as argument to `#for(obj)` is instance of `Referenced` then the child container becomes able to store services that are instances of `Referenced` until the object is destroyed.\n\nThe second way is to use `#withLocal(callback)` method:\n\n```JavaScript\nDI.withLocal(di => {\n    // . . .\n});\n```\n\nThe created container becomes able to store services that are instances of `Referenced` until the (possibly asynchronous) operation represented by callback is completed.\n\n### Defining and resolving dependencies (services)\n\nThere are different methods to access different kinds of services -- variables, classes, functions and arrays. Services of any kind have represented by sequence of one or more string identifiers.\n\n#### Defining and resolving classes\n\nTo access class service `#class(className[, implementationName1[, ...]])` method should be used:\n\n```JavaScript\n// Use #get() method to get a raw class (for inheritance).\n// There also is #getClass(className[, implName1[, ...]])\n// method that is a shorthand for #class(...).get().\nclass A extends DI.class('Referenced').get() {\n    constructor(n) {\n        // . . .\n    }\n    // . . .\n};\n\n// Use this if no instances of the class should be created\n//A[DI.abstract] = true;\n\n// Use #define(clazz) method to register class\nDI.class('A').define(A);\n\n// Method #new(...args) creates new instance and performs\n// dependency injection (if necessarry)\nconst a = DI.class('A').new(42);\n```\n\n#### Defining and resolving functions\n\nTo access function services `#func(functionName[, implementationName1[, ...]])` method should be used:\n\n```JavaScript\n// Use #define(func) to define function:\nDI.func('foo').define(function foo(x) {return x*x;});\n\n// The service accessor function will delegate call to the function if it is defined:\nDI.func('foo')(2); // Will call foo(2)\n\n// Use #get() method to get the function itself:\nDI.func('foo').get() === foo // true\n```\n\n#### Defining and resolving variables\n\nClass and function services may be defined only as [es6-classes](http://www.2ality.com/2015/02/es6-classes-final.html) and functions. To define services that are not functions or classes there are variable services.\n\nMethod `#var(varName[, implName[, ...]])` is used to access variable services:\n```JavaScript\n// Set a variable using #set(value) method:\nDI.var('bar').set('baz');\n\n// Get a variable using #get() method:\nDI.var('bar').get() // 'baz'\n```\n\n#### Defining and resolving arrays\n\nA special case of service is a array of objects items of which may be distributed between multiple containers (the container and chain of it's parents).\n\nMethod `#var(varName[, implName[, ...]])` is used to access variable services:\n\n```JavaScript\n// Define array items in root container:\nDI.array('myArray').add('foo','bar');\n\nDI.withLocal(di => {\n    // Add items in local container:\n    di.array('myArray').add('baz');\n    \n    // Get array from root and from local containers:`\n    di.array('myArray').get() // ['foo', 'bar', 'baz']\n    DI.array('myArray').get() // ['foo', 'bar']\n});\n```\n\n### Dependency injection\n\nDependency injection is implemented [interface-injection](http://martinfowler.com/articles/injection.html#InterfaceInjection)-like way. A class instances of which require dependency injection should implement `#[DI.injector](di[, ...args])` method. That method will be called by method `#new([... args])` of DI container with container the `#new([... args])` method was called on as first argument and arguments passed to the `#new([... args])` method as the following arguments.\n\nIf more than one class in inheritance chain defines `#[DI.injector](di[, ...args])` method then all the methods will be called in the same order as constructors of that classes -- that is not necessarry (and even dangerous) to call `#[DI.injector](di[, ...args])` of superclass explicitly.\n\nHere is an example of dependency injection:\n\n```JavaScript\nclass A {\n    [DI.injector](di) {\n        this._n = di.var('n').get();\n    }\n    \n    get n() {\n        return this._n;\n    }\n}\n\nA[DI.abstract] = true;\n\nDI.class('A').define(A);\n\nclass A1 extends DI.getClass('A') {\n    [DI.injector](di) {\n        // [DI.injector] of A is already executed so it's safe to access #n\n        this._m = this.n * 2;\n    }\n    \n    get m() {\n        return this._m;\n    }\n}\n\nDI.class('A', '1').define(A1);\n\nDI.withLocal(di => {\n    // Will cause error - class A is abstract\n    // di.class('A').new()\n    \n    // Define cariable in local container\n    di.var('n').define(42);\n    // Create instance of A1 injecting services from local container (di)\n    const a = di.class('A', '1').new();\n    \n    a.m; // 84\n});\n```\n","versions":{"0.1.1":{"name":"@dflowng/di","version":"0.1.1","main":"lib/di","license":"MIT","repository":{"type":"git","url":"git+https://bitbucket.org/dflowng/di.git"},"description":"DI container and service locator for Data Flow eNGine","author":{"name":"Alexey Bondarenko","email":"alexey.bond.94.55@gmail.com"},"engines":{"node":"~5.7.0"},"publishConfig":{"access":"public"},"devDependencies":{"mocha":"^2.4.5","sinon":"^1.17.3"},"gitHead":"a883bce9ea97886b484e98a9a55a7074a407864b","homepage":"https://bitbucket.org/dflowng/di#readme","_id":"@dflowng/di@0.1.1","scripts":{},"_shasum":"8d249057bb37142367b1b0162b2efa420bceb5e6","_from":".","_npmVersion":"3.6.0","_nodeVersion":"5.7.0","_npmUser":{"name":"dflowng","email":"dflowng@gmail.com"},"dist":{"shasum":"8d249057bb37142367b1b0162b2efa420bceb5e6","tarball":"https://registry.npmjs.org/@dflowng/di/-/di-0.1.1.tgz","integrity":"sha512-HEJGIxBq3UAbnsIj79eUfruOqVo8dMrBxB2dar2zV5P/4RYp1blv2HSR03Az+f/Kn8OI6hQSdHdT06zHmr1fCQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBgdrzVKewgM/p0qGVBOYLpzRhUDyzQXlt71k1/whYO6AiEA5ZVhqnknvK8iGPVyeVkS9FXCZfCqJwH3ETGxTHd3QxE="}]},"maintainers":[{"name":"dflowng","email":"dflowng@gmail.com"}],"_npmOperationalInternal":{"host":"packages-16-east.internal.npmjs.com","tmp":"tmp/di-0.1.1.tgz_1465474952648_0.6121574963908643"}}},"homepage":"https://bitbucket.org/dflowng/di#readme","repository":{"type":"git","url":"git+https://bitbucket.org/dflowng/di.git"},"author":{"name":"Alexey Bondarenko","email":"alexey.bond.94.55@gmail.com"},"license":"MIT","readmeFilename":"README.md"}