Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/simplify injector #69

Merged
merged 3 commits into from
Aug 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jetli",
"version": "4.0.1",
"version": "4.0.2",
"description": "Simple, lightweight dependency injector - supports factories, classes and primitives.",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
Expand Down
80 changes: 48 additions & 32 deletions src/classes/jetli/jetli.class.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,7 @@ const invalidDependencyIdentificators = {
// tslint:disable-next-line
'number': 123,
// tslint:disable-next-line
'array': [],
// tslint:disable-next-line
'arrow function': () => {
}
'array': []
};

describe('Jetli class', () => {
Expand Down Expand Up @@ -375,11 +372,13 @@ describe('Jetli class', () => {
await jetli.set(typeName, dependency);
jetli.unset(typeName);

let expectedError;
try {
await jetli.get(typeName);
} catch (error) {
expect(error).toBeTruthy();
expectedError = error;
}
expect(expectedError).toBeInstanceOf(Error);
});
});
});
Expand All @@ -389,11 +388,29 @@ describe('Jetli class', () => {
await jetli.get(dependency);
jetli.unset(dependency);

let expectedError;
try {
await jetli.get(typeName);
await jetli.get(dependency.name);
} catch (error) {
expect(error).toBeTruthy();
expectedError = error;
}
expect(expectedError).toBeInstanceOf(Error);
});
});
});

describe('should not raise error when wrong key provided for unset method', () => {
Object.keys(primitiveTypes).forEach((typeName) => {
it(`for ${typeName}`, async () => {
const dependency = primitiveTypes[typeName];

let expectedError;
try {
jetli.unset(dependency);
} catch (error) {
expectedError = error;
}
expect(expectedError).not.toBeInstanceOf(Error);
});
});
});
Expand All @@ -408,15 +425,19 @@ describe('Jetli class', () => {
public initialised = false;

public init = jest.fn(() => {
return Promise.reject('error');
throw new Error('error');
});
}

await jetli.set('some-id', ServiceA);

let expectedError;
try {
await jetli.set('some-id', ServiceA, false);
await jetli.get('some-id');
} catch (error) {
expect(error).toBeTruthy();
expectedError = error;
}
expect(expectedError).toBeInstanceOf(Error);
});

