1.0.7 • Published 7 years ago

pluginjector v1.0.7

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

pluginjector

Simple no nonsense dependency injection for extensibility and testability


Install from NPM

Help with development on GitHub


Donations accepted. 😃 😃 😃 $5 paypal $5 😘 😘 😘

- Usage -

Note: Uses ES6/ES2015 features and may fail on Node versions prior to v6.

Pass your core module object to pluginjector then inject plugins
const pluginjector = require('pluginjector')

const inject = pluginjector(myModule)

const myNewModule = inject(myPlugin)
Overwrite properties in your module
const myModule = { val: 1 }
const myPlugin = { val: 2 }

const newModule = pluginjector(MyModule)(myPlugin)

assert(newModule.val === 2) // true
Overwrite methods in your module
const myModule = {
  method (){return 'method'}
}

const myPlugin = {
  method (){return ('plugin')}
}

const newModule = pluginjector(MyModule)(myPlugin)

assert(newModule.method() === 'plugin') // true
Namespace your plugins
const myPlugin {
  method( return 'method' )
}

const myNewModule = inject({pluginname: myPlugin})

assert(myNewModule.myPlugin.method() === 'method') // true
Bind this to your methods with a simple flag

more detailed look at this later

const myModule = {val: 1}

const myPlugin = {
  pluginjectorBindThis: true,
  method (){ return this.val }
}

const newModule = pluginjector(myModule)({myPlugin})

assert(newModule.myPlugin.method() === 1) // true
Pass in files to be imported
const newModule = inject('../path/to/my/file')

const newNamespacedModule = inject({pluginName: '../path/to/my/file'})

// filenames are automatically namespaced in camelCase

const nModule = inject('../location/my-plugin')
assert( !!nModule.myPlugin ) // true
Include a default directory and your users can pass in just the plugin name.
const inject = (myModule, {dir: '../path/to/default/directory'})

const newModule = inject('pluginName')

const newNamespacedModule = inject({differentPluginName: 'pluginName'})
Lazily inject different plugins as needed
const inject = pluginjector(myModule)
const newModule = inject({data: 'abc'})
inject({moreData: 'def'})

assert(newModule.data + newModule.moreData === 'abcdef') // true
Original core is shallow copied to minimize possibility of undesired mutations
let inject = plugininjector({data: 'core module'})
const newModule = inject({data: 'new module'})

inject = pluginjector(myModule)
const anotherNewModule = inject({})

assert(newModule.data === 'new module') // true
assert(anotherNewModule.data === 'core module') // true
Optionally use core module as prototype instead of shallow copy
const inject = pluginjectore(coreModule, {proto: true})
const newModule = inject(plugin)

assert(coreModule.isPrototypeOf(newModule)) // true

More detail to understand handling of this binding
const myModule = { val: 1 }

const myPlugin = {
  // `this` will naturally point to parent module for first layer
  //    of methods unless you namespace it
  method(){ return this.val }
  obj1: {
    // all methods here will get `this` bound to parent module
    pluginjectorBindThis: true, // flag, any truthy value
    method(){ return this.val },
    method2(){ return this.obj2.val }
  },
  obj2: {
    // no flag, so these will not get special binding
    val:2,
    method: ()=>{ return this.val }
  },
  obj3: {
    // falsey flag doesn't count
    pluginjectorBindThis: false,
    val:3,
    method: ()=>{ return this.val }
  }
}

let newModule = require('pluginjector')(myModule)(myPlugin)

assert(newModule.method() === 1) // true
assert(newModule.obj1.method() === 1) // true
assert(newModule.obj1.method2() === 2) // true
assert(newModule.obj2.method() === 2) // true
assert(newModule.obj3.method() === 3) // true

// with namespace,but no flag, `this` points to `newModule.plugin`
newModule = require('pluginjector')(myModule)({plugin: myPlugin})
assert(newModule.plugin.method() === 1) // false, `this.val` does not exist