Last active
August 29, 2015 14:17
-
-
Save jehugaleahsa/e89962f7cf88c67cd231 to your computer and use it in GitHub Desktop.
JavaScript Dependency Injection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var di = (function () { | |
if (!Array.isArray) { | |
Array.isArray = function(arg) { | |
return Object.prototype.toString.call(arg) === '[object Array]'; | |
}; | |
} | |
function getContainer() { | |
var container = function () { | |
return getContainer(); | |
}; | |
container.singletons = {}; | |
container.bindings = {}; | |
container.bind = function () { | |
return getNamedConfiguration(this, arguments); | |
}; | |
container.get = function (name) { | |
return get(this, name, {}); | |
}; | |
return container; | |
}; | |
function getNamedConfiguration(container, names) { | |
var configuration = {}; | |
configuration.to = function (spec) { | |
if (!Array.isArray(spec) || spec.length == 0) { | |
throw new Exception('Encountered an invalid binding specification.'); | |
} | |
var factory = spec[spec.length - 1]; | |
if (typeof factory !== 'function') { | |
throw new Exception('The last argument of the binding specification must be a factory method.'); | |
} | |
var dependencies = spec.slice(0, spec.length - 1); | |
var binding = addBindings(container, names, factory, dependencies); | |
return getBindingConfiguration(container, binding); | |
}; | |
configuration.toConstant = function (value) { | |
return this.to([function() { | |
return value; | |
}]); | |
}; | |
return configuration; | |
} | |
function addBindings(container, names, factory, dependencies) { | |
var binding = { | |
names: names, | |
thisArg: null, | |
scope: null, | |
dependencies: dependencies, | |
factory: factory | |
}; | |
for (var index = 0; index !== names.length; ++index) { | |
var name = names[index]; | |
container.bindings[name] = binding; | |
} | |
return binding; | |
} | |
function getBindingConfiguration(container, binding) { | |
return { | |
forThis: function (thisArg) { | |
binding.thisArg = thisArg; | |
return this; | |
}, | |
singleton: function () { | |
binding.scope = container.singletons; | |
return this; | |
} | |
} | |
} | |
function get(container, name, cache) { | |
if (name in cache) { | |
return cache[name]; | |
} | |
var binding = container.bindings[name]; | |
if (typeof binding === 'undefined') { | |
return binding; | |
} | |
var value; | |
if (binding.scope) { | |
if (name in binding.scope) { | |
value = binding.scope[name]; | |
} else { | |
value = resolve(container, binding, cache); | |
updateCache(binding.scope, binding.names, value); | |
} | |
} else { | |
value = resolve(container, binding, cache); | |
} | |
updateCache(cache, binding.names, value); | |
return value; | |
} | |
function resolve(container, binding, cache) { | |
var factory = binding.factory; | |
var thisArg = binding.thisArg; | |
var dependencies = getDependencies(container, binding, cache); | |
var value = factory.apply(thisArg, dependencies); | |
if (typeof value === 'function') { | |
value = value.bind(thisArg); | |
} | |
return value; | |
} | |
function getDependencies(container, binding, cache) { | |
var dependencies = []; | |
for (var index = 0; index !== binding.dependencies.length; ++index) { | |
var dependencyName = binding.dependencies[index]; | |
var dependency = get(container, dependencyName, cache); | |
dependencies.push(dependency); | |
} | |
return dependencies; | |
} | |
function updateCache(cache, names, value) { | |
for (var index = 0; index !== names.length; ++index) { | |
var name = names[index]; | |
cache[name] = value; | |
} | |
} | |
return getContainer(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment