/
Manager.js
193 lines (130 loc) · 6.7 KB
/
Manager.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
Joose.Namespace.Manager = new Joose.Managed.Class('Joose.Namespace.Manager', {
have : {
global : null,
current : null
},
methods : {
initialize : function () {
// backward compat, is used in JXND, pending for removal
this.global = Joose.top
this.current = [ Joose.top ]
},
getCurrent: function () {
return this.current[0]
},
executeIn : function (ns, func) {
var current = this.current
current.unshift(ns)
var res = func.call(ns, ns)
current.shift()
return res
},
earlyCreate : function (name, metaClass, props) {
props.constructorOnly = true
return new metaClass(name, props).c
},
//this function establishing the full "namespace chain" (including the last element)
create : function (nsName, metaClass, extend) {
//if no name provided, then we creating an anonymous class, so just skip all the namespace manipulations
if (!nsName) return new metaClass(nsName, extend).c
var me = this
if (/^\./.test(nsName)) return this.executeIn(Joose.top, function () {
return me.create(nsName.replace(/^\./, ''), metaClass, extend)
})
props = extend || {}
var parts = Joose.S.saneSplit(nsName, '.')
var object = this.getCurrent()
var soFar = object == Joose.top ? [] : Joose.S.saneSplit(object.meta.name, '.')
for (var i = 0; i < parts.length; i++) {
var part = parts[i]
var isLast = i == parts.length - 1
if (part == "meta" || part == "my" || !part) throw "Module name [" + nsName + "] may not include a part called 'meta' or 'my' or empty part."
var cur = object[part]
soFar.push(part)
var soFarName = soFar.join(".")
var needFinalize = false
var nsKeeper
// if the namespace segment is empty
if (typeof cur == "undefined") {
if (isLast) {
// perform "early create" which just fills the namespace segment with right constructor
// this allows us to have a right constructor in the namespace segment when the `body` will be called
nsKeeper = this.earlyCreate(soFarName, metaClass, props)
needFinalize = true
} else
nsKeeper = new Joose.Namespace.Keeper(soFarName).c
object[part] = nsKeeper
cur = nsKeeper
} else if (isLast && cur && cur.meta) {
var currentMeta = cur.meta
if (metaClass == Joose.Namespace.Keeper)
//`Module` over something case - extend the original
currentMeta.extend(props)
else {
if (currentMeta instanceof Joose.Namespace.Keeper) {
currentMeta.plant(this.earlyCreate(soFarName, metaClass, props))
needFinalize = true
} else
throw new Error("Double declaration of [" + soFarName + "]")
}
} else
if (isLast && !(cur && cur.meta && cur.meta.meta)) throw "Trying to setup module " + soFarName + " failed. There is already something: " + cur
if (needFinalize) cur.meta.construct(props)
object = cur
}
return object
},
prepareProperties : function (name, props, defaultMeta, callback) {
if (name && typeof name != 'string') {
props = name
name = null
}
var meta
if (props && props.meta) {
meta = props.meta
delete props.meta
}
if (!meta)
if (props && typeof props.isa == 'function' && props.isa.meta)
meta = props.isa.meta.constructor
else
meta = defaultMeta
return callback.call(this, name, meta, props)
},
getDefaultHelperFor : function (metaClass) {
var me = this
return function (name, props) {
return me.prepareProperties(name, props, metaClass, function (name, meta, props) {
return me.create(name, meta, props)
})
}
},
register : function (helperName, metaClass, func) {
var me = this
if (this.meta.hasMethod(helperName)) {
var helper = function () {
return me[ helperName ].apply(me, arguments)
}
if (!Joose.top[ helperName ]) Joose.top[ helperName ] = helper
if (!Joose[ helperName ]) Joose[ helperName ] = helper
} else {
var methods = {}
methods[ helperName ] = func || this.getDefaultHelperFor(metaClass)
this.meta.extend({
methods : methods
})
this.register(helperName)
}
},
Module : function (name, props) {
return this.prepareProperties(name, props, Joose.Namespace.Keeper, function (name, meta, props) {
if (typeof props == 'function') props = { body : props }
return this.create(name, meta, props)
})
}
}
}).c
Joose.Namespace.Manager.my = new Joose.Namespace.Manager()
Joose.Namespace.Manager.my.register('Class', Joose.Meta.Class)
Joose.Namespace.Manager.my.register('Role', Joose.Meta.Role)
Joose.Namespace.Manager.my.register('Module')