1 | ClassMap = require './class_map'
|
2 |
|
3 | name = (injectable) ->
|
4 | if injectable.name? then injectable.name
|
5 | else "'#{injectable}'"
|
6 |
|
7 | class Injector
|
8 | constructor: (@binders...) ->
|
9 | @_singletons = new ClassMap()
|
10 | @_stack = []
|
11 |
|
12 | getInstance: (cls, args...) ->
|
13 | @_stack.push(name(cls))
|
14 |
|
15 | try
|
16 | for binder in @binders
|
17 | for binding in binder.bindings
|
18 | instance = @_resolve(cls, binding)
|
19 | if instance? then return instance
|
20 |
|
21 | unless cls.prototype?
|
22 | throw Error("Could not resolve: #{@_stack.join(' -> ')}")
|
23 | @_createNew(cls, undefined, args...)
|
24 |
|
25 | finally
|
26 | @_stack.pop()
|
27 |
|
28 | _createNew: (cls, scope, args...) ->
|
29 | if cls is Injector then return this
|
30 | singleton = @_singletons.get(cls)
|
31 | if singleton? then return singleton
|
32 |
|
33 | ptype = ->
|
34 | ptype.prototype = cls.prototype
|
35 | instance = new ptype()
|
36 | @_injectFields(cls.prototype, instance)
|
37 | cls.apply(instance, args)
|
38 |
|
39 | if scope?.toUpperCase?() is 'SINGLETON' or cls.scope?.toUpperCase?() is 'SINGLETON'
|
40 | @_singletons.set(cls, instance)
|
41 |
|
42 | instance
|
43 |
|
44 | _resolve: (cls, binding) ->
|
45 | if binding.matches(cls)
|
46 | defaultFactory = =>
|
47 | @_createNew(binding.impl, binding.scope)
|
48 | binding.create(defaultFactory)
|
49 |
|
50 | _injectFields: (ptype, instance) ->
|
51 | for k, v of ptype
|
52 | if v? and v._requiresInjection_
|
53 | instance[k] = @getInstance(v.cls, v.args...)
|
54 |
|
55 | module.exports = Injector
|