@@ -10,7 +10,20 @@ const helpers = require('./helpers')
10
10
const _ = require ( 'lodash' )
11
11
const requireStack = require ( 'require-stack' )
12
12
const CatLog = require ( 'cat-log' )
13
+ const CE = require ( '../Exceptions' )
13
14
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 = { }
14
27
15
28
/**
16
29
* list of registered providers
@@ -69,10 +82,11 @@ let Ioc = exports = module.exports = {}
69
82
*/
70
83
Ioc . _bind = function ( namespace , closure , singleton ) {
71
84
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 ')
73
86
}
74
87
namespace = namespace . trim ( )
75
88
log . verbose ( 'binding %s to ioc container' , namespace )
89
+ emitter . emit ( 'bind:provider' , namespace , singleton )
76
90
providers [ namespace ] = { closure, singleton, instance : null }
77
91
}
78
92
@@ -95,18 +109,36 @@ Ioc.new = function () {
95
109
* @description resolves eagerly loaded provider
96
110
* by setting up dependencies in right order
97
111
* @method _resolveProvider
98
- * @param {Object }
112
+ * @param {String } namespace
99
113
* @return {* }
100
114
* @private
101
115
*/
102
- Ioc . _resolveProvider = function ( provider ) {
116
+ Ioc . _resolveProvider = function ( namespace ) {
117
+ log . verbose ( 'resolving provider %s' , namespace )
118
+ const provider = providers [ namespace ]
103
119
if ( ! provider . singleton ) {
104
- return provider . closure ( Ioc )
120
+ const returnValue = provider . closure ( Ioc )
121
+ emitter . emit ( 'provider:resolved' , namespace , returnValue )
122
+ return returnValue
105
123
}
106
124
provider . instance = provider . instance || provider . closure ( Ioc )
125
+ emitter . emit ( 'provider:resolved' , namespace , provider . instance )
107
126
return provider . instance
108
127
}
109
128
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
+
110
142
/**
111
143
* @description calls provider extenders in a sequence
112
144
* and pass key/return value to provider extend
@@ -140,10 +172,10 @@ Ioc._extendProvider = function (namespace) {
140
172
* @private
141
173
*/
142
174
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 )
145
177
try {
146
- let result = requireStack ( namespace )
178
+ let result = requireStack ( namespacePath )
147
179
/**
148
180
* autoloaded paths can have multiple hooks to be called
149
181
* everytime it is required. Lucid is an example of
@@ -156,6 +188,7 @@ Ioc._autoLoad = function (namespace) {
156
188
}
157
189
} )
158
190
}
191
+ emitter . emit ( 'module:resolved' , namespace , namespacePath , result )
159
192
return result
160
193
} catch ( e ) {
161
194
throw e
@@ -187,6 +220,10 @@ Ioc._type = function (binding) {
187
220
return 'UNKNOWN'
188
221
}
189
222
223
+ if ( fakes [ binding ] ) {
224
+ return 'FAKE'
225
+ }
226
+
190
227
if ( providers [ binding ] ) {
191
228
return 'PROVIDER'
192
229
}
@@ -242,7 +279,7 @@ Ioc.getExtenders = function () {
242
279
* @public
243
280
*/
244
281
Ioc . bind = function ( namespace , closure ) {
245
- Ioc . _bind ( namespace , closure )
282
+ Ioc . _bind ( namespace , closure , false )
246
283
}
247
284
248
285
/**
@@ -274,7 +311,7 @@ Ioc.singleton = function (namespace, closure) {
274
311
*/
275
312
Ioc . manager = function ( namespace , defination ) {
276
313
if ( ! defination . extend ) {
277
- throw new Error ( 'Incomplete implementation, manager objects should have extend method' )
314
+ throw CE . InvalidArgumentException . invalidIocManager ( namespace )
278
315
}
279
316
log . verbose ( 'registering manager for %s' , namespace )
280
317
providerManagers [ namespace ] = defination
@@ -296,10 +333,11 @@ Ioc.manager = function (namespace, defination) {
296
333
*/
297
334
Ioc . extend = function ( namespace , key , closure ) {
298
335
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 ')
300
337
}
301
338
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 )
303
341
providerExtenders [ namespace ] = providerExtenders [ namespace ] || [ ]
304
342
providerExtenders [ namespace ] . push ( { key, closure, args} )
305
343
}
@@ -314,6 +352,7 @@ Ioc.extend = function (namespace, key, closure) {
314
352
* @public
315
353
*/
316
354
Ioc . autoload = function ( namespace , directoryPath ) {
355
+ emitter . emit ( 'bind:autoload' , namespace , directoryPath )
317
356
log . verbose ( 'autoloading directory is set to %s under %s namespace' , directoryPath , namespace )
318
357
autoloadDirectory = { namespace, directoryPath}
319
358
}
@@ -330,10 +369,11 @@ Ioc.use = function (namespace) {
330
369
const type = Ioc . _type ( namespace )
331
370
332
371
switch ( type ) {
372
+ case 'FAKE' :
373
+ return Ioc . _resolveFake ( namespace )
333
374
case 'PROVIDER' :
334
- log . verbose ( 'resolving provider %s' , namespace )
335
375
Ioc . _extendProvider ( namespace )
336
- return Ioc . _resolveProvider ( providers [ namespace ] )
376
+ return Ioc . _resolveProvider ( namespace )
337
377
case 'AUTOLOAD' :
338
378
return Ioc . _autoLoad ( namespace )
339
379
case 'ALIAS' :
@@ -367,6 +407,7 @@ Ioc.aliases = function (hash) {
367
407
*/
368
408
Ioc . alias = function ( key , namespace ) {
369
409
log . verbose ( '%s has been aliased as %s' , namespace , key )
410
+ emitter . emit ( 'bind:alias' , key , namespace )
370
411
aliases [ key ] = namespace
371
412
}
372
413
@@ -387,7 +428,7 @@ Ioc.make = function (Binding) {
387
428
* return the binding from container and should not act
388
429
* smart
389
430
*/
390
- if ( type === 'PROVIDER' || type === 'ALIAS' ) {
431
+ if ( type === 'PROVIDER' || type === 'ALIAS' || type === 'FAKE' ) {
391
432
return Ioc . use ( Binding )
392
433
}
393
434
@@ -443,14 +484,40 @@ Ioc.make = function (Binding) {
443
484
Ioc . makeFunc = function ( Binding ) {
444
485
const parts = Binding . split ( '.' )
445
486
if ( parts . length !== 2 ) {
446
- throw new Error ( 'Unable to make ' + Binding )
487
+ throw CE . InvalidArgumentException . invalidMakeString ( Binding )
447
488
}
448
489
449
490
const instance = Ioc . make ( parts [ 0 ] )
450
491
const method = parts [ 1 ]
451
492
452
493
if ( ! instance [ method ] ) {
453
- throw new Error ( method + ' does not exists on ' + parts [ 0 ] )
494
+ throw CE . RuntimeException . missingMethod ( parts [ 0 ] , method )
454
495
}
455
496
return { instance, method}
456
497
}
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