siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
1,897 lines (1,192 loc) • 3.78 MB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
;if (typeof Joose == "undefined") !function () {;
var Joose = {}
// configuration hash
Joose.C = typeof JOOSE_CFG != 'undefined' ? JOOSE_CFG : {}
Joose.is_IE = '\v' == 'v'
Joose.is_NodeJS = Boolean(typeof process != 'undefined' && process.pid)
Joose.top = Joose.is_NodeJS && global || this
Joose.stub = function () {
return function () { throw new Error("Modules can not be instantiated") }
}
Joose.VERSION = ({ /*PKGVERSION*/VERSION : '3.50.1' }).VERSION
if (typeof module != 'undefined') module.exports = Joose
/*if (!Joose.is_NodeJS) */
this.Joose = Joose
// Static helpers for Arrays
Joose.A = {
each : function (array, func, scope) {
scope = scope || this
for (var i = 0, len = array.length; i < len; i++)
if (func.call(scope, array[i], i) === false) return false
},
eachR : function (array, func, scope) {
scope = scope || this
for (var i = array.length - 1; i >= 0; i--)
if (func.call(scope, array[i], i) === false) return false
},
exists : function (array, value) {
for (var i = 0, len = array.length; i < len; i++) if (array[i] == value) return true
return false
},
map : function (array, func, scope) {
scope = scope || this
var res = []
for (var i = 0, len = array.length; i < len; i++)
res.push( func.call(scope, array[i], i) )
return res
},
grep : function (array, func) {
var a = []
Joose.A.each(array, function (t) {
if (func(t)) a.push(t)
})
return a
},
remove : function (array, removeEle) {
var a = []
Joose.A.each(array, function (t) {
if (t !== removeEle) a.push(t)
})
return a
}
}
// Static helpers for Strings
Joose.S = {
saneSplit : function (str, delimeter) {
var res = (str || '').split(delimeter)
if (res.length == 1 && !res[0]) res.shift()
return res
},
uppercaseFirst : function (string) {
return string.substr(0, 1).toUpperCase() + string.substr(1, string.length - 1)
},
strToClass : function (name, top) {
var current = top || Joose.top
Joose.A.each(name.split('.'), function (segment) {
if (current)
current = current[ segment ]
else
return false
})
return current
}
}
var baseFunc = function () {}
var enumProps = [ 'hasOwnProperty', 'valueOf', 'toString', 'constructor' ]
var manualEnum = true
for (var i in { toString : 1 }) manualEnum = false
// Static helpers for objects
Joose.O = {
each : function (object, func, scope) {
scope = scope || this
for (var i in object)
if (func.call(scope, object[i], i) === false) return false
if (manualEnum)
return Joose.A.each(enumProps, function (el) {
if (object.hasOwnProperty(el)) return func.call(scope, object[el], el)
})
},
eachOwn : function (object, func, scope) {
scope = scope || this
return Joose.O.each(object, function (value, name) {
if (object.hasOwnProperty(name)) return func.call(scope, value, name)
}, scope)
},
copy : function (source, target) {
target = target || {}
Joose.O.each(source, function (value, name) { target[name] = value })
return target
},
copyOwn : function (source, target) {
target = target || {}
Joose.O.eachOwn(source, function (value, name) { target[name] = value })
return target
},
getMutableCopy : function (object) {
baseFunc.prototype = object
return new baseFunc()
},
extend : function (target, source) {
return Joose.O.copy(source, target)
},
isEmpty : function (object) {
for (var i in object) if (object.hasOwnProperty(i)) return false
return true
},
isInstance: function (obj) {
return obj && obj.meta && obj.constructor == obj.meta.c
},
isClass : function (obj) {
return obj && obj.meta && obj.meta.c == obj
},
wantArray : function (obj) {
if (obj instanceof Array) return obj
return [ obj ]
},
// this was a bug in WebKit, which gives typeof / / == 'function'
// should be monitored and removed at some point in the future
isFunction : function (obj) {
return typeof obj == 'function' && obj.constructor != / /.constructor
}
}
//initializers
Joose.I = {
Array : function () { return [] },
Object : function () { return {} },
Function : function () { return arguments.callee },
Now : function () { return new Date() }
};
Joose.Proto = Joose.stub()
Joose.Proto.Empty = Joose.stub()
Joose.Proto.Empty.meta = {};
;(function () {
Joose.Proto.Object = Joose.stub()
var SUPER = function () {
var self = SUPER.caller
if (self == SUPERARG) self = self.caller
if (!self.SUPER) throw "Invalid call to SUPER"
return self.SUPER[self.methodName].apply(this, arguments)
}
var SUPERARG = function () {
return this.SUPER.apply(this, arguments[0])
}
Joose.Proto.Object.prototype = {
SUPERARG : SUPERARG,
SUPER : SUPER,
INNER : function () {
throw "Invalid call to INNER"
},
BUILD : function (config) {
return arguments.length == 1 && typeof config == 'object' && config || {}
},
initialize: function () {
},
toString: function () {
return "a " + this.meta.name
}
}
Joose.Proto.Object.meta = {
constructor : Joose.Proto.Object,
methods : Joose.O.copy(Joose.Proto.Object.prototype),
attributes : {}
}
Joose.Proto.Object.prototype.meta = Joose.Proto.Object.meta
})();
;(function () {
Joose.Proto.Class = function () {
return this.initialize(this.BUILD.apply(this, arguments)) || this
}
var bootstrap = {
VERSION : null,
AUTHORITY : null,
constructor : Joose.Proto.Class,
superClass : null,
name : null,
attributes : null,
methods : null,
meta : null,
c : null,
defaultSuperClass : Joose.Proto.Object,
BUILD : function (name, extend) {
this.name = name
return { __extend__ : extend || {} }
},
initialize: function (props) {
var extend = props.__extend__
this.VERSION = extend.VERSION
this.AUTHORITY = extend.AUTHORITY
delete extend.VERSION
delete extend.AUTHORITY
this.c = this.extractConstructor(extend)
this.adaptConstructor(this.c)
if (extend.constructorOnly) {
delete extend.constructorOnly
return
}
this.construct(extend)
},
construct : function (extend) {
if (!this.prepareProps(extend)) return
var superClass = this.superClass = this.extractSuperClass(extend)
this.processSuperClass(superClass)
this.adaptPrototype(this.c.prototype)
this.finalize(extend)
},
finalize : function (extend) {
this.processStem(extend)
this.extend(extend)
},
//if the extension returns false from this method it should re-enter 'construct'
prepareProps : function (extend) {
return true
},
extractConstructor : function (extend) {
var res = extend.hasOwnProperty('constructor') ? extend.constructor : this.defaultConstructor()
delete extend.constructor
return res
},
extractSuperClass : function (extend) {
if (extend.hasOwnProperty('isa') && !extend.isa) throw new Error("Attempt to inherit from undefined superclass [" + this.name + "]")
var res = extend.isa || this.defaultSuperClass
delete extend.isa
return res
},
processStem : function () {
var superMeta = this.superClass.meta
this.methods = Joose.O.getMutableCopy(superMeta.methods || {})
this.attributes = Joose.O.getMutableCopy(superMeta.attributes || {})
},
initInstance : function (instance, props) {
Joose.O.copyOwn(props, instance)
},
defaultConstructor: function () {
return function (arg) {
var BUILD = this.BUILD
var args = BUILD && BUILD.apply(this, arguments) || arg || {}
var thisMeta = this.meta
thisMeta.initInstance(this, args)
return thisMeta.hasMethod('initialize') && this.initialize(args) || this
}
},
processSuperClass: function (superClass) {
var superProto = superClass.prototype
//non-Joose superclasses
if (!superClass.meta) {
var extend = Joose.O.copy(superProto)
extend.isa = Joose.Proto.Empty
// clear potential value in the `extend.constructor` to prevent it from being modified
delete extend.constructor
var meta = new this.defaultSuperClass.meta.constructor(null, extend)
superClass.meta = superProto.meta = meta
meta.c = superClass
}
this.c.prototype = Joose.O.getMutableCopy(superProto)
this.c.superClass = superProto
},
adaptConstructor: function (c) {
c.meta = this
if (!c.hasOwnProperty('toString')) c.toString = function () { return this.meta.name }
},
adaptPrototype: function (proto) {
//this will fix weird semantic of native "constructor" property to more intuitive (idea borrowed from Ext)
proto.constructor = this.c
proto.meta = this
},
addMethod: function (name, func) {
func.SUPER = this.superClass.prototype
//chrome don't allow to redefine the "name" property
func.methodName = name
this.methods[name] = func
this.c.prototype[name] = func
},
addAttribute: function (name, init) {
this.attributes[name] = init
this.c.prototype[name] = init
},
removeMethod : function (name) {
delete this.methods[name]
delete this.c.prototype[name]
},
removeAttribute: function (name) {
delete this.attributes[name]
delete this.c.prototype[name]
},
hasMethod: function (name) {
return Boolean(this.methods[name])
},
hasAttribute: function (name) {
return this.attributes[name] !== undefined
},
hasOwnMethod: function (name) {
return this.hasMethod(name) && this.methods.hasOwnProperty(name)
},
hasOwnAttribute: function (name) {
return this.hasAttribute(name) && this.attributes.hasOwnProperty(name)
},
extend : function (props) {
Joose.O.eachOwn(props, function (value, name) {
if (name != 'meta' && name != 'constructor')
if (Joose.O.isFunction(value) && !value.meta)
this.addMethod(name, value)
else
this.addAttribute(name, value)
}, this)
},
subClassOf : function (classObject, extend) {
return this.subClass(extend, null, classObject)
},
subClass : function (extend, name, classObject) {
extend = extend || {}
extend.isa = classObject || this.c
return new this.constructor(name, extend).c
},
instantiate : function () {
var f = function () {}
f.prototype = this.c.prototype
var obj = new f()
return this.c.apply(obj, arguments) || obj
}
}
//micro bootstraping
Joose.Proto.Class.prototype = Joose.O.getMutableCopy(Joose.Proto.Object.prototype)
Joose.O.extend(Joose.Proto.Class.prototype, bootstrap)
Joose.Proto.Class.prototype.meta = new Joose.Proto.Class('Joose.Proto.Class', bootstrap)
Joose.Proto.Class.meta.addMethod('isa', function (someClass) {
var f = function () {}
f.prototype = this.c.prototype
return new f() instanceof someClass
})
})();
Joose.Managed = Joose.stub()
Joose.Managed.Property = new Joose.Proto.Class('Joose.Managed.Property', {
name : null,
init : null,
value : null,
definedIn : null,
initialize : function (props) {
Joose.Managed.Property.superClass.initialize.call(this, props)
this.computeValue()
},
computeValue : function () {
this.value = this.init
},
//targetClass is still open at this stage
preApply : function (targetClass) {
},
//targetClass is already open at this stage
postUnApply : function (targetClass) {
},
apply : function (target) {
target[this.name] = this.value
},
isAppliedTo : function (target) {
return target[this.name] == this.value
},
unapply : function (from) {
if (!this.isAppliedTo(from)) throw "Unapply of property [" + this.name + "] from [" + from + "] failed"
delete from[this.name]
},
cloneProps : function () {
return {
name : this.name,
init : this.init,
definedIn : this.definedIn
}
},
clone : function (name) {
var props = this.cloneProps()
props.name = name || props.name
return new this.constructor(props)
}
}).c;
Joose.Managed.Property.ConflictMarker = new Joose.Proto.Class('Joose.Managed.Property.ConflictMarker', {
isa : Joose.Managed.Property,
apply : function (target) {
throw new Error("Attempt to apply ConflictMarker [" + this.name + "] to [" + target + "]")
}
}).c;
Joose.Managed.Property.Requirement = new Joose.Proto.Class('Joose.Managed.Property.Requirement', {
isa : Joose.Managed.Property,
apply : function (target) {
if (!target.meta.hasMethod(this.name))
throw new Error("Requirement [" + this.name + "], defined in [" + this.definedIn.definedIn.name + "] is not satisfied for class [" + target + "]")
},
unapply : function (from) {
}
}).c;
Joose.Managed.Property.Attribute = new Joose.Proto.Class('Joose.Managed.Property.Attribute', {
isa : Joose.Managed.Property,
slot : null,
initialize : function () {
Joose.Managed.Property.Attribute.superClass.initialize.apply(this, arguments)
this.slot = this.name
},
apply : function (target) {
target.prototype[ this.slot ] = this.value
},
isAppliedTo : function (target) {
return target.prototype[ this.slot ] == this.value
},
unapply : function (from) {
if (!this.isAppliedTo(from)) throw "Unapply of property [" + this.name + "] from [" + from + "] failed"
delete from.prototype[this.slot]
},
clearValue : function (instance) {
delete instance[ this.slot ]
},
hasValue : function (instance) {
return instance.hasOwnProperty(this.slot)
},
getRawValueFrom : function (instance) {
return instance[ this.slot ]
},
setRawValueTo : function (instance, value) {
instance[ this.slot ] = value
return this
}
}).c;
Joose.Managed.Property.MethodModifier = new Joose.Proto.Class('Joose.Managed.Property.MethodModifier', {
isa : Joose.Managed.Property,
prepareWrapper : function () {
throw "Abstract method [prepareWrapper] of " + this + " was called"
},
apply : function (target) {
var name = this.name
var targetProto = target.prototype
var isOwn = targetProto.hasOwnProperty(name)
var original = targetProto[name]
var superProto = target.meta.superClass.prototype
var originalCall = isOwn ? original : function () {
return superProto[name].apply(this, arguments)
}
var methodWrapper = this.prepareWrapper({
name : name,
modifier : this.value,
isOwn : isOwn,
originalCall : originalCall,
superProto : superProto,
target : target
})
if (isOwn) methodWrapper.__ORIGINAL__ = original
methodWrapper.__CONTAIN__ = this.value
methodWrapper.__METHOD__ = this
this.value.displayName = this.getDisplayName(target)
methodWrapper.displayName = 'internal wrapper'
targetProto[name] = methodWrapper
},
getDisplayName : function (target) {
return target.meta.name + '[' + this.name + ']'
},
isAppliedTo : function (target) {
var targetCont = target.prototype[this.name]
return targetCont && targetCont.__CONTAIN__ == this.value
},
unapply : function (from) {
var name = this.name
var fromProto = from.prototype
var original = fromProto[name].__ORIGINAL__
if (!this.isAppliedTo(from)) throw "Unapply of method [" + name + "] from class [" + from + "] failed"
//if modifier was applied to own method - restore it
if (original)
fromProto[name] = original
//otherwise - just delete it, to reveal the inherited method
else
delete fromProto[name]
}
}).c;
Joose.Managed.Property.MethodModifier.Override = new Joose.Proto.Class('Joose.Managed.Property.MethodModifier.Override', {
isa : Joose.Managed.Property.MethodModifier,
prepareWrapper : function (params) {
var modifier = params.modifier
var originalCall = params.originalCall
var superProto = params.superProto
var superMetaConst = superProto.meta.constructor
//call to Joose.Proto level, require some additional processing
var isCallToProto = (superMetaConst == Joose.Proto.Class || superMetaConst == Joose.Proto.Object) && !(params.isOwn && originalCall.IS_OVERRIDE)
var original = originalCall
if (isCallToProto) original = function () {
var beforeSUPER = this.SUPER
this.SUPER = superProto.SUPER
var res = originalCall.apply(this, arguments)
this.SUPER = beforeSUPER
return res
}
var override = function () {
var beforeSUPER = this.SUPER
this.SUPER = original
var res = modifier.apply(this, arguments)
this.SUPER = beforeSUPER
return res
}
override.IS_OVERRIDE = true
return override
},
getDisplayName : function (target) {
return target.meta.name + '[override ' + this.name + ']'
}
}).c;
Joose.Managed.Property.MethodModifier.Put = new Joose.Proto.Class('Joose.Managed.Property.MethodModifier.Put', {
isa : Joose.Managed.Property.MethodModifier.Override,
prepareWrapper : function (params) {
if (params.isOwn) throw "Method [" + params.name + "] is applying over something [" + params.originalCall + "] in class [" + params.target + "]"
return Joose.Managed.Property.MethodModifier.Put.superClass.prepareWrapper.call(this, params)
},
getDisplayName : function (target) {
return target.meta.name + '[' + this.name + ']'
}
}).c;
Joose.Managed.Property.MethodModifier.After = new Joose.Proto.Class('Joose.Managed.Property.MethodModifier.After', {
isa : Joose.Managed.Property.MethodModifier,
prepareWrapper : function (params) {
var modifier = params.modifier
var originalCall = params.originalCall
return function () {
var res = originalCall.apply(this, arguments)
modifier.apply(this, arguments)
return res
}
},
getDisplayName : function (target) {
return target.meta.name + '[after ' + this.name + ']'
}
}).c;
Joose.Managed.Property.MethodModifier.Before = new Joose.Proto.Class('Joose.Managed.Property.MethodModifier.Before', {
isa : Joose.Managed.Property.MethodModifier,
prepareWrapper : function (params) {
var modifier = params.modifier
var originalCall = params.originalCall
return function () {
modifier.apply(this, arguments)
return originalCall.apply(this, arguments)
}
},
getDisplayName : function (target) {
return target.meta.name + '[before ' + this.name + ']'
}
}).c;
Joose.Managed.Property.MethodModifier.Around = new Joose.Proto.Class('Joose.Managed.Property.MethodModifier.Around', {
isa : Joose.Managed.Property.MethodModifier,
prepareWrapper : function (params) {
var modifier = params.modifier
var originalCall = params.originalCall
var me
var bound = function () {
return originalCall.apply(me, arguments)
}
return function () {
me = this
var boundArr = [ bound ]
boundArr.push.apply(boundArr, arguments)
return modifier.apply(this, boundArr)
}
},
getDisplayName : function (target) {
return target.meta.name + '[around ' + this.name + ']'
}
}).c;
Joose.Managed.Property.MethodModifier.Augment = new Joose.Proto.Class('Joose.Managed.Property.MethodModifier.Augment', {
isa : Joose.Managed.Property.MethodModifier,
prepareWrapper : function (params) {
var AUGMENT = function () {
//populate callstack to the most deep non-augment method
var callstack = []
var self = AUGMENT
do {
callstack.push(self.IS_AUGMENT ? self.__CONTAIN__ : self)
self = self.IS_AUGMENT && (self.__ORIGINAL__ || self.SUPER[self.methodName])
} while (self)
//save previous INNER
var beforeINNER = this.INNER
//create new INNER
this.INNER = function () {
var innerCall = callstack.pop()
return innerCall ? innerCall.apply(this, arguments) : undefined
}
//augment modifier results in hypotetical INNER call of the same method in subclass
var res = this.INNER.apply(this, arguments)
//restore previous INNER chain
this.INNER = beforeINNER
return res
}
AUGMENT.methodName = params.name
AUGMENT.SUPER = params.superProto
AUGMENT.IS_AUGMENT = true
return AUGMENT
},
getDisplayName : function (target) {
return target.meta.name + '[augment ' + this.name + ']'
}
}).c;
Joose.Managed.PropertySet = new Joose.Proto.Class('Joose.Managed.PropertySet', {
isa : Joose.Managed.Property,
properties : null,
propertyMetaClass : Joose.Managed.Property,
initialize : function (props) {
Joose.Managed.PropertySet.superClass.initialize.call(this, props)
//XXX this guards the meta roles :)
this.properties = props.properties || {}
},
addProperty : function (name, props) {
var metaClass = props.meta || this.propertyMetaClass
delete props.meta
props.definedIn = this
props.name = name
return this.properties[name] = new metaClass(props)
},
addPropertyObject : function (object) {
return this.properties[object.name] = object
},
removeProperty : function (name) {
var prop = this.properties[name]
delete this.properties[name]
return prop
},
haveProperty : function (name) {
return this.properties[name] != null
},
haveOwnProperty : function (name) {
return this.haveProperty(name) && this.properties.hasOwnProperty(name)
},
getProperty : function (name) {
return this.properties[name]
},
//includes inherited properties (probably you wants 'eachOwn', which process only "own" (including consumed from Roles) properties)
each : function (func, scope) {
Joose.O.each(this.properties, func, scope || this)
},
eachOwn : function (func, scope) {
Joose.O.eachOwn(this.properties, func, scope || this)
},
//synonym for each
eachAll : function (func, scope) {
this.each(func, scope)
},
cloneProps : function () {
var props = Joose.Managed.PropertySet.superClass.cloneProps.call(this)
props.propertyMetaClass = this.propertyMetaClass
return props
},
clone : function (name) {
var clone = this.cleanClone(name)
clone.properties = Joose.O.copyOwn(this.properties)
return clone
},
cleanClone : function (name) {
var props = this.cloneProps()
props.name = name || props.name
return new this.constructor(props)
},
alias : function (what) {
var props = this.properties
Joose.O.each(what, function (aliasName, originalName) {
var original = props[originalName]
if (original) this.addPropertyObject(original.clone(aliasName))
}, this)
},
exclude : function (what) {
var props = this.properties
Joose.A.each(what, function (name) {
delete props[name]
})
},
beforeConsumedBy : function () {
},
flattenTo : function (target) {
var targetProps = target.properties
this.eachOwn(function (property, name) {
var targetProperty = targetProps[name]
if (targetProperty instanceof Joose.Managed.Property.ConflictMarker) return
if (!targetProps.hasOwnProperty(name) || targetProperty == null) {
target.addPropertyObject(property)
return
}
if (targetProperty == property) return
target.removeProperty(name)
target.addProperty(name, {
meta : Joose.Managed.Property.ConflictMarker
})
}, this)
},
composeTo : function (target) {
this.eachOwn(function (property, name) {
if (!target.haveOwnProperty(name)) target.addPropertyObject(property)
})
},
composeFrom : function () {
if (!arguments.length) return
var flattening = this.cleanClone()
Joose.A.each(arguments, function (arg) {
var isDescriptor = !(arg instanceof Joose.Managed.PropertySet)
var propSet = isDescriptor ? arg.propertySet : arg
propSet.beforeConsumedBy(this, flattening)
if (isDescriptor) {
if (arg.alias || arg.exclude) propSet = propSet.clone()
if (arg.alias) propSet.alias(arg.alias)
if (arg.exclude) propSet.exclude(arg.exclude)
}
propSet.flattenTo(flattening)
}, this)
flattening.composeTo(this)
},
preApply : function (target) {
this.eachOwn(function (property) {
property.preApply(target)
})
},
apply : function (target) {
this.eachOwn(function (property) {
property.apply(target)
})
},
unapply : function (from) {
this.eachOwn(function (property) {
property.unapply(from)
})
},
postUnApply : function (target) {
this.eachOwn(function (property) {
property.postUnApply(target)
})
}
}).c
;
var __ID__ = 1
Joose.Managed.PropertySet.Mutable = new Joose.Proto.Class('Joose.Managed.PropertySet.Mutable', {
isa : Joose.Managed.PropertySet,
ID : null,
derivatives : null,
opened : null,
composedFrom : null,
initialize : function (props) {
Joose.Managed.PropertySet.Mutable.superClass.initialize.call(this, props)
//initially opened
this.opened = 1
this.derivatives = {}
this.ID = __ID__++
this.composedFrom = []
},
addComposeInfo : function () {
this.ensureOpen()
Joose.A.each(arguments, function (arg) {
this.composedFrom.push(arg)
var propSet = arg instanceof Joose.Managed.PropertySet ? arg : arg.propertySet
propSet.derivatives[this.ID] = this
}, this)
},
removeComposeInfo : function () {
this.ensureOpen()
Joose.A.each(arguments, function (arg) {
var i = 0
while (i < this.composedFrom.length) {
var propSet = this.composedFrom[i]
propSet = propSet instanceof Joose.Managed.PropertySet ? propSet : propSet.propertySet
if (arg == propSet) {
delete propSet.derivatives[this.ID]
this.composedFrom.splice(i, 1)
} else i++
}
}, this)
},
ensureOpen : function () {
if (!this.opened) throw "Mutation of closed property set: [" + this.name + "]"
},
addProperty : function (name, props) {
this.ensureOpen()
return Joose.Managed.PropertySet.Mutable.superClass.addProperty.call(this, name, props)
},
addPropertyObject : function (object) {
this.ensureOpen()
return Joose.Managed.PropertySet.Mutable.superClass.addPropertyObject.call(this, object)
},
removeProperty : function (name) {
this.ensureOpen()
return Joose.Managed.PropertySet.Mutable.superClass.removeProperty.call(this, name)
},
composeFrom : function () {
this.ensureOpen()
return Joose.Managed.PropertySet.Mutable.superClass.composeFrom.apply(this, this.composedFrom)
},
open : function () {
this.opened++
if (this.opened == 1) {
Joose.O.each(this.derivatives, function (propSet) {
propSet.open()
})
this.deCompose()
}
},
close : function () {
if (!this.opened) throw "Unmatched 'close' operation on property set: [" + this.name + "]"
if (this.opened == 1) {
this.reCompose()
Joose.O.each(this.derivatives, function (propSet) {
propSet.close()
})
}
this.opened--
},
reCompose : function () {
this.composeFrom()
},
deCompose : function () {
this.eachOwn(function (property, name) {
if (property.definedIn != this) this.removeProperty(name)
}, this)
}
}).c;
Joose.Managed.StemElement = function () { throw "Modules may not be instantiated." }
Joose.Managed.StemElement.Attributes = new Joose.Proto.Class('Joose.Managed.StemElement.Attributes', {
isa : Joose.Managed.PropertySet.Mutable,
propertyMetaClass : Joose.Managed.Property.Attribute
}).c
;
Joose.Managed.StemElement.Methods = new Joose.Proto.Class('Joose.Managed.StemElement.Methods', {
isa : Joose.Managed.PropertySet.Mutable,
propertyMetaClass : Joose.Managed.Property.MethodModifier.Put,
preApply : function () {
},
postUnApply : function () {
}
}).c;
Joose.Managed.StemElement.Requirements = new Joose.Proto.Class('Joose.Managed.StemElement.Requirements', {
isa : Joose.Managed.PropertySet.Mutable,
propertyMetaClass : Joose.Managed.Property.Requirement,
alias : function () {
},
exclude : function () {
},
flattenTo : function (target) {
this.each(function (property, name) {
if (!target.haveProperty(name)) target.addPropertyObject(property)
})
},
composeTo : function (target) {
this.flattenTo(target)
},
preApply : function () {
},
postUnApply : function () {
}
}).c;
Joose.Managed.StemElement.MethodModifiers = new Joose.Proto.Class('Joose.Managed.StemElement.MethodModifiers', {
isa : Joose.Managed.PropertySet.Mutable,
propertyMetaClass : null,
addProperty : function (name, props) {
var metaClass = props.meta
delete props.meta
props.definedIn = this
props.name = name
var modifier = new metaClass(props)
var properties = this.properties
if (!properties[name]) properties[ name ] = []
properties[name].push(modifier)
return modifier
},
addPropertyObject : function (object) {
var name = object.name
var properties = this.properties
if (!properties[name]) properties[name] = []
properties[name].push(object)
return object
},
//remove only the last modifier
removeProperty : function (name) {
if (!this.haveProperty(name)) return undefined
var properties = this.properties
var modifier = properties[ name ].pop()
//if all modifiers were removed - clearing the properties
if (!properties[name].length) Joose.Managed.StemElement.MethodModifiers.superClass.removeProperty.call(this, name)
return modifier
},
alias : function () {
},
exclude : function () {
},
flattenTo : function (target) {
var targetProps = target.properties
this.each(function (modifiersArr, name) {
var targetModifiersArr = targetProps[name]
if (targetModifiersArr == null) targetModifiersArr = targetProps[name] = []
Joose.A.each(modifiersArr, function (modifier) {
if (!Joose.A.exists(targetModifiersArr, modifier)) targetModifiersArr.push(modifier)
})
})
},
composeTo : function (target) {
this.flattenTo(target)
},
deCompose : function () {
this.each(function (modifiersArr, name) {
var i = 0
while (i < modifiersArr.length)
if (modifiersArr[i].definedIn != this)
modifiersArr.splice(i, 1)
else
i++
})
},
preApply : function (target) {
},
postUnApply : function (target) {
},
apply : function (target) {
this.each(function (modifiersArr, name) {
Joose.A.each(modifiersArr, function (modifier) {
modifier.apply(target)
})
})
},
unapply : function (from) {
this.each(function (modifiersArr, name) {
for (var i = modifiersArr.length - 1; i >=0 ; i--) modifiersArr[i].unapply(from)
})
}
}).c;
Joose.Managed.PropertySet.Composition = new Joose.Proto.Class('Joose.Managed.PropertySet.Composition', {
isa : Joose.Managed.PropertySet.Mutable,
propertyMetaClass : Joose.Managed.PropertySet.Mutable,
processOrder : null,
each : function (func, scope) {
var props = this.properties
var scope = scope || this
Joose.A.each(this.processOrder, function (name) {
func.call(scope, props[name], name)
})
},
eachR : function (func, scope) {
var props = this.properties
var scope = scope || this
Joose.A.eachR(this.processOrder, function (name) {
func.call(scope, props[name], name)
})
// var props = this.properties
// var processOrder = this.processOrder
//
// for(var i = processOrder.length - 1; i >= 0; i--)
// func.call(scope || this, props[ processOrder[i] ], processOrder[i])
},
clone : function (name) {
var clone = this.cleanClone(name)
this.each(function (property) {
clone.addPropertyObject(property.clone())
})
return clone
},
alias : function (what) {
this.each(function (property) {
property.alias(what)
})
},
exclude : function (what) {
this.each(function (property) {
property.exclude(what)
})
},
flattenTo : function (target) {
var targetProps = target.properties
this.each(function (property, name) {
var subTarget = targetProps[name] || target.addProperty(name, {
meta : property.constructor
})
property.flattenTo(subTarget)
})
},
composeTo : function (target) {
var targetProps = target.properties
this.each(function (property, name) {
var subTarget = targetProps[name] || target.addProperty(name, {
meta : property.constructor
})
property.composeTo(subTarget)
})
},
deCompose : function () {
this.eachR(function (property) {
property.open()
})
Joose.Managed.PropertySet.Composition.superClass.deCompose.call(this)
},
reCompose : function () {
Joose.Managed.PropertySet.Composition.superClass.reCompose.call(this)
this.each(function (property) {
property.close()
})
},
unapply : function (from) {
this.eachR(function (property) {
property.unapply(from)
})
}
}).c
;
Joose.Managed.Stem = new Joose.Proto.Class('Joose.Managed.Stem', {
isa : Joose.Managed.PropertySet.Composition,
targetMeta : null,
attributesMC : Joose.Managed.StemElement.Attributes,
methodsMC : Joose.Managed.StemElement.Methods,
requirementsMC : Joose.Managed.StemElement.Requirements,
methodsModifiersMC : Joose.Managed.StemElement.MethodModifiers,
processOrder : [ 'attributes', 'methods', 'requirements', 'methodsModifiers' ],
initialize : function (props) {
Joose.Managed.Stem.superClass.initialize.call(this, props)
var targetMeta = this.targetMeta
this.addProperty('attributes', {
meta : this.attributesMC,
//it can be no 'targetMeta' in clones
properties : targetMeta ? targetMeta.attributes : {}
})
this.addProperty('methods', {
meta : this.methodsMC,
properties : targetMeta ? targetMeta.methods : {}
})
this.addProperty('requirements', {
meta : this.requirementsMC
})
this.addProperty('methodsModifiers', {
meta : this.methodsModifiersMC
})
},
reCompose : function () {
var c = this.targetMeta.c
this.preApply(c)
Joose.Managed.Stem.superClass.reCompose.call(this)
this.apply(c)
},
deCompose : function () {
var c = this.targetMeta.c
this.unapply(c)
Joose.Managed.Stem.superClass.deCompose.call(this)
this.postUnApply(c)
}
}).c
;
Joose.Managed.Builder = new Joose.Proto.Class('Joose.Managed.Builder', {
targetMeta : null,
_buildStart : function (targetMeta, props) {
targetMeta.stem.open()
Joose.A.each([ 'trait', 'traits', 'removeTrait', 'removeTraits', 'does', 'doesnot', 'doesnt' ], function (builder) {
if (props[builder]) {
this[builder](targetMeta, props[builder])
delete props[builder]
}
}, this)
},
_extend : function (props) {
if (Joose.O.isEmpty(props)) return
var targetMeta = this.targetMeta
this._buildStart(targetMeta, props)
Joose.O.eachOwn(props, function (value, name) {
var handler = this[name]
if (!handler) throw new Error("Unknown builder [" + name + "] was used during extending of [" + targetMeta.c + "]")
handler.call(this, targetMeta, value)
}, this)
this._buildComplete(targetMeta, props)
},
_buildComplete : function (targetMeta, props) {
targetMeta.stem.close()
},
methods : function (targetMeta, info) {
Joose.O.eachOwn(info, function (value, name) {
targetMeta.addMethod(name, value)
})
},
removeMethods : function (targetMeta, info) {
Joose.A.each(info, function (name) {
targetMeta.removeMethod(name)
})
},
have : function (targetMeta, info) {
Joose.O.eachOwn(info, function (value, name) {
targetMeta.addAttribute(name, value)
})
},
havenot : function (targetMeta, info) {
Joose.A.each(info, function (name) {
targetMeta.removeAttribute(name)
})
},
havent : function (targetMeta, info) {
this.havenot(targetMeta, info)
},
after : function (targetMeta, info) {
Joose.O.each(info, function (value, name) {
targetMeta.addMethodModifier(name, value, Joose.Managed.Property.MethodModifier.After)
})
},
before : function (targetMeta, info) {
Joose.O.each(info, function (value, name) {
targetMeta.addMethodModifier(name, value, Joose.Managed.Property.MethodModifier.Before)
})
},
override : function (targetMeta, info) {
Joose.O.each(info, function (value, name) {
targetMeta.addMethodModifier(name, value, Joose.Managed.Property.MethodModifier.Override)
})
},
around : function (targetMeta, info) {
Joose.O.each(info, function (value, name) {
targetMeta.addMethodModifier(name, value, Joose.Managed.Property.MethodModifier.Around)
})
},
augment : function (targetMeta, info) {
Joose.O.each(info, function (value, name) {
targetMeta.addMethodModifier(name, value, Joose.Managed.Property.MethodModifier.Augment)
})
},
removeModifier : function (targetMeta, info) {
Joose.A.each(info, function (name) {
targetMeta.removeMethodModifier(name)
})
},
does : function (targetMeta, info) {
Joose.A.each(Joose.O.wantArray(info), function (desc) {
targetMeta.addRole(desc)
})
},
doesnot : function (targetMeta, info) {
Joose.A.each(Joose.O.wantArray(info), function (desc) {
targetMeta.removeRole(desc)
})
},
doesnt : function (targetMeta, info) {
this.doesnot(targetMeta, info)
},
trait : function () {
this.traits.apply(this, arguments)
},
traits : function (targetMeta, info) {
if (targetMeta.firstPass) return
if (!targetMeta.meta.isDetached) throw "Can't apply trait to not detached class"
targetMeta.meta.extend({
does : info
})
},
removeTrait : function () {
this.removeTraits.apply(this, arguments)
},
removeTraits : function (targetMeta, info) {
if (!targetMeta.meta.isDetached) throw "Can't remove trait from not detached class"
targetMeta.meta.extend({
doesnot : info
})
},
name : function (targetMeta, name) {
targetMeta.name = name
}
}).c;
Joose.Managed.Class = new Joose.Proto.Class('Joose.Managed.Class', {
isa : Joose.Proto.Class,
stem : null,
stemClass : Joose.Managed.Stem,
stemClassCreated : false,
builder : null,
builderClass : Joose.Managed.Builder,
builderClassCreated : false,
isDetached : false,
firstPass : true,
// a special instance, which, when passed as 1st argument to constructor, signifies that constructor should
// skips traits processing for this instance
skipTraitsAnchor : {},
//build for metaclasses - collects traits from roles
BUILD : function () {
var sup = Joose.Managed.Class.superClass.BUILD.apply(this, arguments)
var props = sup.__extend__
var traits = Joose.O.wantArray(props.trait || props.traits || [])
delete props.trait
delete props.traits
Joose.A.each(Joose.O.wantArray(props.does || []), function (arg) {
var role = (arg.meta instanceof Joose.Managed.Class) ? arg : arg.role
if (role.meta.meta.isDetached) traits.push(role.meta.constructor)
})
if (traits.length) props.traits = traits
return sup
},
initInstance : function (instance, props) {
Joose.O.each(this.attributes, function (attribute, name) {
if (