it('for get method', async () => {
Expand All @@ -425,15 +446,17 @@ describe('Jetli class', () => {
public initialised = false;

public init = jest.fn(() => {
return Promise.reject('error');
throw new Error('error');
});
}

let expectedError;
try {
const serviceA = await jetli.get(ServiceA);
} catch (error) {
expect(error).toBeTruthy();
expectedError = error;
}
expect(expectedError).toBeInstanceOf(Error);
});

});
Expand All @@ -447,11 +470,13 @@ describe('Jetli class', () => {
await jetli.set(typeName, dependency);
jetli.unset(typeName);

let expectedError;
try {
await jetli.get(typeName);
} catch (error) {
expect(error).toBeTruthy();
expectedError = error;
}
expect(expectedError).toBeInstanceOf(Error);
});
});
});
Expand All @@ -462,11 +487,13 @@ describe('Jetli class', () => {
await jetli.get(dependency);
jetli.unset(dependency);

let expectedError;
try {
await jetli.get(typeName);
await jetli.get(dependency.name);
} catch (error) {
expect(error).toBeTruthy();
expectedError = error;
}
expect(expectedError).toBeInstanceOf(Error);
});
});
});
Expand All @@ -475,8 +502,6 @@ describe('Jetli class', () => {
describe(`for string key`, () => {
Object.keys(constructorTypes).forEach((typeName) => {
it(`for ${typeName}`, async () => {
const dependency = constructorTypes[typeName];

try {
await jetli.get(typeName);
} catch (error) {
Expand All @@ -485,31 +510,20 @@ describe('Jetli class', () => {
});
});
});
describe(`for constructor key`, () => {
Object.keys(constructorTypes).forEach((typeName) => {
it(`for ${typeName}`, async () => {
const dependency = constructorTypes[typeName];

try {
await jetli.get(dependency);
} catch (error) {
expect(error).toBeTruthy();
}
});
});
});
});

describe('should throw error for requesting unregistered dependency via set method', () => {
Object.keys(undefinedDependencies).forEach((typeName) => {
it(`for ${typeName} dependency`, async () => {
const dependency = constructorTypes[typeName];

let expectedError;
try {
await jetli.set('someType', dependency);
} catch (error) {
expect(error).toBeTruthy();
expectedError = error;
}
expect(expectedError).toBeInstanceOf(Error);
});
});
});
Expand All @@ -519,11 +533,13 @@ describe('Jetli class', () => {
it(`for ${typeName} dependency`, async () => {
const identificator = invalidDependencyIdentificators[typeName];

let expectedError;
try {
await jetli.get(identificator);
} catch (error) {
expect(error).toBeTruthy();
expectedError = error;
}
expect(expectedError).toBeInstanceOf(Error);
});
});
});
Expand Down
12 changes: 10 additions & 2 deletions src/classes/jetli/jetli.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,19 @@ export class Jetli implements IJetli {

/**
* Unregister dependency (also primitive values) by key
* @param {string} key
* @param {IDependency | string} dependency
*/
public unset<T = any>(
key: string
dependency: IDependency | string
): void {

let key;
try{
key = this.getKey(dependency);
} catch (error) {
return;
}

delete this.dependencies[key];
delete this.initialisedDependencies[key];
}
Expand Down
14 changes: 7 additions & 7 deletions src/docs/readme.body.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Jetli allows you to inject consistently classes, functions and primitives across

Injecting instances of classes is trivial with jetli - just use 'get' method without any additional options.

<pre class="runkit-source">const jetli = require('jetli@4.0.1').jetli;
<pre class="runkit-source">const jetli = require('jetli@4.0.2').jetli;

class Attack {
constructor(){
Expand All @@ -60,7 +60,7 @@ Functions, already instantiated objects or primitive values like array, string a

Registration is provided via 'set' method and requires you to provide string token that identifies the injectable element.

<pre class="runkit-source">const jetli = require('jetli@4.0.1').jetli;
<pre class="runkit-source">const jetli = require('jetli@4.0.2').jetli;

class Attack {
constructor(){
Expand All @@ -83,7 +83,7 @@ fighter2.punch();</pre>

As explained in previous example primitives can be easily used across your applications with associated string id provided during registration.

<pre class="runkit-source">const jetli = require('jetli@4.0.1').jetli;
<pre class="runkit-source">const jetli = require('jetli@4.0.2').jetli;

const someNumber = 123;
const someString = 'punch';
Expand All @@ -108,7 +108,7 @@ To use Jetli to full extend implement services that expose init method. This met

If you already initialised injectable and dont want jetli to call "init" make sure to set "initialise" property to true;

<pre class="runkit-source">const jetli = require('jetli@4.0.1').jetli;
<pre class="runkit-source">const jetli = require('jetli@4.0.2').jetli;

await jetli.set('someNumber', 123);

Expand Down Expand Up @@ -138,7 +138,7 @@ fighter2.punch();</pre>

### Pass arguments to services constructor

<pre class="runkit-source">const jetli = require('jetli@4.0.1').jetli;
<pre class="runkit-source">const jetli = require('jetli@4.0.2').jetli;

class Attack {
constructor(id){
Expand All @@ -162,7 +162,7 @@ fighter2.punch();</pre>

Jetli uses battle-tested method to fight 'cyclic dependencies' - optional initialisation callback. Injector searches for optional "init" method to call it and as an argument to provide instance of injector itself. This method provide safe moment to inject all dependencies required by service - you can be sure that all dependencies will be already initialised.

<pre class="runkit-source">const jetli = require('jetli@4.0.1').jetli;
<pre class="runkit-source">const jetli = require('jetli@4.0.2').jetli;

class ServiceA {
constructor(){
Expand Down Expand Up @@ -214,7 +214,7 @@ console.log(serviceB.getId());</pre>

Its rather trivial to mock module dependencies if you have total control whats injected where, right? With Jetli you can reset any previously registered/injected dependencies and introduce your own mocks / stubs.

<pre class="runkit-source">const jetli = require('jetli@4.0.1').jetli;
<pre class="runkit-source">const jetli = require('jetli@4.0.2').jetli;

class Attack {
constructor(){
Expand Down