Skip to content

Shehats/easy-injectionJS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

easy-injectionJS

A package that provides dependency injection using common design patterns as stereotypes. It easily injects depedencies in runtime and supports inheritance:

There's no additional dependencies or containers needed to use the package. You can simply use it as follows:

npm i -S easy-injectionjs

Or

yarn add easy-injectionjs

Dependencies without inheritance:

import { Easy, EasyPrototype, EasySingleton } from 'easy-injectionjs';

// Creates a singleton instance of Movie class in runtime
@EasySingleton()
class Movie {
  constructor (private name: string, private ratings: number) {
    // Lets say that they just release the movie :D
    this.name = 'Black Panther';
    this.ratings = 9.0; // I really like that movie
  }

  public getName(): string {
    return this.name;
  }

  public getRatings(): number {
    return this.ratings;
  }

  public setName(v: string) {
    this.name = v;
  }

  public setRatings(v: number) {
    this.ratings = v;
  }
}

// Creates a multiple instances as needed in runtime
@EasyPrototype()
class Actor {
  @Easy()
  private movie: Movie;
  private name: string;

  constructor (name: string) {
    this.name = name;
  }

  public getMovieName(): string {
    return this.movie.getName();
  }

  public setMovieName(v: string) {
    this.movie.setName(v);
  }
}

let T_Challa = new Actor('Chadwick Boseman');
console.log(T_Challa.getMovieName());// Output is Black Panther
T_Challa.setMovieName('Black Panther II'); // Hopefully
console.log(T_Challa.getMovieName()); // Output is Black Panther II
let Erik_Killmonger = new Actor('Michael B Jordan');
console.log(Erik_Killmonger.getMovieName()) // // Output is Black Panther II

If the movie had the annotaion of EasyPrototype instead, Erik_Killmonger.getMovieName() will return Black Panther istead of Black Panther 2.

Interfaces and named dependencies example:

import { Easy, EasyPrototype, EasySingleton } from 'easy-injectionjs';

interface Show {
  getName(): string;
  getRatings(): number;
  setName(v: string);
  setRatings(v: number);
}

// Creates a singleton instance of Movie class in runtime
@EasySingleton('Movie')
class Movie implements Show {
  constructor (private name: string, private ratings: number) {
    // Lets say that they just release the movie :D
    this.name = 'Black Panther';
    this.ratings = 9.0; // I really like that movie
  }

  public getName(): string {
    return this.name;
  }

  public getRatings(): number {
    return this.ratings;
  }

  public setName(v: string) {
    this.name = v;
  }

  public setRatings(v: number) {
    this.ratings = v;
  }
}

// Creates a multiple instances as needed in runtime
@EasyPrototype()
class Actor {
  @Easy('Movie')
  private movie: Show;
  private name: string;

  constructor (name: string) {
    this.name = name;
  }

  public getMovieName(): string {
    return this.movie.getName();
  }

  public setMovieName(v: string) {
    this.movie.setName(v);
  }
}

let T_Challa = new Actor('Chadwick Boseman');
console.log(T_Challa.getMovieName());// Output is Black Panther
T_Challa.setMovieName('Black Panther II'); // Hopefully
console.log(T_Challa.getMovieName()); // Output is Black Panther II
let Erik_Killmonger = new Actor('Michael B Jordan');
console.log(Erik_Killmonger.getMovieName()) // // Output is Black Panther II

The package support inheritance even with abstract classes using the @EasyFactory decorator:

Example:

import { Easy, EasyFactory, EasyPrototype, EasySingleton } from 'easy-injectionjs';

@EasyFactory()
abstract class Show {
  public abstract getName(): string;
  public abstract getRatings(): number;
  public abstract setName(v: string);
  public abstract setRatings(v: number);
}

// Creates a singleton instance of Movie class in runtime
@EasySingleton()
class Movie extends Show {
  constructor (private name: string, private ratings: number) {
    super();
    // Lets say that they just release the movie :D
    this.name = 'Black Panther';
    this.ratings = 9.0; // I really like that movie
  }

  public getName(): string {
    return this.name;
  }

  public getRatings(): number {
    return this.ratings;
  }

  public setName(v: string) {
    this.name = v;
  }

  public setRatings(v: number) {
    this.ratings = v;
  }
}

// Creates a multiple instances as needed in runtime
@EasyPrototype()
class Actor {
  @Easy()
  private movie: Show;
  private name: string;

  constructor (name: string) {
    this.name = name;
  }

  public getMovieName(): string {
    return this.movie.getName();
  }

  public setMovieName(v: string) {
    this.movie.setName(v);
  }
}

let T_Challa = new Actor('Chadwick Boseman');
console.log(T_Challa.getMovieName());// Output is Black Panther
T_Challa.setMovieName('Black Panther II'); // Hopefully
console.log(T_Challa.getMovieName()); // Output is Black Panther II
let Erik_Killmonger = new Actor('Michael B Jordan');
console.log(Erik_Killmonger.getMovieName()) // // Output is Black Panther II

Both Iterfaces and abstract classes inheritance support naming to differentiate between the children dependencies and the names have to go into the @Easy decorator and have to match the names in the @EasyPrototype and @EasySingleton decorators. You can even name the @EasyFactory decorator if u have many abstract classes extending each others.

You can even not name anything and let the package figure out which dependencies as needed:

import { Easy, EasyFactory, EasyPrototype, EasySingleton } from 'easy-injectionjs';

