Comparing version 1.1.1 to 1.1.2
@@ -13,33 +13,34 @@ (function(factory){ | ||
function Node(instance, name){ | ||
this.nb = this.pb = this.na = this.pa = this.nf = this.pf = this; | ||
this.i = instance; | ||
this.n = name; | ||
this.next_before = this.prev_before = this.next_after = this.prev_after = | ||
this.next_around = this.prev_around = this; | ||
this.instance = instance; | ||
this.name = name; | ||
} | ||
var p = Node.prototype = { | ||
a: function(b, a, f, o){ | ||
var t = new Node(this.i, this.n); | ||
t.p = this; | ||
t.b = b; | ||
this._a("b", t); | ||
t.a = a; | ||
this._a("a", t); | ||
t.f = f; | ||
this._a("f", t, o); | ||
t.o = o; | ||
if(o){ t.f = advise._f(o, t.pf.f, this); } | ||
return t; | ||
add: function(before, after, around, original){ | ||
var node = new Node(this.instance, this.name); | ||
node.parent = this; | ||
node.before = before; | ||
this._add("before", node); | ||
node.after = after; | ||
this._add("after", node); | ||
node.around = around; | ||
this._add("around", node, original); | ||
node.original = original; | ||
if(original){ node.around = advise._instantiate(original, node.prev_around.around, this); } | ||
return node; | ||
}, | ||
_a: function(topic, node, flag){ | ||
_add: function(topic, node, flag){ | ||
if(node[topic] || flag){ | ||
var n = "n" + topic, p = "p" + topic; | ||
var n = "next_" + topic, p = "prev_" + topic; | ||
(node[p] = this[p])[n] = (node[n] = this)[p] = node; | ||
} | ||
}, | ||
r: function(node){ | ||
this._r("b", node); | ||
this._r("a", node); | ||
this._r("f", node); | ||
remove: function(node){ | ||
this._remove("before", node); | ||
this._remove("after", node); | ||
this._remove("around", node); | ||
}, | ||
_r: function(topic, node){ | ||
var n = "n" + topic, p = "p" + topic; | ||
_remove: function(topic, node){ | ||
var n = "next_" + topic, p = "prev_" + topic; | ||
node[n][p] = node[p]; | ||
@@ -49,12 +50,12 @@ node[p][n] = node[n]; | ||
destroy: function(){ | ||
var f = this.pf.f, t = this.nf, p = this.p; | ||
this.r(this); | ||
var around = this.prev_around.around, t = this.next_around, parent = this.parent; | ||
this.remove(this); | ||
if(t !== this){ | ||
for(; t !== p; f = t.f, t = t.nf){ | ||
if(t.o){ | ||
t.f = advise._f(t.o, f, this); | ||
for(; t !== parent; around = t.around, t = t.next_around){ | ||
if(t.original){ | ||
t.around = advise._instantiate(t.original, around, this); | ||
} | ||
} | ||
} | ||
this.i = 0; | ||
this.instance = 0; | ||
} | ||
@@ -64,20 +65,21 @@ }; | ||
function makeAOPStub(x){ | ||
function makeAOPStub(node){ | ||
var f = function(){ | ||
var p, r, t = this, a = arguments; | ||
var p, r, t = this, a = arguments, thrown; | ||
// running the before chain | ||
for(p = x.pb; p !== x; p = p.pb){ | ||
p.b.apply(t, a); | ||
for(p = node.prev_before; p !== node; p = p.prev_before){ | ||
p.before.apply(t, a); | ||
} | ||
// running the around chain | ||
try{ | ||
if(x.pf !== x){ r = x.pf.f.apply(t, a); } | ||
if(node.prev_around !== node){ r = node.prev_around.around.apply(t, a); } | ||
}catch(e){ | ||
r = e; | ||
thrown = true; | ||
} | ||
// running the after chain | ||
for(p = x.na; p !== x; p = p.na){ | ||
p.a.call(t, a, r); | ||
for(p = node.next_after; p !== node; p = p.next_after){ | ||
p.after.call(t, a, r); | ||
} | ||
if(r instanceof Error){ | ||
if(thrown){ | ||
throw r; | ||
@@ -87,3 +89,3 @@ } | ||
}; | ||
f.adviceNode = x; | ||
f.adviceNode = node; | ||
return f; | ||
@@ -93,27 +95,27 @@ } | ||
function advise(instance, name, advice){ | ||
var f = instance[name], a; | ||
var f = instance[name], node; | ||
if(f && f.adviceNode && f.adviceNode instanceof Node){ | ||
a = f.adviceNode; | ||
node = f.adviceNode; | ||
}else{ | ||
a = new Node(instance, name); | ||
node = new Node(instance, name); | ||
if(f && f.advices){ | ||
f = f.advices; | ||
a.a(f.b, f.a, f.f); | ||
node.add(f.before, f.after, f.around); | ||
}else{ | ||
a.a(0, 0, f); | ||
node.add(0, 0, f); | ||
} | ||
instance[name] = makeAOPStub(a); | ||
instance[name] = makeAOPStub(node); | ||
} | ||
if(typeof advice == "function"){ advice = advice(name, instance); } | ||
return a.a(advice.before, advice.after, 0, advice.around); | ||
return node.add(advice.before, advice.after, 0, advice.around); | ||
} | ||
advise.before = function(instance, name, f){ return advise(instance, name, {before: f}); }; | ||
advise.after = function(instance, name, f){ return advise(instance, name, {after: f}); }; | ||
advise.after = function(instance, name, f){ return advise(instance, name, {after: f}); }; | ||
advise.around = function(instance, name, f){ return advise(instance, name, {around: f}); }; | ||
advise.Node = Node; | ||
advise._f = function(f, a, node){ return f(a); }; | ||
advise._instantiate = function(advice, previous, node){ return advice(previous); }; | ||
return advise; | ||
}); |
63
dcl.js
@@ -17,26 +17,27 @@ (function(factory){ | ||
constructor: function(){ | ||
this.b = this.f.before; | ||
this.a = this.f.after; | ||
this.f = this.f.around; | ||
this.before = this.around.before; | ||
this.after = this.around.after; | ||
this.around = this.around.around; | ||
} | ||
}); | ||
function advise(f){ return dcl._mk(f, Advice); } | ||
function advise(advice){ return dcl._makeSuper(advice, Advice); } | ||
function makeAOPStub(b, a, f){ | ||
var sb = b || nop, | ||
sa = a || nop, | ||
sf = f || nop, | ||
x = function(){ | ||
var r; | ||
function makeAOPStub(before, after, around){ | ||
var beforeChain = before || nop, | ||
afterChain = after || nop, | ||
aroundChain = around || nop, | ||
stub = function(){ | ||
var r, thrown; | ||
// running the before chain | ||
sb.apply(this, arguments); | ||
beforeChain.apply(this, arguments); | ||
// running the around chain | ||
try{ | ||
r = sf.apply(this, arguments); | ||
r = aroundChain.apply(this, arguments); | ||
}catch(e){ | ||
r = e; | ||
thrown = true; | ||
} | ||
// running the after chain | ||
sa.call(this, arguments, r); | ||
if(r instanceof Error){ | ||
afterChain.call(this, arguments, r); | ||
if(thrown){ | ||
throw r; | ||
@@ -46,4 +47,4 @@ } | ||
}; | ||
x.advices = {b: b, a: a, f: f}; | ||
return x; | ||
stub.advices = {before: before, after: after, around: around}; | ||
return stub; | ||
} | ||
@@ -53,9 +54,9 @@ | ||
return function(ctor, name){ | ||
var m = ctor._m, c; | ||
if(m){ | ||
c = (+m.w[name] || 0); | ||
if(c && c != id){ | ||
dcl._e("set chaining", name, ctor, id, c); | ||
var meta = ctor._meta, rule; | ||
if(meta){ | ||
rule = +meta.weaver[name] || 0; | ||
if(rule && rule != id){ | ||
dcl._error("set chaining", name, ctor, id, rule); | ||
} | ||
m.w[name] = id; | ||
meta.weaver[name] = id; | ||
} | ||
@@ -71,3 +72,3 @@ }; | ||
before: function(f){ return dcl.advise({before: f}); }, | ||
after: function(f){ return dcl.advise({after: f}); }, | ||
after: function(f){ return dcl.advise({after: f}); }, | ||
around: dcl.superCall, | ||
@@ -81,5 +82,5 @@ // chains | ||
} | ||
var t = o.constructor._m, i; | ||
var t = o.constructor._meta, i; | ||
if(t){ | ||
for(t = t.b, i = t.length - 1; i >= 0; --i){ | ||
for(t = t.bases, i = t.length - 1; i >= 0; --i){ | ||
if(t[i] === ctor){ | ||
@@ -93,8 +94,8 @@ return true; | ||
// protected API starts with _ (don't use it!) | ||
_sb: /*generic stub*/ function(id, bases, name, chains){ | ||
var f = chains[name] = dcl._ec(bases, name, "f"), | ||
b = dcl._ec(bases, name, "b").reverse(), | ||
a = dcl._ec(bases, name, "a"); | ||
f = id ? dcl._st(f, id == 1 ? function(f){ return dcl._sc(f.reverse()); } : dcl._sc, name) : dcl._ss(f, name); | ||
return !b.length && !a.length ? f || function(){} : makeAOPStub(dcl._sc(b), dcl._sc(a), f); | ||
_stub: /*generic stub*/ function(id, bases, name, chains){ | ||
var f = chains[name] = dcl._extractChain(bases, name, "around"), | ||
b = dcl._extractChain(bases, name, "before").reverse(), | ||
a = dcl._extractChain(bases, name, "after"); | ||
f = id ? dcl._stubChainSuper(f, id == 1 ? function(f){ return dcl._stubChain(f.reverse()); } : dcl._stubChain, name) : dcl._stubSuper(f, name); | ||
return !b.length && !a.length ? f || function(){} : makeAOPStub(dcl._stubChain(b), dcl._stubChain(a), f); | ||
} | ||
@@ -101,0 +102,0 @@ }); |
86
debug.js
@@ -38,4 +38,4 @@ (function(factory){ | ||
var noDecls = "(specify 'declaredClass' string in your classes to get better diagnostics)"; | ||
advise.around(dcl, "_e", function(/*sup*/){ | ||
var noDecls = " (specify 'declaredClass' string in your classes to get better diagnostics)"; | ||
advise.around(dcl, "_error", function(/*sup*/){ | ||
return function(reason, a1, a2, a3, a4, a5){ | ||
@@ -51,3 +51,3 @@ var cName, someUnknown, i, base, name, names = [], c = {}; | ||
if(!name){ | ||
name = "UNNAMED_" + base._u; | ||
name = "UNNAMED_" + base._uniqueId; | ||
someUnknown = true; | ||
@@ -67,5 +67,5 @@ } | ||
someUnknown = !(cName && name); | ||
throw new ChainingError("dcl: conflicting chain directives from bases found in: " + (cName || ("UNNAMED_" + a2._u)) + | ||
throw new ChainingError("dcl: conflicting chain directives from bases found in: " + (cName || ("UNNAMED_" + a2._uniqueId)) + | ||
", method: " + a1 + " - it was " + chainName(a3) + " yet " + | ||
(name || ("UNNAMED_" + a4._u)) + " sets it to " + chainName(a5) + | ||
(name || ("UNNAMED_" + a4._uniqueId)) + " sets it to " + chainName(a5) + | ||
(someUnknown ? noDecls : "")); | ||
@@ -75,3 +75,3 @@ case "set chaining": | ||
someUnknown = !cName; | ||
throw new SetChainingError("dcl: attempt to set conflicting chain directives in: " + (cName || ("UNNAMED_" + a2._u)) + | ||
throw new SetChainingError("dcl: attempt to set conflicting chain directives in: " + (cName || ("UNNAMED_" + a2._uniqueId)) + | ||
", method: " + a1 + " - it was " + chainName(a4) + " yet being changed to " + chainName(a3) + | ||
@@ -83,3 +83,3 @@ (someUnknown ? noDecls : "")); | ||
throw new SuperCallError("dcl: argument of around advice or supercall decorator should be a function in: " + | ||
(cName || ("UNNAMED_" + a1._u)) + ", method: " + a2 + (someUnknown ? noDecls : "")); | ||
(cName || ("UNNAMED_" + a1._uniqueId)) + ", method: " + a2 + (someUnknown ? noDecls : "")); | ||
case "wrong super": | ||
@@ -89,3 +89,3 @@ cName = a1.prototype.hasOwnProperty("declaredClass") && a1.prototype.declaredClass; | ||
throw new SuperError("dcl: super method should be a function in: " + | ||
(cName || ("UNNAMED_" + a1._u)) + ", method: " + a2 + (someUnknown ? noDecls : "")); | ||
(cName || ("UNNAMED_" + a1._uniqueId)) + ", method: " + a2 + (someUnknown ? noDecls : "")); | ||
case "wrong super result": | ||
@@ -95,3 +95,3 @@ cName = a1.prototype.hasOwnProperty("declaredClass") && a1.prototype.declaredClass; | ||
throw new SuperResultError("dcl: around advice or supercall should return a function in: " + | ||
(cName || ("UNNAMED_" + a1._u)) + ", method: " + a2 + (someUnknown ? noDecls : "")); | ||
(cName || ("UNNAMED_" + a1._uniqueId)) + ", method: " + a2 + (someUnknown ? noDecls : "")); | ||
} | ||
@@ -102,6 +102,6 @@ throw new DclError("dcl: " + reason); | ||
advise.after(dcl, "_p", function(args, ctor){ | ||
advise.after(dcl, "_postprocess", function(args, ctor){ | ||
// validate that chaining is consistent | ||
var meta = ctor._m, weaver = meta.w, bases = meta.b, | ||
name, chain, base, i, c; | ||
var meta = ctor._meta, weaver = meta.weaver, bases = meta.bases, | ||
name, chain, base, i, rule; | ||
dcl.allKeys(weaver).forEach(function(name){ | ||
@@ -111,7 +111,7 @@ chain = (+weaver[name] || 0); | ||
base = bases[i]; | ||
meta = base._m; | ||
meta = base._meta; | ||
if(meta){ | ||
c = (+meta.w[name] || 0); | ||
if(chain != c && (!chain || c)){ | ||
dcl._e("chain", name, ctor, chain, base, c); | ||
rule = (+meta.weaver[name] || 0); | ||
if(chain != rule && (!chain || rule)){ | ||
dcl._error("chain", name, ctor, chain, base, rule); | ||
} | ||
@@ -123,15 +123,15 @@ } | ||
advise.around(dcl, "_f", function(/*sup*/){ | ||
return function(f, a, n){ | ||
if(!f || !f.spr || typeof f.spr.f != "function"){ | ||
dcl._e("wrong super call", f.ctr, n); | ||
advise.around(dcl, "_instantiate", function(/*sup*/){ | ||
return function(advice, previous, node){ | ||
if(!advice || !advice.spr || typeof advice.spr.around != "function"){ | ||
dcl._error("wrong super call", advice.ctr, node); | ||
} | ||
if(a && typeof a != "function"){ | ||
dcl._e("wrong super", f.ctr, n); | ||
if(previous && typeof previous != "function"){ | ||
dcl._error("wrong super", advice.ctr, node); | ||
} | ||
var t = f.spr.f(a); | ||
var t = advice.spr.around(previous); | ||
if(typeof t != "function"){ | ||
dcl._e("wrong super result", f.ctr, n); | ||
dcl._error("wrong super result", advice.ctr, node); | ||
} | ||
t.ctr = f.ctr; | ||
t.ctr = advice.ctr; | ||
return t; | ||
@@ -141,14 +141,14 @@ }; | ||
advise(advise, "_f", { | ||
before: function(f, a, n){ | ||
if(typeof f != "function"){ | ||
dcl._e("wrong super call", n.i.constructor, n.n); | ||
advise(advise, "_instantiate", { | ||
before: function(advice, previous, node){ | ||
if(typeof advice != "function"){ | ||
dcl._error("wrong super call", node.instance.constructor, node.name); | ||
} | ||
if(a && typeof a != "function"){ | ||
dcl._e("wrong super", n.i.constructor, n.n); | ||
if(previous && typeof previous != "function"){ | ||
dcl._error("wrong super", node.instance.constructor, node.name); | ||
} | ||
}, | ||
after: function(a, f){ | ||
if(typeof f != "function"){ | ||
dcl._e("wrong super result", a[2].i.constructor, a[2].n); | ||
after: function(a, result){ | ||
if(typeof result != "function"){ | ||
dcl._error("wrong super result", a[2].instance.constructor, a[2].name); | ||
} | ||
@@ -159,3 +159,3 @@ } | ||
function logCtor(ctor){ | ||
var meta = ctor._m; | ||
var meta = ctor._meta; | ||
if(!meta){ | ||
@@ -165,3 +165,3 @@ console.log("*** class does not have meta information compatible with dcl"); | ||
} | ||
var weaver = meta.w, bases = meta.b, chains = meta.c, names = [], base, name, someUnknown, i; | ||
var weaver = meta.weaver, bases = meta.bases, chains = meta.chains, names = [], base, name, someUnknown, i; | ||
for(i = 0; i < bases.length; ++i){ | ||
@@ -171,3 +171,3 @@ base = bases[i]; | ||
if(!name){ | ||
name = "UNNAMED_" + (base.hasOwnProperty("_u") ? base._u : ""); | ||
name = "UNNAMED_" + (base.hasOwnProperty("_uniqueId") ? base._uniqueId : ""); | ||
someUnknown = true; | ||
@@ -189,5 +189,5 @@ } | ||
if(hasStub){ | ||
var b = dcl._ec(bases, name, "b").length, | ||
f = dcl._ec(bases, name, "f").length, | ||
a = dcl._ec(bases, name, "a").length; | ||
var b = dcl._extractChain(bases, name, "b").length, | ||
f = dcl._extractChain(bases, name, "f").length, | ||
a = dcl._extractChain(bases, name, "a").length; | ||
} | ||
@@ -203,4 +203,4 @@ console.log(" class method " + name + " is " + chainName(i) + | ||
function countAdvices(node, chain){ | ||
for(var c = 0, p = node[chain]; p != node; p = p[chain], ++c); | ||
return c; | ||
for(var counter = 0, p = node[chain]; p != node; p = p[chain], ++counter); | ||
return counter; | ||
} | ||
@@ -217,3 +217,3 @@ | ||
if(!name){ | ||
name = "UNNAMED_" + (base.hasOwnProperty("_u") ? base._u : ""); | ||
name = "UNNAMED_" + (base.hasOwnProperty("_uniqueId") ? base._uniqueId : ""); | ||
} | ||
@@ -220,0 +220,0 @@ console.log("*** object of class " + name); |
@@ -13,5 +13,5 @@ (function(factory){ | ||
function inherited(ctor, name, args){ | ||
var c = arguments.length < 3 && ctor.callee, // c is truthy if in non-strict mode. | ||
f = get.call(this, c ? c.ctr : ctor, c ? c.nom : name); | ||
if(f){ return f.apply(this, c ? ctor || name : args); } | ||
var callee = arguments.length < 3 && ctor.callee, // callee is truthy if in non-strict mode. | ||
f = get.call(this, callee ? callee.ctr : ctor, callee ? callee.nom : name); | ||
if(f){ return f.apply(this, callee ? ctor || name : args); } | ||
// intentionally no return | ||
@@ -21,9 +21,9 @@ } | ||
function get(ctor, name){ | ||
var meta = this.constructor._m, bases, base, i, l; | ||
if(+meta.w[name]){ | ||
var meta = this.constructor._meta, bases, base, i, l; | ||
if(+meta.weaver[name]){ | ||
return; // return undefined | ||
} | ||
if(meta){ | ||
if(meta.c.hasOwnProperty(name)){ | ||
if((bases = meta.c[name])){ // intentional assignment | ||
if(meta.chains.hasOwnProperty(name)){ | ||
if((bases = meta.chains[name])){ // intentional assignment | ||
for(i = bases.length - 1; i >= 0; --i){ | ||
@@ -38,3 +38,3 @@ base = bases[i]; | ||
} | ||
for(bases = meta.b, i = bases.length - 1; i >= 0; --i){ | ||
for(bases = meta.bases, i = bases.length - 1; i >= 0; --i){ | ||
if(bases[i] === ctor){ | ||
@@ -46,4 +46,4 @@ break; | ||
for(++i, l = bases.length; i < l; ++i){ | ||
if((meta = (base = bases[i])._m)){ // intentional assignments | ||
if((meta = meta.h).hasOwnProperty(name)){ // intentional assignment | ||
if((meta = (base = bases[i])._meta)){ // intentional assignments | ||
if((meta = meta.ownProps).hasOwnProperty(name)){ // intentional assignment | ||
return meta[name]; | ||
@@ -60,9 +60,9 @@ } | ||
advise.after(dcl, "_p", function(args, ctor){ | ||
advise.after(dcl, "_postprocess", function(args, ctor){ | ||
// decorate all methods with necessary nom/ctr variables | ||
var bases = ctor._m.b, i = bases.length - 1, base, meta, name, f; | ||
var bases = ctor._meta.bases, i = bases.length - 1, base, meta, name, f; | ||
for(; i >= 0; --i){ | ||
base = bases[i]; | ||
if((meta = base._m)){ // intentional assignment | ||
meta = meta.h; | ||
if((meta = base._meta)){ // intentional assignment | ||
meta = meta.ownProps; | ||
dcl.allKeys(meta).some(function(name){ | ||
@@ -69,0 +69,0 @@ f = meta[name]; |
@@ -35,5 +35,3 @@ (function(factory){ | ||
var counter = 0, cname = "constructor", pname = "prototype", | ||
F = function(){}, empty = {}, mix, extractChain, | ||
stubSuper, stubChain, stubChainSuper, post; | ||
var counter = 0, cname = "constructor", pname = "prototype", empty = {}, mix; | ||
@@ -53,7 +51,7 @@ function dcl(superClass, props){ | ||
// 1) add a unique id | ||
base._u = base._u || counter++; | ||
base._uniqueId = base._uniqueId || counter++; | ||
// 2) build a connection map and the base list | ||
if((proto = base._m)){ // intentional assignment | ||
for(vector = proto.b, j = vector.length - 1; j > 0; --j){ | ||
n = vector[j]._u; | ||
if((proto = base._meta)){ // intentional assignment | ||
for(vector = proto.bases, j = vector.length - 1; j > 0; --j){ | ||
n = vector[j]._uniqueId; | ||
connectionMap[n] = (connectionMap[n] || 0) + 1; | ||
@@ -72,3 +70,3 @@ } | ||
base = vector[0]; | ||
n = base._u; | ||
n = base._uniqueId; | ||
if(!connectionMap[n]){ | ||
@@ -81,3 +79,3 @@ if(!output[n]){ | ||
if(vector.length){ | ||
--connectionMap[vector[0]._u]; | ||
--connectionMap[vector[0]._uniqueId]; | ||
}else{ | ||
@@ -90,12 +88,12 @@ superClasses.splice(i, 1); | ||
// error | ||
dcl._e("cycle", props, superClasses); | ||
dcl._error("cycle", props, superClasses); | ||
} | ||
// calculate a base class | ||
superClass = superClass[0]; | ||
j = bases.length - ((meta = superClass._m) && superClass === bases[bases.length - (j = meta.b.length)] ? j : 1) - 1; // intentional assignments | ||
j = bases.length - ((meta = superClass._meta) && superClass === bases[bases.length - (j = meta.bases.length)] ? j : 1) - 1; // intentional assignments | ||
}else{ | ||
// 1) add a unique id | ||
superClass._u = superClass._u || counter++; | ||
superClass._uniqueId = superClass._uniqueId || counter++; | ||
// 2) single inheritance | ||
bases = bases.concat((meta = superClass._m) ? meta.b : superClass); // intentional assignment | ||
bases = bases.concat((meta = superClass._meta) ? meta.bases : superClass); // intentional assignment | ||
} | ||
@@ -106,3 +104,3 @@ } | ||
// the next line assumes that constructor is actually named "constructor", should be changed if desired | ||
vector = superClass && (meta = superClass._m) ? dcl.delegate(meta.w) : {constructor: 2}; // intentional assignment | ||
vector = superClass && (meta = superClass._meta) ? dcl.delegate(meta.weaver) : {constructor: 2}; // intentional assignment | ||
@@ -112,6 +110,6 @@ // create prototype: mix in mixins and props | ||
base = bases[j]; | ||
meta = base._m; | ||
dcl.mix(proto, meta && meta.h || base[pname]); | ||
meta = base._meta; | ||
dcl.mix(proto, meta && meta.ownProps || base[pname]); | ||
if(meta){ | ||
allKeys(superClasses = meta.w).forEach(function(n){ // intentional assignment | ||
allKeys(superClasses = meta.weaver).forEach(function(n){ // intentional assignment | ||
vector[n] = (+vector[n] || 0) | superClasses[n]; | ||
@@ -131,10 +129,10 @@ }); | ||
// | ||
meta = {b: bases, h: props, w: vector, c: {}}; | ||
meta = {bases: bases, ownProps: props, weaver: vector, chains: {}}; | ||
// meta information is coded like that: | ||
// b: an array of super classes (bases) and mixins | ||
// h: a bag of immediate prototype properties for the constructor | ||
// w: a bag of chain instructions (before is 1, after is 2) | ||
// c: a bag of chains (ordered arrays) | ||
// bases: an array of super classes (bases) and mixins | ||
// ownProps: a bag of immediate prototype properties for the constructor | ||
// weaver: a bag of chain instructions (before is 1, after is 2) | ||
// chains: a bag of chains (ordered arrays) | ||
bases[0] = {_m: meta, prototype: proto}; | ||
bases[0] = {_meta: meta, prototype: proto}; | ||
buildStubs(meta, proto); | ||
@@ -144,3 +142,3 @@ ctor = proto[cname]; | ||
// put in place all decorations and return a constructor | ||
ctor._m = meta; | ||
ctor._meta = meta; | ||
ctor[pname] = proto; | ||
@@ -151,6 +149,6 @@ //proto.constructor = ctor; // uncomment if constructor is not named "constructor" | ||
// each constructor may have two properties on it: | ||
// _m: a meta information object as above | ||
// _u: a unique number, which is used to id the constructor | ||
// _meta: a meta information object as above | ||
// _uniqueId: a unique number, which is used to id the constructor | ||
return dcl._p(ctor); // fully prepared constructor | ||
return dcl._postprocess(ctor); // fully prepared constructor | ||
} | ||
@@ -160,3 +158,3 @@ | ||
function Super(f){ this.f = f; } | ||
function Super(f){ this.around = f; } | ||
function isSuper(f){ return f && f.spr instanceof Super; } | ||
@@ -178,3 +176,3 @@ | ||
Super: Super, | ||
superCall: function superCall(f){ return dcl._mk(f); }, | ||
superCall: function superCall(f){ return dcl._makeSuper(f); }, | ||
@@ -184,20 +182,20 @@ // protected API starts with _ (don't use it!) | ||
// make a Super marker | ||
_mk: function makeSuper(f, S){ var fn = function(){}; fn.spr = new (S || Super)(f); return fn; }, | ||
_makeSuper: function makeSuper(advice, S){ var f = function(){}; f.spr = new (S || Super)(advice); return f; }, | ||
// post-processor for a constructor, can be used to add more functionality | ||
// or augment its behavior | ||
_p: function(ctor){ return ctor; }, // identity, used to hang on advices | ||
_postprocess: function(ctor){ return ctor; }, // identity, used to hang on advices | ||
// error function, augmented by debug.js | ||
_e: function(msg){ throw Error("dcl: " + msg); }, | ||
_error: function(msg){ throw Error("dcl: " + msg); }, | ||
// supercall instantiation, augmented by debug.js | ||
_f: function(f, a, n){ var t = f.spr.f(a); t.ctr = f.ctr; return t; }, | ||
_instantiate: function(advice, previous, node){ var t = advice.spr.around(previous); t.ctr = advice.ctr; return t; }, | ||
// the "buildStubs()" helpers, can be overwritten | ||
_ec: extractChain = function(bases, name, advice){ | ||
var i = bases.length - 1, chain = [], base, f, around = advice == "f"; | ||
_extractChain: function(bases, name, advice){ | ||
var i = bases.length - 1, chain = [], base, f, around = advice == "around"; | ||
for(; base = bases[i]; --i){ | ||
// next line contains 5 intentional assignments | ||
if((f = base._m) ? (f = f.h).hasOwnProperty(name) && (isSuper(f = f[name]) ? (around ? f.spr.f : (f = f.spr[advice])) : around) : around && (f = name == cname ? base : base[pname][name]) && f !== empty[name]){ | ||
if((f = base._meta) ? (f = f.ownProps).hasOwnProperty(name) && (isSuper(f = f[name]) ? (around ? f.spr.around : (f = f.spr[advice])) : around) : around && (f = name == cname ? base : base[pname][name]) && f !== empty[name]){ | ||
f.ctr = base; | ||
@@ -209,3 +207,3 @@ chain.push(f); | ||
}, | ||
_sc: stubChain = function(chain){ // this is "after" chain | ||
_stubChain: function(chain){ // this is "after" chain | ||
var l = chain.length, f; | ||
@@ -222,10 +220,10 @@ return !l ? 0 : l == 1 ? | ||
}, | ||
_ss: stubSuper = function(chain, name){ | ||
_stubSuper: function(chain, name){ | ||
var i = 0, f, p = empty[name]; | ||
for(; f = chain[i]; ++i){ | ||
p = isSuper(f) ? (chain[i] = dcl._f(f, p, name)) : f; | ||
p = isSuper(f) ? (chain[i] = dcl._instantiate(f, p, name)) : f; | ||
} | ||
return name != cname ? p : function(){ p.apply(this, arguments); }; | ||
}, | ||
_st: stubChainSuper = function(chain, stub, name){ | ||
_stubChainSuper: function(chain, stub, name){ | ||
var i = 0, f, diff, pi = 0; | ||
@@ -235,3 +233,3 @@ for(; f = chain[i]; ++i){ | ||
diff = i - pi; | ||
diff = chain[i] = dcl._f(f, !diff ? 0 : diff == 1 ? chain[pi] : stub(chain.slice(pi, i)), name); | ||
chain[i] = dcl._instantiate(f, !diff ? 0 : diff == 1 ? chain[pi] : stub(chain.slice(pi, i)), name); | ||
pi = i; | ||
@@ -243,5 +241,5 @@ } | ||
}, | ||
_sb: /*generic stub*/ function(id, bases, name, chains){ | ||
var f = chains[name] = extractChain(bases, name, "f"); | ||
return (id ? stubChainSuper(f, stubChain, name) : stubSuper(f, name)) || function(){}; | ||
_stub: /*generic stub*/ function(id, bases, name, chains){ | ||
var f = chains[name] = dcl._extractChain(bases, name, "around"); | ||
return (id ? dcl._stubChainSuper(f, dcl._stubChain, name) : dcl._stubSuper(f, name)) || function(){}; | ||
} | ||
@@ -251,5 +249,5 @@ }); | ||
function buildStubs(meta, proto){ | ||
var weaver = meta.w, bases = meta.b, chains = meta.c; | ||
var weaver = meta.weaver, bases = meta.bases, chains = meta.chains; | ||
allKeys(weaver).forEach(function(name){ | ||
proto[name] = dcl._sb(weaver[name], bases, name, chains); | ||
proto[name] = dcl._stub(weaver[name], bases, name, chains); | ||
}); | ||
@@ -256,0 +254,0 @@ } |
90
mini.js
@@ -12,5 +12,3 @@ (function(factory){ | ||
var counter = 0, cname = "constructor", pname = "prototype", | ||
F = function(){}, empty = {}, mix, extractChain, | ||
stubSuper, stubChain, stubChainSuper, post; | ||
var counter = 0, cname = "constructor", pname = "prototype", empty = {}, mix; | ||
@@ -30,7 +28,7 @@ function dcl(superClass, props){ | ||
// 1) add a unique id | ||
base._u = base._u || counter++; | ||
base._uniqueId = base._uniqueId || counter++; | ||
// 2) build a connection map and the base list | ||
if((proto = base._m)){ // intentional assignment | ||
for(vector = proto.b, j = vector.length - 1; j > 0; --j){ | ||
n = vector[j]._u; | ||
if((proto = base._meta)){ // intentional assignment | ||
for(vector = proto.bases, j = vector.length - 1; j > 0; --j){ | ||
n = vector[j]._uniqueId; | ||
connectionMap[n] = (connectionMap[n] || 0) + 1; | ||
@@ -49,3 +47,3 @@ } | ||
base = vector[0]; | ||
n = base._u; | ||
n = base._uniqueId; | ||
if(!connectionMap[n]){ | ||
@@ -58,3 +56,3 @@ if(!output[n]){ | ||
if(vector.length){ | ||
--connectionMap[vector[0]._u]; | ||
--connectionMap[vector[0]._uniqueId]; | ||
}else{ | ||
@@ -67,12 +65,12 @@ superClasses.splice(i, 1); | ||
// error | ||
dcl._e("cycle", props, superClasses); | ||
dcl._error("cycle", props, superClasses); | ||
} | ||
// calculate a base class | ||
superClass = superClass[0]; | ||
j = bases.length - ((meta = superClass._m) && superClass === bases[bases.length - (j = meta.b.length)] ? j : 1) - 1; // intentional assignments | ||
j = bases.length - ((meta = superClass._meta) && superClass === bases[bases.length - (j = meta.bases.length)] ? j : 1) - 1; // intentional assignments | ||
}else{ | ||
// 1) add a unique id | ||
superClass._u = superClass._u || counter++; | ||
superClass._uniqueId = superClass._uniqueId || counter++; | ||
// 2) single inheritance | ||
bases = bases.concat((meta = superClass._m) ? meta.b : superClass); // intentional assignment | ||
bases = bases.concat((meta = superClass._meta) ? meta.bases : superClass); // intentional assignment | ||
} | ||
@@ -83,3 +81,3 @@ } | ||
// the next line assumes that constructor is actually named "constructor", should be changed if desired | ||
vector = superClass && (meta = superClass._m) ? dcl.delegate(meta.w) : {constructor: 2}; // intentional assignment | ||
vector = superClass && (meta = superClass._meta) ? dcl.delegate(meta.weaver) : {constructor: 2}; // intentional assignment | ||
@@ -89,6 +87,6 @@ // create prototype: mix in mixins and props | ||
base = bases[j]; | ||
meta = base._m; | ||
dcl.mix(proto, meta && meta.h || base[pname]); | ||
meta = base._meta; | ||
dcl.mix(proto, meta && meta.ownProps || base[pname]); | ||
if(meta){ | ||
for(n in (superClasses = meta.w)){ // intentional assignment | ||
for(n in (superClasses = meta.weaver)){ // intentional assignment | ||
vector[n] = (+vector[n] || 0) | superClasses[n]; | ||
@@ -108,10 +106,10 @@ } | ||
// | ||
meta = {b: bases, h: props, w: vector, c: {}}; | ||
meta = {bases: bases, ownProps: props, weaver: vector, chains: {}}; | ||
// meta information is coded like that: | ||
// b: an array of super classes (bases) and mixins | ||
// h: a bag of immediate prototype properties for the constructor | ||
// w: a bag of chain instructions (before is 1, after is 2) | ||
// c: a bag of chains (ordered arrays) | ||
// bases: an array of super classes (bases) and mixins | ||
// ownProps: a bag of immediate prototype properties for the constructor | ||
// weaver: a bag of chain instructions (before is 1, after is 2) | ||
// chains: a bag of chains (ordered arrays) | ||
bases[0] = {_m: meta, prototype: proto}; | ||
bases[0] = {_meta: meta, prototype: proto}; | ||
buildStubs(meta, proto); | ||
@@ -121,3 +119,3 @@ ctor = proto[cname]; | ||
// put in place all decorations and return a constructor | ||
ctor._m = meta; | ||
ctor._meta = meta; | ||
ctor[pname] = proto; | ||
@@ -128,6 +126,6 @@ //proto.constructor = ctor; // uncomment if constructor is not named "constructor" | ||
// each constructor may have two properties on it: | ||
// _m: a meta information object as above | ||
// _u: a unique number, which is used to id the constructor | ||
// _meta: a meta information object as above | ||
// _uniqueId: a unique number, which is used to id the constructor | ||
return dcl._p(ctor); // fully prepared constructor | ||
return dcl._postprocess(ctor); // fully prepared constructor | ||
} | ||
@@ -137,3 +135,3 @@ | ||
function Super(f){ this.f = f; } | ||
function Super(f){ this.around = f; } | ||
function isSuper(f){ return f && f.spr instanceof Super; } | ||
@@ -163,3 +161,3 @@ | ||
Super: Super, | ||
superCall: function superCall(f){ return dcl._mk(f); }, | ||
superCall: function superCall(f){ return dcl._makeSuper(f); }, | ||
@@ -169,20 +167,20 @@ // protected API starts with _ (don't use it!) | ||
// make a Super marker | ||
_mk: function makeSuper(f, S){ var fn = function(){}; fn.spr = new (S || Super)(f); return fn; }, | ||
_makeSuper: function makeSuper(advice, S){ var f = function(){}; f.spr = new (S || Super)(advice); return f; }, | ||
// post-processor for a constructor, can be used to add more functionality | ||
// or augment its behavior | ||
_p: function(ctor){ return ctor; }, // identity, used to hang on advices | ||
_postprocess: function(ctor){ return ctor; }, // identity, used to hang on advices | ||
// error function, augmented by debug.js | ||
_e: function(msg){ throw Error("dcl: " + msg); }, | ||
_error: function(msg){ throw Error("dcl: " + msg); }, | ||
// supercall instantiation, augmented by debug.js | ||
_f: function(f, a, n){ var t = f.spr.f(a); t.ctr = f.ctr; return t; }, | ||
_instantiate: function(advice, previous, node){ var t = advice.spr.around(previous); t.ctr = advice.ctr; return t; }, | ||
// the "buildStubs()" helpers, can be overwritten | ||
_ec: extractChain = function(bases, name, advice){ | ||
var i = bases.length - 1, chain = [], base, f, around = advice == "f"; | ||
_extractChain: function(bases, name, advice){ | ||
var i = bases.length - 1, chain = [], base, f, around = advice == "around"; | ||
for(; base = bases[i]; --i){ | ||
// next line contains 5 intentional assignments | ||
if((f = base._m) ? (f = f.h).hasOwnProperty(name) && (isSuper(f = f[name]) ? (around ? f.spr.f : (f = f.spr[advice])) : around) : around && (f = name == cname ? base : base[pname][name]) && f !== empty[name]){ | ||
if((f = base._meta) ? (f = f.ownProps).hasOwnProperty(name) && (isSuper(f = f[name]) ? (around ? f.spr.around : (f = f.spr[advice])) : around) : around && (f = name == cname ? base : base[pname][name]) && f !== empty[name]){ | ||
f.ctr = base; | ||
@@ -194,3 +192,3 @@ chain.push(f); | ||
}, | ||
_sc: stubChain = function(chain){ // this is "after" chain | ||
_stubChain: function(chain){ // this is "after" chain | ||
var l = chain.length, f; | ||
@@ -207,10 +205,10 @@ return !l ? 0 : l == 1 ? | ||
}, | ||
_ss: stubSuper = function(chain, name){ | ||
_stubSuper: function(chain, name){ | ||
var i = 0, f, p = empty[name]; | ||
for(; f = chain[i]; ++i){ | ||
p = isSuper(f) ? (chain[i] = dcl._f(f, p, name)) : f; | ||
p = isSuper(f) ? (chain[i] = dcl._instantiate(f, p, name)) : f; | ||
} | ||
return name != cname ? p : function(){ p.apply(this, arguments); }; | ||
}, | ||
_st: stubChainSuper = function(chain, stub, name){ | ||
_stubChainSuper: function(chain, stub, name){ | ||
var i = 0, f, diff, pi = 0; | ||
@@ -220,3 +218,3 @@ for(; f = chain[i]; ++i){ | ||
diff = i - pi; | ||
diff = chain[i] = dcl._f(f, !diff ? 0 : diff == 1 ? chain[pi] : stub(chain.slice(pi, i)), name); | ||
chain[i] = dcl._instantiate(f, !diff ? 0 : diff == 1 ? chain[pi] : stub(chain.slice(pi, i)), name); | ||
pi = i; | ||
@@ -228,5 +226,5 @@ } | ||
}, | ||
_sb: /*generic stub*/ function(id, bases, name, chains){ | ||
var f = chains[name] = extractChain(bases, name, "f"); | ||
return (id ? stubChainSuper(f, stubChain, name) : stubSuper(f, name)) || function(){}; | ||
_stub: /*generic stub*/ function(id, bases, name, chains){ | ||
var f = chains[name] = dcl._extractChain(bases, name, "around"); | ||
return (id ? dcl._stubChainSuper(f, dcl._stubChain, name) : dcl._stubSuper(f, name)) || function(){}; | ||
} | ||
@@ -236,5 +234,5 @@ }); | ||
function buildStubs(meta, proto){ | ||
var weaver = meta.w, bases = meta.b, chains = meta.c; | ||
var weaver = meta.weaver, bases = meta.bases, chains = meta.chains; | ||
for(var name in weaver){ | ||
proto[name] = dcl._sb(weaver[name], bases, name, chains); | ||
proto[name] = dcl._stub(weaver[name], bases, name, chains); | ||
} | ||
@@ -241,0 +239,0 @@ } |
{ | ||
"name": "dcl", | ||
"version": "1.1.1", | ||
"version": "1.1.2", | ||
"description": "Elegant minimalistic implementation of OOP with mixins + AOP.", | ||
@@ -5,0 +5,0 @@ "homepage": "http://www.dcljs.org", |
@@ -1,3 +0,9 @@ | ||
# DCL [![Build Status](https://secure.travis-ci.org/uhop/dcl.png?branch=master)](http://travis-ci.org/uhop/dcl) | ||
# DCL | ||
[![Build status][travis-image]][travis-url] | ||
[![Dependencies][deps-image]][deps-url] | ||
[![devDependencies][dev-deps-image]][dev-deps-url] | ||
[![NPM version][npm-image]][npm-url] | ||
A minimalistic yet complete JavaScript package for [node.js](http://nodejs.org) | ||
@@ -8,4 +14,3 @@ and modern browsers that implements OOP with mixins + AOP at both "class" and | ||
full set of advices, and provides some useful generic building blocks. The whole | ||
package comes with an extensive test set (111 tests at the time of writing) and | ||
fully compatible with the strict mode. | ||
package comes with an extensive test set, and it is fully compatible with the strict mode. | ||
@@ -29,3 +34,3 @@ The package was written with debuggability of your code in mind. It comes with | ||
If you plan to use it in your [node.js](http://nodejs.org) project install it | ||
If you plan to use it in your [node.js](http://nodejs.org) project, install it | ||
like this: | ||
@@ -60,3 +65,3 @@ | ||
## Inheritance, constructors, super calls | ||
### Inheritance, constructors, super calls | ||
@@ -173,3 +178,3 @@ Let's continue with our coding example: | ||
## AOP | ||
### AOP | ||
@@ -246,3 +251,3 @@ We can use aspect-oriented advices to create our "classes": | ||
## Chaining | ||
### Chaining | ||
@@ -290,3 +295,3 @@ While constructors are chained by default you can chain any methods you like. | ||
## Advising objects | ||
### Advising objects | ||
@@ -314,3 +319,3 @@ While class-level AOP is static, we can always advise any method dynamically, | ||
}); | ||
var wakeAd2 = advise(ethel, "wakeUp", { | ||
var wakeAd3 = advise(ethel, "wakeUp", { | ||
before: function(){ console.log("dress up for work"); } | ||
@@ -342,3 +347,3 @@ }); | ||
// brushing teeth more than once a day is overrated, right? | ||
sleepAd1.unadvise(); | ||
sleepAd2.unadvise(); | ||
// no need to dress up for work either --- Ethel is CEO! | ||
@@ -366,3 +371,3 @@ wakeAd3.unadvise(); | ||
## Debugging helpers | ||
### Debugging helpers | ||
@@ -463,1 +468,10 @@ There is a special module `dcl/debug` that adds better error checking and reporting | ||
Happy hacking! | ||
[npm-image]: https://img.shields.io/npm/v/dcl.svg | ||
[npm-url]: https://npmjs.org/package/dcl | ||
[deps-image]: https://img.shields.io/david/uhop/dcl.svg | ||
[deps-url]: https://david-dm.org/uhop/dcl | ||
[dev-deps-image]: https://img.shields.io/david/dev/uhop/dcl.svg | ||
[dev-deps-url]: https://david-dm.org/uhop/dcl#info=devDependencies | ||
[travis-image]: https://img.shields.io/travis/uhop/dcl.svg | ||
[travis-url]: https://travis-ci.org/uhop/dcl |
@@ -7,3 +7,3 @@ /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) | ||
function getNames(ctor){ | ||
var b = ctor._m.b, r = []; | ||
var b = ctor._meta.bases, r = []; | ||
for(var i = 0, l = b.length; i < l; ++i){ | ||
@@ -10,0 +10,0 @@ r.push(b[i].prototype.declaredClass); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
102717
37
2688
468