dependency-injection
Advanced tools
Comparing version 2.2.0 to 2.3.0
@@ -1,1 +0,3 @@ | ||
module.exports = require('./lib/DIConfigurator'); | ||
console.log('DIConfigurator is deprecated, please use DIFactory instead.'); | ||
module.exports = require('./lib/DIFactory'); |
114
lib/DI.js
@@ -27,2 +27,4 @@ // Generated by CoffeeScript 1.6.3 | ||
DI.prototype.instantiate = true; | ||
function DI() { | ||
@@ -37,3 +39,3 @@ this.services = {}; | ||
if (this.config === null) { | ||
throw new Error('DI container was not created with DIConfigurator.'); | ||
throw new Error('DI container was not created with DIFactory.'); | ||
} | ||
@@ -48,2 +50,3 @@ return this.config.getParameter(parameter); | ||
DI.prototype.addService = function(name, service, args) { | ||
var originalService; | ||
if (args == null) { | ||
@@ -55,10 +58,93 @@ args = []; | ||
} | ||
originalService = service; | ||
if (typeof service === 'string') { | ||
service = require.resolve(this.getPath(service)); | ||
this.paths[service] = name; | ||
if (service.match(/^(factory\:)?[@$]/)) { | ||
service = this.tryCallArgument(service); | ||
} else { | ||
service = this.resolveModulePath(service); | ||
if (service === null) { | ||
throw new Error("Service '" + originalService + "' can not be found."); | ||
} | ||
this.paths[service] = name; | ||
} | ||
} | ||
this.services[name] = new Service(this, name, service, args); | ||
this.services[name].setInstantiate(this.instantiate); | ||
return this.services[name]; | ||
}; | ||
DI.prototype.resolveModulePath = function(_path) { | ||
var get; | ||
get = function(p) { | ||
var err; | ||
try { | ||
return require.resolve(p); | ||
} catch (_error) { | ||
err = _error; | ||
return null; | ||
} | ||
}; | ||
return get(_path) || get(this.getPath(_path)) || get(Helpers.normalizePath(_path)) || get(Helpers.normalizePath(this.getPath(_path))); | ||
}; | ||
DI.prototype.tryCallArgument = function(arg) { | ||
var a, after, args, factory, i, match, original, pos, service, sub, type, _i, _len; | ||
if (typeof arg !== 'string') { | ||
return arg; | ||
} | ||
if (!arg.match(/^(factory\:)?[@$]/)) { | ||
return arg; | ||
} | ||
factory = false; | ||
if (arg.match(/^factory\:/)) { | ||
factory = true; | ||
arg = arg.substr(8); | ||
} | ||
type = arg[0] === '@' ? 'service' : 'path'; | ||
original = arg; | ||
arg = arg.substr(1); | ||
service = null; | ||
after = []; | ||
if ((pos = arg.indexOf('::')) !== -1) { | ||
after = arg.substr(pos + 2).split('::'); | ||
arg = arg.substr(0, pos); | ||
} | ||
if (type === 'service') { | ||
service = factory ? this.getFactory(arg) : this.get(arg); | ||
} else if (type === 'path') { | ||
service = factory ? this.getFactoryByPath(arg) : this.getByPath(arg); | ||
} | ||
if (service === null) { | ||
throw new Error("Service '" + arg + "' can not be found."); | ||
} | ||
if (after.length > 0) { | ||
args = []; | ||
while (after.length > 0) { | ||
sub = after.shift(); | ||
if ((match = sub.match(/^(.+)\((.*)\)$/)) !== null) { | ||
sub = match[1]; | ||
args = match[2].split(','); | ||
for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) { | ||
a = args[i]; | ||
a = a.trim(); | ||
if ((match = a.match(/'(.*)'/)) || (match = a.match(/"(.*)"/))) { | ||
args[i] = match[1]; | ||
} else { | ||
args[i] = this.tryCallArgument(a); | ||
} | ||
} | ||
} | ||
if (typeof service[sub] === 'undefined') { | ||
throw new Error("Can not access '" + sub + "' in '" + original + "'."); | ||
} | ||
if (Object.prototype.toString.call(service[sub]) === '[object Function]') { | ||
service = this.inject(service[sub], args, service); | ||
} else { | ||
service = service[sub]; | ||
} | ||
} | ||
} | ||
return service; | ||
}; | ||
DI.prototype.autowireArguments = function(method, args) { | ||
@@ -127,11 +213,4 @@ if (args == null) { | ||
DI.prototype.getByPath = function(path) { | ||
var e, error; | ||
error = false; | ||
try { | ||
path = require.resolve(this.getPath(path)); | ||
} catch (_error) { | ||
e = _error; | ||
error = true; | ||
} | ||
if (typeof this.paths[path] !== 'undefined' && !error) { | ||
path = this.resolveModulePath(path); | ||
if (path !== null && typeof this.paths[path] !== 'undefined') { | ||
return this.get(this.paths[path]); | ||
@@ -143,11 +222,4 @@ } | ||
DI.prototype.getFactoryByPath = function(path) { | ||
var e, error; | ||
error = false; | ||
try { | ||
path = require.resolve(this.getPath(path)); | ||
} catch (_error) { | ||
e = _error; | ||
error = true; | ||
} | ||
if (typeof this.paths[path] !== 'undefined' && !error) { | ||
path = this.resolveModulePath(path); | ||
if (path !== null && typeof this.paths[path] !== 'undefined') { | ||
return this.getFactory(this.paths[path]); | ||
@@ -154,0 +226,0 @@ } |
@@ -40,2 +40,27 @@ // Generated by CoffeeScript 1.6.3 | ||
Helpers.dirName = function(path) { | ||
var num; | ||
num = path.lastIndexOf('/'); | ||
return path.substr(0, num); | ||
}; | ||
Helpers.normalizePath = function(path) { | ||
var part, parts, prev, result, _i, _len; | ||
parts = path.split('/'); | ||
result = []; | ||
prev = null; | ||
for (_i = 0, _len = parts.length; _i < _len; _i++) { | ||
part = parts[_i]; | ||
if (part === '.' || part === '') { | ||
continue; | ||
} else if (part === '..' && prev) { | ||
result.pop(); | ||
} else { | ||
result.push(part); | ||
} | ||
prev = part; | ||
} | ||
return '/' + result.join('/'); | ||
}; | ||
Helpers.log = function(message) { | ||
@@ -156,23 +181,3 @@ if ((typeof console !== "undefined" && console !== null ? console.log : void 0) != null) { | ||
} else { | ||
if (args[0] !== null && typeof args[0] === 'string' && args[0].match(/^factory:/) !== null) { | ||
args[0] = args[0].substr(8); | ||
factory = true; | ||
} | ||
if (args[0] !== null && typeof args[0] === 'string' && args[0].match(/^@/) !== null) { | ||
args[0] = args[0].substr(1); | ||
if (factory) { | ||
result.push(container.getFactory(args[0])); | ||
} else { | ||
result.push(container.get(args[0])); | ||
} | ||
} else if (args[0] !== null && typeof args[0] === 'string' && args[0].match(/^\$/) !== null) { | ||
args[0] = args[0].substr(1); | ||
if (factory) { | ||
result.push(container.getFactoryByPath(args[0])); | ||
} else { | ||
result.push(container.getByPath(args[0])); | ||
} | ||
} else { | ||
result.push(args[0]); | ||
} | ||
result.push(container.tryCallArgument(args[0])); | ||
previousDots = false; | ||
@@ -179,0 +184,0 @@ args.shift(); |
{ | ||
"name": "dependency-injection", | ||
"description": "Dependency injection with configuration and autowire for node js and browser", | ||
"version": "2.2.0", | ||
"version": "2.3.0", | ||
"author": { | ||
@@ -21,3 +21,3 @@ "name": "David Kudera", | ||
"engines": { | ||
"node": "*" | ||
"node": ">=0.9" | ||
}, | ||
@@ -31,3 +31,3 @@ "main": "./lib/DI", | ||
"chai": "~1.8.1", | ||
"mocha": "~1.16.2", | ||
"mocha": "~1.17.0", | ||
"mocha-phantomjs": "~3.3.1", | ||
@@ -39,3 +39,3 @@ "phantomjs": "~1.9.2-6" | ||
"build-and-test": "npm run test-build && npm run test", | ||
"test-build": "cd ./test/browser; simq build;", | ||
"test-build": "coffee -co ./test/data ./test/data; coffee -co ./test/node/lib ./test/node/src; cd ./test/browser; simq build;", | ||
"test-node": "mocha ./test/node/index.js --reporter spec", | ||
@@ -42,0 +42,0 @@ "test-browser": "mocha-phantomjs ./test/browser/index.html" |
@@ -52,2 +52,4 @@ [![NPM version](https://badge.fury.io/js/dependency-injection.png)](http://badge.fury.io/js/dependency-injection) | ||
You can of course use also modules from node_modules directory just like you are used to. | ||
DI automatically look into values from setup in your module (service). If it is function, then it will be called, otherwise | ||
@@ -59,6 +61,6 @@ argument will be passed into this object property. | ||
``` | ||
var DIConfigurator = require('dependency-injection/DIConfigurator'); | ||
var configurator = new DIConfigurator('./path/to/your/configuration/file.json'); | ||
var DIFactory = require('dependency-injection/DIFactory'); | ||
var factory = new DIFactory('./path/to/your/configuration/file.json'); | ||
var di = configurator.create(); | ||
var di = factory.create(); | ||
``` | ||
@@ -83,6 +85,8 @@ | ||
Default base path in node is directory of file from which you are initializing DI. You have to set this manually in browser. | ||
Base path is used for requiring your services. All services (exceptions are node_modules services) are relative to this path. | ||
**Default base path is directory in which is your config.json file.** | ||
``` | ||
di.basePath = __dirname; | ||
di.basePath = __dirname + '/my/custom/base/directory'; | ||
``` | ||
@@ -348,4 +352,44 @@ | ||
Now this `foreignLibrary` will gets your `translator` service in constructor. | ||
you can even access properties or methods from other services: | ||
``` | ||
{ | ||
"services": { | ||
"foreignLibrary": { | ||
"service": "path/to/service", | ||
"arguments": [ | ||
"@translator::getLanguage('en')", // en can be default language | ||
"@http::basePath" | ||
] | ||
} | ||
} | ||
} | ||
``` | ||
or create service from other service (for example from factory) | ||
``` | ||
{ | ||
"services": { | ||
"httpFactory": { | ||
"service": "./path/to/http/module" | ||
}, | ||
"http": { | ||
"service": "@httpFactory::createHttp()" | ||
} | ||
} | ||
} | ||
``` | ||
## Default settings | ||
You can change default behavior of some options in your config file. | ||
``` | ||
{ | ||
"defaults": { | ||
"instantiate": false | ||
}, | ||
"services": { ... } | ||
} | ||
``` | ||
## Default services | ||
@@ -405,13 +449,13 @@ | ||
If you need more control over configuration, you can create instance of `easy-configuration` object on your own and pass | ||
it to DIConfigurator. | ||
it to DIFactory. | ||
``` | ||
var Config = require('easy-configuration'); | ||
var DIConfigurator = require('dependency-injection/DIConfigurator'); | ||
var Configuration = require('dependency-injection/Configuration'); // shortcut to easy-configuration module | ||
var DIFactory = require('dependency-injection/DIFactory'); | ||
var config = new Config; | ||
var config = new Configuration; | ||
config.addConfig('./path/to/config.json', 'development'); | ||
var configurator = new DIConfigurator(config); | ||
var di = configurator.create(); | ||
var factory = new DIFactory(config); | ||
var di = factory.create(); | ||
``` | ||
@@ -483,2 +527,12 @@ | ||
* 2.3.0 | ||
+ Added option for services derived from other services | ||
+ Support for calling methods from other services in config | ||
+ Some optimization | ||
+ exposed [easy-configuration](https://github.com/sakren/node-easy-configuration) into dependency-injection/Configuration | ||
+ DIConfigurator renamed to DIFactory (DIConfigurator is now deprecated) | ||
+ Support for services from npm modules | ||
+ Default base path for services in config file is dir name of config file | ||
+ Updated dependencies | ||
* 2.2.0 | ||
@@ -496,3 +550,3 @@ + Relative paths to config files | ||
* 2.1.0 | ||
+ Added [config](https://github.com/sakren/node-easy-configuration) object do DIConfigurator | ||
+ Added [config](https://github.com/sakren/node-easy-configuration) object do DIFactory | ||
+ Bug with exposing | ||
@@ -499,0 +553,0 @@ + Accessing parameters from di instance |
@@ -9,8 +9,18 @@ { | ||
"./lib/*.js", | ||
"./test/data/*.<(coffee|json)$>" | ||
"./DI.js", | ||
"./DIFactory.js", | ||
"./Configuration.js", | ||
"./test/data/*.<(coffee|json)$>", | ||
"callsite" | ||
], | ||
"aliases": { | ||
"dependency-injection": "/lib/DI.js", | ||
"dependency-injection/Configuration.js": "/Configuration.js", | ||
"dependency-injection/DIFactory.js": "/lib/DIFactory.js", | ||
"dependency-injection/Helpers.js": "/Helpers.js" | ||
}, | ||
"run": [ | ||
"/test/browser/tests/Helpers", | ||
"/test/browser/tests/DI", | ||
"/test/browser/tests/DIConfigurator" | ||
"/test/browser/tests/DIFactory" | ||
] | ||
@@ -17,0 +27,0 @@ } |
@@ -8,2 +8,8 @@ // Generated by CoffeeScript 1.6.3 | ||
Http.prototype.async = false; | ||
Http.prototype.greetings = function(name) { | ||
return 'hello ' + name; | ||
}; | ||
return Http; | ||
@@ -10,0 +16,0 @@ |
require('./lib/Helpers'); | ||
require('./lib/DI'); | ||
require('./lib/DIConfigurator'); | ||
require('./lib/DIFactory'); |
@@ -59,2 +59,60 @@ // Generated by CoffeeScript 1.6.3 | ||
}); | ||
describe('#tryCallArgument()', function() { | ||
it('should just return argument if it is not string', function() { | ||
return expect(di.tryCallArgument(new Date)).to.be.an["instanceof"](Date); | ||
}); | ||
it('should just return argument if it is not in right format', function() { | ||
return expect(di.tryCallArgument('hello word')).to.be.equal('hello word'); | ||
}); | ||
it('should return service by its name', function() { | ||
di.addService('date', Date); | ||
return expect(di.tryCallArgument('@date')).to.be.an["instanceof"](Date); | ||
}); | ||
it('should return service by its path', function() { | ||
di.addService('callsite', 'callsite').setInstantiate(false); | ||
return expect(di.tryCallArgument('$callsite/index.js')).to.be.equal(require('callsite')); | ||
}); | ||
it('should return factory by its name', function() { | ||
var factory; | ||
di.addService('date', Date); | ||
factory = di.tryCallArgument('factory:@date'); | ||
expect(factory).to.be.an["instanceof"](Function); | ||
return expect(factory()).to.be.an["instanceof"](Date); | ||
}); | ||
it('should return factory by its path', function() { | ||
var factory; | ||
di.addService('callsite', 'callsite').setInstantiate(false); | ||
factory = di.tryCallArgument('factory:$callsite/index.js'); | ||
expect(factory).to.be.an["instanceof"](Function); | ||
return expect(factory()).to.be.equal(require('callsite')); | ||
}); | ||
it('should return result from method in service', function() { | ||
di.addService('obj', { | ||
doSomething: function() { | ||
return 'hello'; | ||
} | ||
}).setInstantiate(false); | ||
return expect(di.tryCallArgument('@obj::doSomething')).to.be.equal('hello'); | ||
}); | ||
it('should return result from method with arguments', function() { | ||
di.addService('obj', { | ||
doSomething: function(one, two, three) { | ||
return one + two + three; | ||
} | ||
}).setInstantiate(false); | ||
return expect(di.tryCallArgument('@obj::doSomething("hello", " ", "word")')).to.be.equal('hello word'); | ||
}); | ||
return it('should return result from method with arguments with sub calls to di', function() { | ||
di.addService('obj', { | ||
complete: function() { | ||
return { | ||
callMe: function(greetings, name) { | ||
return greetings + ' ' + name; | ||
} | ||
}; | ||
} | ||
}).setInstantiate(false); | ||
return expect(di.tryCallArgument('@obj::complete::callMe("hello", "David")')).to.be.equal('hello David'); | ||
}); | ||
}); | ||
describe('#createInstance()', function() { | ||
@@ -112,2 +170,6 @@ beforeEach(function() { | ||
}); | ||
it('should add service from node_modules', function() { | ||
di.addService('callsite', 'callsite').setInstantiate(false); | ||
return expect(di.get('callsite')).to.be.equal(require('callsite')); | ||
}); | ||
it('should return info array without instantiating it', function() { | ||
@@ -114,0 +176,0 @@ return expect(di.get('info')).to.be.eql(['hello']); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
211932
47
3645
645
8