Skip to content

Commit d0fcc61

Browse files
committed
Merge branch 'release-3.0.3'
2 parents 0af3b52 + 84a3d53 commit d0fcc61

File tree

9 files changed

+518
-47
lines changed

9 files changed

+518
-47
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
<a name="3.0.3"></a>
2+
## 3.0.3 (2016-08-26)
3+
4+
### Features
5+
6+
* **ioc:** add event and support for fakes ([98fae41](https://github.com/poppinss/adonis-fold/commit/98fae41))
7+
* **providers:** add support for boot method ([f7157a4](https://github.com/poppinss/adonis-fold/commit/f7157a4))
8+
9+
110
<a name="3.0.2"></a>
211
## 3.0.2 (2016-06-26)
312

package.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "adonis-fold",
3-
"version": "3.0.2",
3+
"version": "3.0.3",
44
"description": "Dependency manager and ioc container for your next NodeJs application",
55
"main": "index.js",
66
"directories": {
@@ -18,16 +18,19 @@
1818
"coveralls": "^2.11.4",
1919
"cz-conventional-changelog": "^1.1.5",
2020
"istanbul": "^0.3.22",
21-
"mocha": "^2.3.3",
21+
"mocha": "^3.0.1",
2222
"mocha-lcov-reporter": "^1.0.0",
23-
"standard": "^5.4.1"
23+
"standard": "^7.1.2"
2424
},
2525
"dependencies": {
26-
"co": "^4.6.0",
2726
"cat-log": "^1.0.0",
27+
"co": "^4.6.0",
2828
"co-parallel": "^1.0.0",
29+
"coveralls": "^2.11.12",
2930
"dwell": "^1.0.0",
31+
"eventemitter2": "^2.1.0",
3032
"lodash": "^3.10.1",
33+
"node-exceptions": "^1.0.3",
3134
"require-stack": "^1.0.1"
3235
},
3336
"repository": {

src/Exceptions/index.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
'use strict'
2+
3+
/*
4+
* adonis-fold
5+
*
6+
* (c) Harminder Virk <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
const NE = require('node-exceptions')
13+
14+
class InvalidArgumentException extends NE.InvalidArgumentException {
15+
16+
/**
17+
* default error code to be used for raising
18+
* exceptions
19+
*
20+
* @return {Number}
21+
*/
22+
static get defaultErrorCode () {
23+
return 500
24+
}
25+
26+
/**
27+
* This exception is raised when a manager does not
28+
* have extend method.
29+
*
30+
* @param {String} namespace
31+
* @param {Number} [code=500]
32+
*
33+
* @return {Object}
34+
*/
35+
static invalidIocManager (namespace, code) {
36+
return new this(`Make sure ${namespace} does have a extend method. Report this issue to the provider author`, code || this.defaultErrorCode, 'E_INVALID_IOC_MANAGER')
37+
}
38+
39+
/**
40+
* This exception is raised when the function
41+
* parameter is invalid
42+
*
43+
* @param {String} message
44+
* @param {Number} [code=500]
45+
*
46+
* @return {Object}
47+
*/
48+
static invalidParameters (message, code) {
49+
return new this(message, code || this.defaultErrorCode, 'E_INVALID_PARAMETER')
50+
}
51+
52+
/**
53+
* The exception is raised when string passed to
54+
* Ioc.makeFunc is not valid.
55+
*
56+
* @param {Number} [code=500]
57+
*
58+
* @return {Object}
59+
*/
60+
static invalidMakeString (input, code) {
61+
return new this(`Ioc.makeFunc expects a string in module.method format instead received ${input}`, code || this.defaultErrorCode, 'E_INVALID_MAKE_STRING')
62+
}
63+
}
64+
65+
class RuntimeException extends NE.RuntimeException {
66+
67+
/**
68+
* default error code to be used for raising
69+
* exceptions
70+
*
71+
* @return {Number}
72+
*/
73+
static get defaultErrorCode () {
74+
return 500
75+
}
76+
77+
/**
78+
* This exception is raised when a method being called
79+
* or accessed does not exists on a given parent.
80+
*
81+
* @param {String} parent
82+
* @param {String} method
83+
* @param {Number} [code=500]
84+
*
85+
* @return {Object}
86+
*/
87+
static missingMethod (parent, method, code) {
88+
return new this(`Method ${method} missing on ${parent}`, code || this.defaultErrorCode, 'E_UNDEFINED_METHOD')
89+
}
90+
}
91+
92+
module.exports = { InvalidArgumentException, RuntimeException }

src/Ioc/index.js

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,20 @@ const helpers = require('./helpers')
1010
const _ = require('lodash')
1111
const requireStack = require('require-stack')
1212
const CatLog = require('cat-log')
13+
const CE = require('../Exceptions')
1314
const log = new CatLog('adonis:ioc')
15+
const EventEmitter2 = require('eventemitter2').EventEmitter2
16+
const emitter = new EventEmitter2({
17+
wildcard: false,
18+
newListener: false
19+
})
20+
21+
/**
22+
* fakes to be used for testing
23+
*
24+
* @type {Object}
25+
*/
26+
let fakes = {}
1427

1528
/**
1629
* list of registered providers
@@ -69,10 +82,11 @@ let Ioc = exports = module.exports = {}
6982
*/
7083
Ioc._bind = function (namespace, closure, singleton) {
7184
if (typeof (closure) !== 'function') {
72-
throw new Error('Invalid arguments, bind expects a callback')
85+
throw CE.InvalidArgumentException.invalidParameters('Ioc.bind expects 2nd parameter to be a closure')
7386
}
7487
namespace = namespace.trim()
7588
log.verbose('binding %s to ioc container', namespace)
89+
emitter.emit('bind:provider', namespace, singleton)
7690
providers[namespace] = {closure, singleton, instance: null}
7791
}
7892

@@ -95,18 +109,36 @@ Ioc.new = function () {
95109
* @description resolves eagerly loaded provider
96110
* by setting up dependencies in right order
97111
* @method _resolveProvider
98-
* @param {Object}
112+
* @param {String} namespace
99113
* @return {*}
100114
* @private
101115
*/
102-
Ioc._resolveProvider = function (provider) {
116+
Ioc._resolveProvider = function (namespace) {
117+
log.verbose('resolving provider %s', namespace)
118+
const provider = providers[namespace]
103119
if (!provider.singleton) {
104-
return provider.closure(Ioc)
120+
const returnValue = provider.closure(Ioc)
121+
emitter.emit('provider:resolved', namespace, returnValue)
122+
return returnValue
105123
}
106124
provider.instance = provider.instance || provider.closure(Ioc)
125+
emitter.emit('provider:resolved', namespace, provider.instance)
107126
return provider.instance
108127
}
109128

129+
/**
130+
* resolves a fake for the fakes list
131+
*
132+
* @param {String} namespace
133+
*
134+
* @return {Mixed}
135+
*
136+
* @private
137+
*/
138+
Ioc._resolveFake = function (namespace) {
139+
return fakes[namespace].closure(Ioc)
140+
}
141+
110142
/**
111143
* @description calls provider extenders in a sequence
112144
* and pass key/return value to provider extend
@@ -140,10 +172,10 @@ Ioc._extendProvider = function (namespace) {
140172
* @private
141173
*/
142174
Ioc._autoLoad = function (namespace) {
143-
namespace = namespace.replace(autoloadDirectory.namespace, autoloadDirectory.directoryPath)
144-
log.verbose('autoloading %s from ioc container', namespace)
175+
const namespacePath = namespace.replace(autoloadDirectory.namespace, autoloadDirectory.directoryPath)
176+
log.verbose('resolving %s from path %s', namespace, namespacePath)
145177
try {
146-
let result = requireStack(namespace)
178+
let result = requireStack(namespacePath)
147179
/**
148180
* autoloaded paths can have multiple hooks to be called
149181
* everytime it is required. Lucid is an example of
@@ -156,6 +188,7 @@ Ioc._autoLoad = function (namespace) {
156188
}
157189
})
158190
}
191+
emitter.emit('module:resolved', namespace, namespacePath, result)
159192
return result
160193
} catch (e) {
161194
throw e
@@ -187,6 +220,10 @@ Ioc._type = function (binding) {
187220
return 'UNKNOWN'
188221
}
189222

223+
if (fakes[binding]) {
224+
return 'FAKE'
225+
}
226+
190227
if (providers[binding]) {
191228
return 'PROVIDER'
192229
}
@@ -242,7 +279,7 @@ Ioc.getExtenders = function () {
242279
* @public
243280
*/
244281
Ioc.bind = function (namespace, closure) {
245-
Ioc._bind(namespace, closure)
282+
Ioc._bind(namespace, closure, false)
246283
}
247284

248285
/**
@@ -274,7 +311,7 @@ Ioc.singleton = function (namespace, closure) {
274311
*/
275312
Ioc.manager = function (namespace, defination) {
276313
if (!defination.extend) {
277-
throw new Error('Incomplete implementation, manager objects should have extend method')
314+
throw CE.InvalidArgumentException.invalidIocManager(namespace)
278315
}
279316
log.verbose('registering manager for %s', namespace)
280317
providerManagers[namespace] = defination
@@ -296,10 +333,11 @@ Ioc.manager = function (namespace, defination) {
296333
*/
297334
Ioc.extend = function (namespace, key, closure) {
298335
if (typeof (closure) !== 'function') {
299-
throw new Error('Invalid arguments, extend expects a callback')
336+
throw CE.InvalidArgumentException.invalidParameters('Ioc.extend expects 3rd parameter to be a closure')
300337
}
301338
const args = _.drop(_.toArray(arguments), 3)
302-
log.verbose('extending %s', namespace)
339+
log.verbose('extending %s adding %s', namespace, key)
340+
emitter.emit('extend:provider', key, namespace)
303341
providerExtenders[namespace] = providerExtenders[namespace] || []
304342
providerExtenders[namespace].push({key, closure, args})
305343
}
@@ -314,6 +352,7 @@ Ioc.extend = function (namespace, key, closure) {
314352
* @public
315353
*/
316354
Ioc.autoload = function (namespace, directoryPath) {
355+
emitter.emit('bind:autoload', namespace, directoryPath)
317356
log.verbose('autoloading directory is set to %s under %s namespace', directoryPath, namespace)
318357
autoloadDirectory = {namespace, directoryPath}
319358
}
@@ -330,10 +369,11 @@ Ioc.use = function (namespace) {
330369
const type = Ioc._type(namespace)
331370

332371
switch (type) {
372+
case 'FAKE':
373+
return Ioc._resolveFake(namespace)
333374
case 'PROVIDER':
334-
log.verbose('resolving provider %s', namespace)
335375
Ioc._extendProvider(namespace)
336-
return Ioc._resolveProvider(providers[namespace])
376+
return Ioc._resolveProvider(namespace)
337377
case 'AUTOLOAD':
338378
return Ioc._autoLoad(namespace)
339379
case 'ALIAS':
@@ -367,6 +407,7 @@ Ioc.aliases = function (hash) {
367407
*/
368408
Ioc.alias = function (key, namespace) {
369409
log.verbose('%s has been aliased as %s', namespace, key)
410+
emitter.emit('bind:alias', key, namespace)
370411
aliases[key] = namespace
371412
}
372413

@@ -387,7 +428,7 @@ Ioc.make = function (Binding) {
387428
* return the binding from container and should not act
388429
* smart
389430
*/
390-
if (type === 'PROVIDER' || type === 'ALIAS') {
431+
if (type === 'PROVIDER' || type === 'ALIAS' || type === 'FAKE') {
391432
return Ioc.use(Binding)
392433
}
393434

@@ -443,14 +484,40 @@ Ioc.make = function (Binding) {
443484
Ioc.makeFunc = function (Binding) {
444485
const parts = Binding.split('.')
445486
if (parts.length !== 2) {
446-
throw new Error('Unable to make ' + Binding)
487+
throw CE.InvalidArgumentException.invalidMakeString(Binding)
447488
}
448489

449490
const instance = Ioc.make(parts[0])
450491
const method = parts[1]
451492

452493
if (!instance[method]) {
453-
throw new Error(method + ' does not exists on ' + parts[0])
494+
throw CE.RuntimeException.missingMethod(parts[0], method)
454495
}
455496
return {instance, method}
456497
}
498+
499+
/**
500+
* registers fake for a given namespace
501+
*
502+
* @param {String} namespace
503+
* @param {Function} closure
504+
*
505+
* @public
506+
*/
507+
Ioc.fake = function (namespace, closure) {
508+
if (typeof (closure) !== 'function') {
509+
throw CE.InvalidArgumentException.invalidParameters('Ioc.fake expects 2nd parameter to be a closure')
510+
}
511+
namespace = namespace.trim()
512+
fakes[namespace] = {closure}
513+
}
514+
515+
/**
516+
* adding methods of the event emitter
517+
*/
518+
Ioc.on = emitter.on.bind(emitter)
519+
Ioc.once = emitter.once.bind(emitter)
520+
Ioc.listenerCount = emitter.listenerCount.bind(emitter)
521+
Ioc.removeListener = emitter.removeListener.bind(emitter)
522+
Ioc.removeAllListeners = emitter.removeAllListeners.bind(emitter)
523+
Ioc.emit = emitter.emit.bind(emitter)

0 commit comments

Comments
 (0)