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

Modernize #23

Merged
merged 19 commits into from
Jan 28, 2017
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
15 changes: 15 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"env": {
"node": true,
"es6": true
},
"extends": "standard",
"rules": {
"space-before-function-paren": ["error", {
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}]
},
"no-var": ["error"]
}
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
*.iml
node_modules
*.log
node_modules
coverage
.nyc_output
21 changes: 0 additions & 21 deletions .jshintrc

This file was deleted.

6 changes: 4 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
language: node_js
node_js:
- "0.12"
- "0.10"
- "4"
- "6"
after_success:
- './node_modules/.bin/nyc report --reporter=text-lcov | ./node_modules/.bin/coveralls'
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ _"JavaScript dependency injection that's so small, it almost doesn't count."_

| Branch | Status |
| ------------- |:-------------:|
| Master | [![Build Status](https://travis-ci.org/ecowden/pluto.js.png?branch=master)](https://travis-ci.org/ecowden/pluto.js) |
| All | [![Build Status](https://travis-ci.org/ecowden/pluto.js.png)](https://travis-ci.org/ecowden/pluto.js) |
| Master | [![Build Status](https://travis-ci.org/ecowden/pluto.js.png?branch=master)](https://travis-ci.org/ecowden/pluto.js) [![Coverage Status](https://coveralls.io/repos/github/ecowden/pluto.js/badge.svg?branch=master)](https://coveralls.io/github/ecowden/pluto.js?branch=master) |
| All | [![Build Status](https://travis-ci.org/ecowden/pluto.js.png)](https://travis-ci.org/ecowden/pluto.js) [![Coverage Status](https://coveralls.io/repos/github/ecowden/pluto.js/badge.svg?branch=master)](https://coveralls.io/github/ecowden/pluto.js) |

What is Pluto?
--------------
Expand Down
50 changes: 50 additions & 0 deletions lib/examplesSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict'

const test = require('ava')

const pluto = require('./pluto')

test('bind to instance', function* (t) {
const anInstance = {} // can be any JavaScript object
const module = pluto.createModule(function (bind) {
bind('myInstance').toInstance(anInstance)
})

t.is(module.get('myInstance'), anInstance)
})

test('bind to constructor', function* (t) {
function Greeter(greeting) {
this.greeting = greeting
}

Greeter.prototype.greet = function () {
return this.greeting
}

const module = pluto.createModule(function (bind) {
bind('greeting').toInstance('Hello, world!')
bind('greeter').toConstructor(Greeter)
})

const theGreeter = module.get('greeter')

t.is(theGreeter.greet(), 'Hello, world!')
})

test('bind to factory function', function* (t) {
function greeterFactory(greeting) {
return function () {
return greeting
}
}

const module = pluto.createModule(function (bind) {
bind('greeting').toInstance('Hello, world!')
bind('greeter').toFactory(greeterFactory)
})

const theGreeter = module.get('greeter')

t.is(theGreeter(), 'Hello, world!')
})
127 changes: 63 additions & 64 deletions lib/pluto.js
Original file line number Diff line number Diff line change
@@ -1,149 +1,148 @@
var _ = require('underscore'),
MAX_CONSTRUCTOR_ARGUMENTS = 8;
const _ = require('underscore')
const MAX_CONSTRUCTOR_ARGUMENTS = 8

var createModule = function(createModuleCallback) {
function createModule(createModuleCallback) {
function createInstanceResolver(instance) {
return function() {
return instance;
};
return function () {
return instance
}
}

function getArgumentNames(func) {
var funStr = func.toString();
return funStr.slice(funStr.indexOf('(') + 1, funStr.indexOf(')')).match(/([^\s,]+)/g);
const funStr = func.toString()
return funStr.slice(funStr.indexOf('(') + 1, funStr.indexOf(')')).match(/([^\s,]+)/g)
}

function createFactoryResolver(factory) {
return function() {
var argumentNames = getArgumentNames(factory);
return function () {
const argumentNames = getArgumentNames(factory)
if (!argumentNames || argumentNames.length === 0) {
return factory();
return factory()
}

var args = getAll(argumentNames);
return factory.apply(factory, args);
};
const args = getAll(argumentNames)
return factory.apply(factory, args)
}
}

function createConstructorResolver(Constructor) {
return function() {
return function () {
/*
* It turns out that dynamically invoking constructor functions is a bit tricky. I have decided to
* manually invoke them for now until I can do further research and choose the best alternative.
* For now, constructor injection will be limited to eight arguments.
*/
var argumentNames = getArgumentNames(Constructor);
const argumentNames = getArgumentNames(Constructor)
if (!argumentNames || argumentNames.length === 0) {
return new Constructor();
return new Constructor()
}

var argumentCount = argumentNames.length;
var args = getAll(argumentNames);
const argumentCount = argumentNames.length
const args = getAll(argumentNames)
if (argumentCount === 1) {
return new Constructor(args[0]);
return new Constructor(args[0])
}

if (argumentCount === 2) {
return new Constructor(args[0], args[1]);
return new Constructor(args[0], args[1])
}

if (argumentCount === 3) {
return new Constructor(args[0], args[1], args[2]);
return new Constructor(args[0], args[1], args[2])
}

if (argumentCount === 4) {
return new Constructor(args[0], args[1], args[2], args[3]);
return new Constructor(args[0], args[1], args[2], args[3])
}

if (argumentCount === 5) {
return new Constructor(args[0], args[1], args[2], args[3], args[4]);
return new Constructor(args[0], args[1], args[2], args[3], args[4])
}

if (argumentCount === 6) {
return new Constructor(args[0], args[1], args[2], args[3], args[4], args[5]);
return new Constructor(args[0], args[1], args[2], args[3], args[4], args[5])
}

if (argumentCount === 7) {
return new Constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
return new Constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6])
}

if (argumentCount === 8) {
return new Constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
return new Constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7])
}

var msg = "Pluto cannot inject constructor functions with " + MAX_CONSTRUCTOR_ARGUMENTS + " or more arguments " +
"at this time (it's a long story). Please use a non-constructor factory function instead or consider injecting fewer dependencies.";
throw Error(msg);
};
const msg = 'Pluto cannot inject constructor functions with ' + MAX_CONSTRUCTOR_ARGUMENTS + ' or more arguments ' +
"at this time (it's a long story). Please use a non-constructor factory function instead or consider injecting fewer dependencies."
throw Error(msg)
}
}

var namesToResolvers = {};
const namesToResolvers = {}

var get = _.memoize(function get(name) {

var resolver = namesToResolvers[name];
const get = _.memoize(function get(name) {
const resolver = namesToResolvers[name]
if (!resolver) {
throw Error("nothing is mapped for name '" + name + "'");
throw Error("nothing is mapped for name '" + name + "'")
}
return resolver();
});
return resolver()
})

function getAll(names) {
return names.map(function(name) {
return get(name);
});
return names.map(function (name) {
return get(name)
})
}

function eagerlyLoadAll() {
_.keys(namesToResolvers).forEach(function(name) {
get(name);
});
_.keys(namesToResolvers).forEach(function (name) {
get(name)
})
}

createModuleCallback(function bind(name) {
function validateBinding(target) {
if (_.has(namesToResolvers, name)) {
throw Error('module already contains a mapping with the name \'' + name + '\'');
throw Error('module already contains a mapping with the name \'' + name + '\'')
}
if (_.isUndefined(target)) {
throw Error('cannot bind \'' + name + '\' because the specified target is undefined.');
throw Error('cannot bind \'' + name + '\' because the specified target is undefined.')
}
if (_.isNull(target)) {
throw Error('cannot bind \'' + name + '\' because the specified target is null.');
throw Error('cannot bind \'' + name + '\' because the specified target is null.')
}
}

function validateTargetIsAFunction(factory) {
if (!_.isFunction(factory)) {
throw Error('cannot bind \'' + name + '\' because the specified target is not a function.');
throw Error('cannot bind \'' + name + '\' because the specified target is not a function.')
}
}

return {
toInstance: function(instance) {
validateBinding(instance);
namesToResolvers[name] = createInstanceResolver(instance);
toInstance: function (instance) {
validateBinding(instance)
namesToResolvers[name] = createInstanceResolver(instance)
},
toFactory: function(factory) {
validateBinding(factory);
validateTargetIsAFunction(factory);
namesToResolvers[name] = createFactoryResolver(factory);
toFactory: function (factory) {
validateBinding(factory)
validateTargetIsAFunction(factory)
namesToResolvers[name] = createFactoryResolver(factory)
},
toConstructor: function(constructor) {
validateBinding(constructor);
validateTargetIsAFunction(constructor);
namesToResolvers[name] = createConstructorResolver(constructor);
toConstructor: function (constructor) {
validateBinding(constructor)
validateTargetIsAFunction(constructor)
namesToResolvers[name] = createConstructorResolver(constructor)
}
};
});
}
})

return {
eagerlyLoadAll: eagerlyLoadAll,
get: get,
getAll: getAll
};
};
}
}

exports = module.exports = {
createModule: createModule
};
}
Loading