@EasyFactory()
abstract class Person {
  abstract getName();
  abstract setName(v: string);
}

// @EasyObservable()
@EasySingleton()
class Somebody extends Person{
  // @Easy()
  constructor (private name: string) {
    super()
    this.name = 'Sal';
  }

  public getName() {
    return this.name;
  }
  public setName(v: string) {
    this.name = v;
  }
}

@EasyPrototype()
class Nobody extends Person{
  @Easy()
  somebody: Person;
  constructor () {
    super()
  }
  
  public getName() {
    return this.somebody.getName();
  }

  public setName(v: string) {
    this.somebody.setName(v);
  }
}

@EasyPrototype()
class Data {
  @Easy()
  somebody: Person;
  name: string;

  change(v: string) {
    this.somebody.setName(v);
  }

  getName(): string {
    return this.somebody.getName();
  }
}

let n = new Nobody();
console.log(n.getName()) // Prints Sal
n.setName('awesome');
console.log(n.getName())  // Prints awesome
let d = new Data()
console.log(d.getName())  // Prints awesome
d.change('Gelba')
console.log(n.getName())  // Prints Gelba
d.change('kaa')
console.log(n.getName())  // Prints Kaa

The "is" Keyword:

The "is" function is used to retrieve dependencies anywhere in the program. It can also be usint with constructor injection:

Example:

import { EasySingleton,
         EasyPrototype,
         is } import 'easy-injectionjs';

@EasySingleton()
class Somebody {
  // @Easy()
  constructor (private name: string) {
    this.name = 'Vladi';
  }

  public getName() {
    return this.name;
  }
  public setName(v: string) {
    this.name = v;
  }
}

@EasyPrototype()
class Awesome {
  private _name: string;
  constructor (someone: Somebody = is(Somebody)) {
    someone.setName('Sal')
    this._name = someone.getName();
    console.log(this._name);
  }
}

is(Awesome) // call returns an instance of Awesome

console.log(is(Somebody).getName()) // returns Sal since it is a singleton :D

The "Easily" Method:

The "Easily" is ideally used to define static constants or simple objects like:

import { Easily } from 'easy-injectionjs';

const config = {
  author: 'Sal'
}
Easily('config', config);

It requires a name to be injected. PS it can work for npm packages also, if imported like this: import * as smth from 'package'

@EasyPrototype()
class Nobody {
  @Easy('config')
  config: Object;
  constructor () {
    super()
  }
  
  public getName() {
    return this.somebody.getName();
  }
 
  public setName(v: string) {
    this.somebody.setName(v);
  }
}

A bit complicated example:

import {Easy, EasyPrototype, EasySingleton, EasyFactory, Easily, is} from 'easy-injectionjs';

Easily('config', {
  feeling: 'hungry'
})

@EasyFactory()
abstract class Person {
  abstract getName();
  abstract setName(v: string);
}

@EasySingleton()
class Somebody extends Person{
  // @Easy()
  constructor (private name: string) {
    super()
    this.name = 'Sal';
  }
 
  public getName() {
    return this.name;
  }
  public setName(v: string) {
    this.name = v;
  }
}
 
@EasyPrototype()
class Nobody extends Person{
  @Easy()
  somebody: Person;
  @Easy('config')
  config: Object;
  constructor () {
    super()
  }
  
  public getName() {
    return this.somebody.getName();
  }
 
  public setName(v: string) {
    this.somebody.setName(v);
  }
}

@EasyFactory()
abstract class Show {
  public abstract getName(): string;
  public abstract getRatings(): number;
  public abstract setName(v: string);
  public abstract setRatings(v: number);
}
 
// Creates a singleton instance of Movie class in runtime
@EasySingleton()
class Movie extends Show {
  constructor (private name: string, private ratings: number) {
    super();
    // Lets say that they just release the movie :D
    this.name = 'Black Panther';
    this.ratings = 9.0; // I really like that movie
  }
 
  public getName(): string {
    return this.name;
  }
 
  public getRatings(): number {
    return this.ratings;
  }
 
  public setName(v: string) {
    this.name = v;
  }
 
  public setRatings(v: number) {
    this.ratings = v;
  }
}
 
@EasySingleton()
class Data {
  @Easy()
  somebody: Person;
  name: string;
  @Easy()
  movie: Movie;
  change(v: string) {
    this.somebody.setName(v);
  }
 
  getName(): string {
    return this.somebody.getName();
  }
}
 
let n = new Nobody();
console.log(n)
console.log(n.getName()) // Prints Sal
n.setName('awesome');
console.log(n.getName())  // Prints awesome
let d = new Data()
console.log(d)
console.log(d.getName())  // Prints awesome
d.change('Gelba')
console.log(n.getName())  // Prints Gelba
d.change('kaa')
console.log(n.getName())

Even method injection is very easy using both "Easily", the decorators and "is". That makes dynamic injection very easy.

import { Easily } from 'easy-injectionjs';

Easily('Data', {
  name: 'Sal'
});

And somewhere in the program in another file:

import { is, Easily } from 'easy-injectionjs';

function modifyData(data: any = is('Data')) {
  data.name = 'I am Batman';
  // update it
  Easily('Data',data);
}

And maybe another class requires "Data":

import { EasyPrototype, Easy } from 'easy-injectionjs';
// why not :D
@EasyPrototype()
class Mule {
  @Easy('Data')
  private data:any;
}

If modifyData was called before Mule was used, the data name inside the property data of mule will change in runtime.

About

No description or website provided.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published