Comparing version 1.1.3 to 2.0.0
@@ -1,27 +0,21 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define(["../dcl"], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(require("../dcl")); | ||
}else{ | ||
dclAdvicesCounter = factory(dcl); | ||
} | ||
})(function(dcl){ | ||
"use strict"; | ||
/* 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)}))}) | ||
(['../dcl'], function (dcl) { | ||
'use strict'; | ||
var Counter = new dcl(null, { | ||
declaredClass: "dcl/advices/counter/Counter", | ||
constructor: function(){ | ||
declaredClass: 'dcl/advices/counter/Counter', | ||
constructor: function () { | ||
this.reset(); | ||
}, | ||
reset: function(){ | ||
reset: function () { | ||
this.calls = this.errors = 0; | ||
}, | ||
advice: function(){ | ||
advice: function () { | ||
var self = this; | ||
return { | ||
before: function(){ | ||
before: function () { | ||
++self.calls; | ||
}, | ||
after: function(args, result){ | ||
if(result instanceof Error){ | ||
after: function (args, result) { | ||
if (result instanceof Error) { | ||
++self.errors; | ||
@@ -28,0 +22,0 @@ } |
@@ -1,24 +0,19 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define([], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(); | ||
}else{ | ||
dclAdvicesFlow = factory(); | ||
} | ||
})(function(){ | ||
"use strict"; | ||
/* 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 () { | ||
'use strict'; | ||
var flowStack = [], flowCount = {}; | ||
return { | ||
advice: function(name){ | ||
advice: function (name) { | ||
return { | ||
before: function(){ | ||
before: function () { | ||
flowStack.push(name); | ||
if(flowCount[name]){ | ||
if (flowCount[name]) { | ||
++flowCount[name]; | ||
}else{ | ||
} else { | ||
flowCount[name] = 1; | ||
} | ||
}, | ||
after: function(){ | ||
after: function () { | ||
--flowCount[name]; | ||
@@ -29,9 +24,9 @@ flowStack.pop(); | ||
}, | ||
inFlowOf: function(name){ | ||
inFlowOf: function (name) { | ||
return flowCount[name]; | ||
}, | ||
getStack: function(){ | ||
getStack: function () { | ||
return flowStack; | ||
}, | ||
getCount: function(){ | ||
getCount: function () { | ||
return flowCount; | ||
@@ -38,0 +33,0 @@ } |
@@ -1,60 +0,54 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define([], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(); | ||
}else{ | ||
dclAdvicesMemoize = factory(); | ||
} | ||
})(function(){ | ||
"use strict"; | ||
/* 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 () { | ||
'use strict'; | ||
return { | ||
advice: function(name, keyMaker){ | ||
advice: function (name, keyMaker) { | ||
return keyMaker ? | ||
{ | ||
around: function(sup){ | ||
return function(){ | ||
around: function (sup) { | ||
return function () { | ||
var key = keyMaker(this, arguments), cache = this.__memoizerCache, dict; | ||
if(!cache){ | ||
if (!cache) { | ||
cache = this.__memoizerCache = {}; | ||
} | ||
if(cache.hasOwnProperty(name)){ | ||
if (cache.hasOwnProperty(name)) { | ||
dict = cache[name]; | ||
}else{ | ||
} else { | ||
dict = cache[name] = {}; | ||
} | ||
if(dict.hasOwnProperty(key)){ | ||
if (dict.hasOwnProperty(key)) { | ||
return dict[key]; | ||
} | ||
return dict[key] = sup ? sup.apply(this, arguments) : undefined; | ||
} | ||
return dict[key] = sup ? sup.apply(this, arguments) : void 0; | ||
}; | ||
} | ||
} : | ||
{ | ||
around: function(sup){ | ||
return function(first){ | ||
around: function (sup) { | ||
return function (first) { | ||
var cache = this.__memoizerCache, dict; | ||
if(!cache){ | ||
if (!cache) { | ||
cache = this.__memoizerCache = {}; | ||
} | ||
if(cache.hasOwnProperty(name)){ | ||
if (cache.hasOwnProperty(name)) { | ||
dict = cache[name]; | ||
}else{ | ||
} else { | ||
dict = cache[name] = {}; | ||
} | ||
if(dict.hasOwnProperty(first)){ | ||
if (dict.hasOwnProperty(first)) { | ||
return dict[first]; | ||
} | ||
return dict[first] = sup ? sup.apply(this, arguments) : undefined; | ||
} | ||
}; | ||
} | ||
}; | ||
}, | ||
guard: function(name){ | ||
guard: function (name) { | ||
return { | ||
after: function(){ | ||
after: function () { | ||
var cache = this.__memoizerCache; | ||
if(cache && name){ | ||
delete cache[name] | ||
}else{ | ||
if (cache && name) { | ||
delete cache[name]; | ||
} else { | ||
this.__memoizerCache = {}; | ||
@@ -61,0 +55,0 @@ } |
@@ -1,22 +0,17 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define([], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(); | ||
}else{ | ||
dclAdvicesTime = factory(); | ||
} | ||
})(function(){ | ||
"use strict"; | ||
/* 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 () { | ||
'use strict'; | ||
var uniq = 0; | ||
return function(name){ | ||
var inCall = 0, label = name || ("Timer #" + uniq++); | ||
return function (name) { | ||
var inCall = 0, label = name || ('Timer #' + uniq++); | ||
return { | ||
before: function(){ | ||
if(!(inCall++)){ | ||
before: function () { | ||
if (!(inCall++)) { | ||
console.time(label); | ||
} | ||
}, | ||
after: function(){ | ||
if(!--inCall){ | ||
after: function () { | ||
if (!--inCall) { | ||
console.timeEnd(label); | ||
@@ -23,0 +18,0 @@ } |
@@ -1,34 +0,31 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define([], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(); | ||
}else{ | ||
dclAdvicesTrace = factory(); | ||
} | ||
})(function(){ | ||
"use strict"; | ||
/* 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 () { | ||
'use strict'; | ||
var lvl = 0; | ||
function rep(ch, n){ | ||
if(n < 1){ return ""; } | ||
if(n == 1){ return ch; } | ||
function rep (ch, n) { | ||
if (n < 1) { return ''; } | ||
if (n == 1) { return ch; } | ||
var h = rep(ch, Math.floor(n / 2)); | ||
return h + h + ((n & 1) ? ch : ""); | ||
return h + h + ((n & 1) ? ch : ''); | ||
} | ||
function pad(value, width, ch){ | ||
function pad (value, width, ch) { | ||
var v = value.toString(); | ||
return v + rep(ch || " ", width - v.length); | ||
return v + rep(ch || ' ', width - v.length); | ||
} | ||
return function(name, level){ | ||
return function (name, level) { | ||
return { | ||
before: function(){ | ||
before: function () { | ||
++lvl; | ||
console.log((level ? pad(lvl, 2 * lvl) : "") + this + " => " + | ||
name + "(" + Array.prototype.join.call(arguments, ", ") + ")"); | ||
console.log((level ? pad(lvl, 2 * lvl) : '') + this + ' => ' + | ||
name + '(' + Array.prototype.join.call(arguments, ', ') + ')'); | ||
}, | ||
after: function(args, result){ | ||
console.log((level ? pad(lvl, 2 * lvl) : "") + this + " => " + | ||
name + (result && result instanceof Error ? " throws" : " returns") + | ||
" " + result); | ||
after: function (args, result) { | ||
console.log((level ? pad(lvl, 2 * lvl) : '') + this + ' => ' + | ||
name + (result && result instanceof Error ? ' throws' : ' returns') + | ||
' ' + result); | ||
--lvl; | ||
@@ -35,0 +32,0 @@ } |
265
advise.js
@@ -1,116 +0,207 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define([], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(); | ||
}else{ | ||
advise = factory(); | ||
/* 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 () { | ||
'use strict'; | ||
var pname = 'prototype'; | ||
function Node (parent) { | ||
this.parent = parent || this; | ||
} | ||
})(function(){ | ||
"use strict"; | ||
function Node(instance, 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 = { | ||
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; | ||
Node[pname] = { | ||
removeTopic: function (topic) { | ||
var n = 'next_' + topic, p = 'prev_' + topic; | ||
if (this[n] && this[p]) { | ||
this[n][p] = this[p]; | ||
this[p][n] = this[n]; | ||
} | ||
}, | ||
_add: function(topic, node, flag){ | ||
if(node[topic] || flag){ | ||
var n = "next_" + topic, p = "prev_" + topic; | ||
(node[p] = this[p])[n] = (node[n] = this)[p] = node; | ||
remove: function () { | ||
this.removeTopic('before'); | ||
this.removeTopic('around'); | ||
// remove & recreate around advices | ||
var parent = this.parent, next = this.next_around; | ||
this.removeTopic('after'); | ||
for (; next && next !== parent; next = next.next_around) { | ||
next.around = next.originalAround(next.prev_around.around); | ||
} | ||
}, | ||
remove: function(node){ | ||
this._remove("before", node); | ||
this._remove("after", node); | ||
this._remove("around", node); | ||
addTopic: function (node, topic) { | ||
var n = 'next_' + topic, p = 'prev_' + topic, | ||
prev = node[p] = this[p] || this; | ||
node[n] = this; | ||
prev[n] = this[p] = node; | ||
}, | ||
_remove: function(topic, node){ | ||
var n = "next_" + topic, p = "prev_" + topic; | ||
node[n][p] = node[p]; | ||
node[p][n] = node[n]; | ||
}, | ||
destroy: function(){ | ||
var around = this.prev_around.around, t = this.next_around, parent = this.parent; | ||
this.remove(this); | ||
if(t !== this){ | ||
for(; t !== parent; around = t.around, t = t.next_around){ | ||
if(t.original){ | ||
t.around = advise._instantiate(t.original, around, this); | ||
} | ||
addAdvice: function (advice, instance, name, type) { | ||
var node = new Node(this); | ||
if (advice.before) { | ||
node.before = advice.before; | ||
this.addTopic(node, 'before'); | ||
} | ||
if (advice.around) { | ||
if (typeof advice.around != 'function') { | ||
advise._error('wrong super call', instance, name, type); | ||
} | ||
node.originalAround = advice.around; | ||
this.addTopic(node, 'around'); | ||
if (node.prev_around.around && typeof node.prev_around.around != 'function') { | ||
advise._error('wrong super arg', instance, name, type); | ||
} | ||
node.around = advice.around(node.prev_around.around || null); | ||
if (typeof node.around != 'function') { | ||
advise._error('wrong super result', instance, name, type); | ||
} | ||
} | ||
this.instance = 0; | ||
if (advice.after) { | ||
node.after = advice.after; | ||
this.addTopic(node, 'after'); | ||
} | ||
return node; | ||
} | ||
}; | ||
p.unadvise = p.destroy; // alias | ||
function makeAOPStub(node){ | ||
var f = function(){ | ||
var p, r, t = this, a = arguments, thrown; | ||
Node[pname].destroy = Node[pname].unadvise = Node[pname].remove; | ||
function addNode (root, topic) { | ||
return function (f) { | ||
var node = new Node(root); | ||
node[topic] = f; | ||
root.addTopic(node, topic); | ||
}; | ||
} | ||
function makeStub (value) { | ||
var root = new Node(); | ||
if (value) { | ||
if (typeof value.advices == 'object') { | ||
var advices = value.advices; | ||
advices.before.forEach(addNode(root, 'before')); | ||
advices.after. forEach(addNode(root, 'after')); | ||
advices.around && addNode(root, 'around')(advices.around); | ||
} else { | ||
addNode(root, 'around')(value); | ||
} | ||
} | ||
function stub () { | ||
var result, thrown, p; | ||
// running the before chain | ||
for(p = node.prev_before; p !== node; p = p.prev_before){ | ||
p.before.apply(t, a); | ||
for (p = root.prev_before; p && p !== root; p = p.prev_before) { | ||
p.before.apply(this, arguments); | ||
} | ||
// running the around chain | ||
try{ | ||
if(node.prev_around !== node){ r = node.prev_around.around.apply(t, a); } | ||
}catch(e){ | ||
r = e; | ||
thrown = true; | ||
if (root.prev_around && root.prev_around !== root) { | ||
try { | ||
result = root.prev_around.around.apply(this, arguments); | ||
} catch (error) { | ||
result = error; | ||
thrown = true; | ||
} | ||
} | ||
// running the after chain | ||
for(p = node.next_after; p !== node; p = p.next_after){ | ||
p.after.call(t, a, r); | ||
for (p = root.next_after; p && p !== root; p = p.next_after) { | ||
p.after.call(this, arguments, result, makeReturn, makeThrow); | ||
} | ||
if(thrown){ | ||
throw r; | ||
if (thrown) { | ||
throw result; | ||
} | ||
return r; | ||
return result; | ||
function makeReturn (value) { result = value; thrown = false; } | ||
function makeThrow (value) { result = value; thrown = true; } | ||
}; | ||
f.adviceNode = node; | ||
return f; | ||
stub.node = root; | ||
return stub; | ||
} | ||
function advise(instance, name, advice){ | ||
var f = instance[name], node; | ||
if(f && f.adviceNode && f.adviceNode instanceof Node){ | ||
node = f.adviceNode; | ||
}else{ | ||
node = new Node(instance, name); | ||
if(f && f.advices){ | ||
f = f.advices; | ||
node.add(f.before, f.after, f.around); | ||
}else{ | ||
node.add(0, 0, f); | ||
function convert (value, advice, instance, name, type) { | ||
if (!value || !(value.node instanceof Node)) { | ||
value = makeStub(value); | ||
value.node.instance = instance; | ||
value.node.name = name; | ||
value.node.type = type; | ||
} | ||
var node = value.node.addAdvice(advice, instance, name, type); | ||
return {value: value, handle: node}; | ||
} | ||
function combineHandles (handles) { | ||
var handle = { | ||
remove: function () { | ||
handles.forEach(function (handle) { handle.remove(); }); | ||
} | ||
instance[name] = makeAOPStub(node); | ||
} | ||
if(typeof advice == "function"){ advice = advice(name, instance); } | ||
return node.add(advice.before, advice.after, 0, advice.around); | ||
handle.unadvise = handle.remove; | ||
return handle; | ||
} | ||
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.around = function(instance, name, f){ return advise(instance, name, {around: f}); }; | ||
function advise (instance, name, advice) { | ||
var prop = getPropertyDescriptor(instance, name), handles = []; | ||
if (prop) { | ||
if (prop.get || prop.set) { | ||
var result; | ||
if (prop.get && advice.get) { | ||
result = convert(prop.get, advice.get, instance, name, 'get'); | ||
prop.get = result.value; | ||
handles.push(result.handle); | ||
} | ||
if (prop.set && advice.set) { | ||
result = convert(prop.set, advice.set, instance, name, 'set'); | ||
prop.set = result.value; | ||
handles.push(result.handle); | ||
} | ||
} else { | ||
if (prop.value && advice) { | ||
result = convert(prop.value, advice, instance, name, 'value'); | ||
prop.value = result.value; | ||
handles.push(result.handle); | ||
} | ||
} | ||
} else { | ||
prop = {writable: true, configurable: true, enumerable: true}; | ||
if (advice.get || advice.set) { | ||
if (advice.get) { | ||
result = convert(null, advice.get, instance, name, 'get'); | ||
prop.get = result.value; | ||
handles.push(result.handles); | ||
} | ||
if (advice.set) { | ||
result = convert(null, advice.set, instance, name, 'set'); | ||
prop.set = result.value; | ||
handles.push(result.handles); | ||
} | ||
} else { | ||
result = convert(null, advice, instance, name, 'value'); | ||
prop.value = result.value; | ||
handles.push(result.handles); | ||
} | ||
} | ||
Object.defineProperty(instance, name, prop); | ||
return combineHandles(handles); | ||
} | ||
// export | ||
// guts, do not use them! | ||
advise._error = function (msg) { | ||
throw new Error(msg); | ||
}; | ||
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.around = function (instance, name, f) { return advise(instance, name, {around: f}); }; | ||
advise.Node = Node; | ||
advise._instantiate = function(advice, previous, node){ return advice(previous); }; | ||
return advise; | ||
return advise; | ||
// copied from dcl.js so we can be independent | ||
function getPropertyDescriptor (o, name) { | ||
while (o && o !== Object[pname]) { | ||
if (o.hasOwnProperty(name)) { | ||
return Object.getOwnPropertyDescriptor(o, name); | ||
} | ||
o = Object.getPrototypeOf(o); | ||
} | ||
return; // undefined | ||
} | ||
}); |
@@ -1,17 +0,11 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define(["../mini"], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(require("../mini")); | ||
}else{ | ||
dclBasesMixer = factory(dcl); | ||
} | ||
})(function(dcl){ | ||
"use strict"; | ||
/* 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)}))}) | ||
(['../dcl'], function (dcl) { | ||
'use strict'; | ||
return dcl(null, { | ||
declaredClass: "dcl/bases/Mixer", | ||
constructor: function(x){ | ||
dcl.mix(this, x); | ||
declaredClass: 'dcl/bases/Mixer', | ||
constructor: function (x) { | ||
Object.defineProperties(this, dcl.collectPropertyDescriptors({}, x)); | ||
} | ||
}); | ||
}); |
@@ -1,21 +0,12 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define(["../mini"], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(require("../mini")); | ||
}else{ | ||
dclBasesReplacer = factory(dcl); | ||
} | ||
})(function(dcl){ | ||
"use strict"; | ||
/* 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)}))}) | ||
(['../dcl'], function (dcl) { | ||
'use strict'; | ||
return dcl(null, { | ||
declaredClass: "dcl/bases/Replacer", | ||
constructor: function(x){ | ||
var empty = {}; | ||
dcl.allKeys(x).forEach(function(name){ | ||
if(name in this){ | ||
var t = x[name], e = empty[name]; | ||
if(t !== e){ | ||
this[name] = t; | ||
} | ||
declaredClass: 'dcl/bases/Replacer', | ||
constructor: function (x) { | ||
var props = dcl.collectPropertyDescriptors({}, x); | ||
Object.keys(props).forEach(function (name) { | ||
if (name in this) { | ||
Object.defineProperty(this, name, props[name]); | ||
} | ||
@@ -22,0 +13,0 @@ }, this); |
{ | ||
"name": "dcl", | ||
"version": "1.1.3", | ||
"description": "Elegant minimalistic implementation of OOP with mixins + AOP.", | ||
"main": "dcl.js", | ||
"authors": [ | ||
"Eugene Lazutkin <eugene.lazutkin@gmail.com> (http://www.lazutkin.com/)" | ||
], | ||
"license": "BSD-3-Clause", | ||
"keywords": [ | ||
"object-oriented", | ||
"programming", | ||
"aspect-oriented", | ||
"OOP", | ||
"AOP", | ||
"OO" | ||
], | ||
"homepage": "https://github.com/uhop/dcl", | ||
"moduleType": [ | ||
"amd", | ||
"globals", | ||
"node" | ||
], | ||
"ignore": [ | ||
@@ -6,0 +24,0 @@ "**/.*", |
773
dcl.js
@@ -1,99 +0,728 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define(["./mini"], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(require("./mini")); | ||
}else{ | ||
dcl = factory(dcl); | ||
/* 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 () { | ||
'use strict'; | ||
// set up custom names | ||
var mname = '_meta', pname = 'prototype', cname = 'constructor'; | ||
// MODULE: restricted Map shim (used by C3 MRO) | ||
var M; // our map implementation if not defined | ||
if (typeof Map == 'undefined') { | ||
// our fake, inefficient, incomplete, yet totally correct Map | ||
M = function () { | ||
this.list = []; | ||
this.size = 0; | ||
}; | ||
M.prototype = { | ||
has: function (key) { return this.get(key); }, | ||
get: function (key) { | ||
for (var i = 0, n = this.list.length; i < n; i += 2) { | ||
if (key === this.list[i]) { | ||
return this.list[i + 1]; | ||
} | ||
} | ||
// returns undefined if not found | ||
}, | ||
set: function (key, value) { | ||
for (var i = 0, n = this.list.length; i < n; i += 2) { | ||
if (key === this.list[i]) { | ||
this.list[i + 1] = value; | ||
return this; | ||
} | ||
} | ||
this.list.push(key, value); | ||
++this.size; | ||
return this; | ||
} | ||
}; | ||
} else { | ||
M = Map; | ||
} | ||
})(function(dcl){ | ||
"use strict"; | ||
function nop(){} | ||
var Advice = dcl(dcl.Super, { | ||
//declaredClass: "dcl.Advice", | ||
constructor: function(){ | ||
this.before = this.around.before; | ||
this.after = this.around.after; | ||
this.around = this.around.around; | ||
// MODULE: C3 MRO | ||
function c3mro (bases, props) { | ||
// build a connectivity matrix | ||
var connectivity = new M(); | ||
bases.forEach(function (base) { | ||
(base[mname] ? base[mname].bases : [base]).forEach(function (base, index, array) { | ||
if (connectivity.has(base)) { | ||
var value = connectivity.get(base); | ||
++value.counter; | ||
if (index) { | ||
value.links.push(array[index - 1]); | ||
} | ||
} else { | ||
connectivity.set(base, { | ||
links: index ? [array[index - 1]] : [], | ||
counter: index + 1 == array.length ? 0 : 1 | ||
}); | ||
} | ||
}); | ||
}); | ||
// Kahn's algorithm | ||
var output = [], unreferenced = []; | ||
// find unreferenced bases | ||
bases.forEach(function (base) { | ||
var last = base[mname] ? base[mname].bases[base[mname].bases.length - 1] : base; | ||
if (!connectivity.get(last).counter) { | ||
unreferenced.push(last); | ||
} | ||
}); | ||
while (unreferenced.length) { | ||
var base = unreferenced.pop(); | ||
output.push(base); | ||
var value = connectivity.get(base); | ||
value.links.forEach(updateCounter); | ||
} | ||
}); | ||
function advise(advice){ return dcl._makeSuper(advice, Advice); } | ||
// final checks and return | ||
if (connectivity.size != output.length) { | ||
dcl._error('cycle', bases, props); | ||
} | ||
return output; | ||
function makeAOPStub(before, after, around){ | ||
var beforeChain = before || nop, | ||
afterChain = after || nop, | ||
aroundChain = around || nop, | ||
stub = function(){ | ||
var r, thrown; | ||
function updateCounter (base) { | ||
var value = connectivity.get(base); | ||
if (!--value.counter) { | ||
unreferenced.push(base); | ||
} | ||
} | ||
} | ||
// MODULE: handling properties | ||
function updateProps (props, defaults, augmentDescriptor, augmentWritable) { | ||
var augmenter; | ||
if ('configurable' in defaults) { | ||
augmenter = augmentDescriptor('configurable', defaults.configurable); | ||
Object.keys(props).forEach(function (name) { augmenter(props[name], name); }); | ||
} | ||
if ('enumerable' in defaults) { | ||
augmenter = augmentDescriptor('enumerable', defaults.enumerable); | ||
Object.keys(props).forEach(function (name) { augmenter(props[name], name); }); | ||
} | ||
if ('writable' in defaults) { | ||
augmenter = augmentWritable(defaults.writable); | ||
Object.keys(props).forEach(function (name) { augmenter(props[name], name); }); | ||
} | ||
return props; | ||
} | ||
var descriptorProperties = {configurable: 1, enumerable: 1, value: 1, writable: 1, get: 1, set: 1}; | ||
function toProperties(x, defaults) { | ||
var props, descriptors; | ||
if (x instanceof dcl.Prop) { | ||
props = x.x; | ||
} else { | ||
Object.getOwnPropertyNames(x).forEach(function(key) { | ||
var prop = Object.getOwnPropertyDescriptor(x, key); | ||
if (prop.get || prop.set) { | ||
// accessor descriptor | ||
descriptors = descriptors || {}; | ||
descriptors[key] = prop; | ||
} else { | ||
// data descriptor | ||
var value = prop.value; | ||
if (value instanceof dcl.Prop) { | ||
props = props || {}; | ||
props[key] = value.x; | ||
} else { | ||
if (defaults.detectProps && value && typeof value == 'object') { | ||
if (Object.keys(value).every(function (name) { return descriptorProperties[name] === 1; })) { | ||
props = props || {}; | ||
props[key] = value; | ||
return; | ||
} | ||
} | ||
descriptors = descriptors || {}; | ||
descriptors[key] = prop; | ||
} | ||
} | ||
}); | ||
} | ||
if (props) { | ||
props = updateProps(props, defaults, augmentDescriptor, augmentWritable); | ||
} | ||
if (descriptors) { | ||
descriptors = updateProps(descriptors, defaults, replaceDescriptor, replaceWritable); | ||
} | ||
if (descriptors && props) { | ||
Object.keys(props).forEach(function(key) { | ||
descriptors[key] = props[key]; | ||
}); | ||
} | ||
return descriptors || props || {}; | ||
} | ||
function cloneDescriptor (descriptor) { // shallow copy | ||
var newDescriptor = {}; | ||
Object.keys(descriptor).forEach(function (name) { | ||
newDescriptor[name] = descriptor[name]; | ||
}); | ||
return newDescriptor; | ||
} | ||
function augmentDescriptor(type, value) { | ||
return typeof value == 'function' ? value : function(descriptor) { | ||
if (!descriptor.hasOwnProperty(type)) { | ||
descriptor[type] = value; | ||
} | ||
}; | ||
} | ||
function augmentWritable(value) { | ||
return typeof value == 'function' ? value : function(descriptor) { | ||
if (!descriptor.get && !descriptor.set && !descriptor.hasOwnProperty('writable')) { | ||
descriptor.writable = value; | ||
} | ||
}; | ||
} | ||
function replaceDescriptor(type, value) { | ||
return typeof value == 'function' ? value : function(descriptor) { | ||
descriptor[type] = value; | ||
}; | ||
} | ||
function replaceWritable(value) { | ||
return typeof value == 'function' ? value : function(descriptor) { | ||
if (descriptor.hasOwnProperty('value')) { | ||
descriptor.writable = value; | ||
} | ||
}; | ||
} | ||
function getPropertyDescriptor (o, name) { | ||
while (o && o !== Object.prototype) { | ||
if (o.hasOwnProperty(name)) { | ||
return Object.getOwnPropertyDescriptor(o, name); | ||
} | ||
o = Object.getPrototypeOf(o); | ||
} | ||
return; // undefined | ||
} | ||
// MODULE: produce properties | ||
function recordProp(props, o, recorded) { | ||
return function (name) { | ||
if (recorded[name] !== 1) { | ||
recorded[name] = 1; | ||
props[name] = Object.getOwnPropertyDescriptor(o, name); | ||
} | ||
}; | ||
} | ||
function collectPropertyDescriptors (props, o) { | ||
var recorded = {}; | ||
while (o && o !== Object.prototype) { | ||
Object.getOwnPropertyNames(o).forEach(recordProp(props, o, recorded)); | ||
o = Object.getPrototypeOf(o); | ||
} | ||
return props; | ||
} | ||
// populate properties with simple properties | ||
function populateProps (props, mixins, special) { | ||
var newSpecial = {}; | ||
mixins.forEach(function (base) { | ||
// copy properties for dcl objects | ||
if (base[mname]) { | ||
var baseProps = base[mname].props; | ||
Object.keys(baseProps).forEach(function (name) { | ||
if (special.hasOwnProperty(name)) { | ||
newSpecial[name] = special[name]; | ||
} else { | ||
props[name] = baseProps[name]; | ||
} | ||
}); | ||
return; | ||
} | ||
// copy properties for regular objects | ||
collectPropertyDescriptors(props, base[pname]); | ||
}); | ||
return newSpecial; | ||
} | ||
var empty = {}; | ||
function weaveProp (name, bases, weaver, props) { | ||
var state = {prop: null, backlog: []}; | ||
weaver.start && weaver.start(state); | ||
bases.forEach(function (base, index) { | ||
var prop; | ||
if (base[mname]) { | ||
var baseProps = base[mname].props; | ||
if (baseProps.hasOwnProperty(name)) { | ||
prop = baseProps[name]; | ||
} | ||
} else { | ||
prop = getPropertyDescriptor(base[pname], name); | ||
if (!prop && name == cname) { | ||
prop = {configurable: true, enumerable: false, writable: true, value: base}; | ||
} | ||
} | ||
if (!prop) { | ||
return; | ||
} | ||
var newProp = cloneDescriptor(prop), prevProp, superArg; | ||
if (prop.get || prop.set) { | ||
// accessor | ||
var superGet = isSuper(prop.get) && prop.get.spr.around, | ||
superSet = isSuper(prop.set) && prop.set.spr.around; | ||
if (superGet || superSet) { | ||
processBacklog(state, weaver); | ||
prevProp = state.prop; | ||
} | ||
if (superGet) { | ||
if (typeof prop.get.spr.around != 'function') { | ||
dcl._error('wrong super get call', base, name, index, props); | ||
} | ||
superArg = null; | ||
if (prevProp) { | ||
superArg = prevProp.get || prevProp.set ? | ||
prevProp.get : adaptValue(prevProp.value); | ||
} | ||
if (superArg && typeof superArg != 'function') { | ||
dcl._error('wrong super get arg', base, name, index, props); | ||
} | ||
newProp.get = prop.get.spr.around(superArg); | ||
if (typeof newProp.get != 'function') { | ||
dcl._error('wrong super get result', base, name, index, props); | ||
} | ||
state.prop = null; | ||
} | ||
if (superSet) { | ||
if (typeof prop.set.spr.around != 'function') { | ||
dcl._error('wrong super set call', base, name, index, props); | ||
} | ||
superArg = prevProp && prevProp.set; | ||
if (superArg && typeof superArg != 'function') { | ||
dcl._error('wrong super set arg', base, name, index, props); | ||
} | ||
newProp.set = prop.set.spr.around(superArg); | ||
if (typeof newProp.set != 'function') { | ||
dcl._error('wrong super set result', base, name, index, props); | ||
} | ||
state.prop = null; | ||
} | ||
if ((!prop.get || isSuper(prop.get) && !prop.get.spr.around) && (!prop.set || isSuper(prop.set) && !prop.set.spr.around)) { | ||
return; // skip descriptor: no actionable value | ||
} | ||
} else { | ||
// data | ||
if (isSuper(prop.value) && prop.value.spr.around) { | ||
processBacklog(state, weaver); | ||
prevProp = state.prop; | ||
if (typeof prop.value.spr.around != 'function') { | ||
dcl._error('wrong super value call', base, name, index, props); | ||
} | ||
if (prevProp) { | ||
superArg = prevProp.get || prevProp.set ? | ||
adaptGet(prevProp.get) : prevProp.value; | ||
} else { | ||
superArg = name !== cname && empty[name]; | ||
} | ||
if (superArg && typeof superArg != 'function') { | ||
dcl._error('wrong super value arg', base, name, index, props); | ||
} | ||
newProp.value = prop.value.spr.around(superArg); | ||
if (typeof newProp.value != 'function') { | ||
dcl._error('wrong super value result', base, name, index, props); | ||
} | ||
state.prop = null; | ||
} | ||
if (!prop.value || isSuper(prop.value) && !prop.value.spr.around) { | ||
return; // skip descriptor: no actionable value | ||
} | ||
} | ||
if (state.prop) { | ||
if (newProp.get || newProp.set) { | ||
if (state.backlog.length) { | ||
state.backlog = []; | ||
} | ||
} else { | ||
state.backlog.push(convertToValue(state.prop)); | ||
} | ||
} | ||
state.prop = newProp; | ||
}); | ||
processBacklog(state, weaver); | ||
return weaver.stop ? weaver.stop(state) : state.prop; | ||
} | ||
var dclUtils = {adaptValue: adaptValue, adaptGet: adaptGet, | ||
convertToValue: convertToValue, cloneDescriptor: cloneDescriptor, | ||
augmentDescriptor: augmentDescriptor, augmentWritable: augmentWritable, | ||
replaceDescriptor: replaceDescriptor, replaceWritable: replaceWritable | ||
}; | ||
function processBacklog (state, weaver) { | ||
if (state.backlog.length) { | ||
state.backlog.push(convertToValue(state.prop)); | ||
state.prop = weaver.weave(state.backlog, dclUtils); | ||
state.backlog = []; | ||
} | ||
} | ||
function adaptValue (f) { | ||
return f ? function () { return f; } : null; | ||
} | ||
function adaptGet (f) { | ||
return f ? function () { return f.call(this).apply(this, arguments); } : null; | ||
} | ||
function convertToValue (prop) { | ||
if (prop.get || prop.set) { | ||
var newProp = cloneDescriptor(prop); | ||
delete newProp.get; | ||
delete newProp.set; | ||
newProp.value = adaptGet(prop.get); | ||
return newProp; | ||
} | ||
return prop; | ||
} | ||
// dcl helpers | ||
function getAccessorSideAdvices (name, bases, propName) { | ||
var before = [], after = []; | ||
bases.forEach(function (base) { | ||
if (base[mname]) { | ||
var prop = base[mname].props[name]; | ||
if (typeof prop == 'object') { | ||
if (prop.get || prop.set) { | ||
var f = prop[propName]; | ||
if (isSuper(f)) { | ||
f.spr.before && before.push(f.spr.before); | ||
f.spr.after && after .push(f.spr.after); | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
if (before.length > 1) { before.reverse(); } | ||
return {before: before, after: after}; | ||
} | ||
function getDataSideAdvices (name, bases) { | ||
var before = [], after = []; | ||
bases.forEach(function (base) { | ||
if (base[mname]) { | ||
var prop = base[mname].props[name]; | ||
if (typeof prop == 'object') { | ||
var f = prop.get || prop.set ? prop.get : prop.value; | ||
if (isSuper(f)) { | ||
f.spr.before && before.push(f.spr.before); | ||
f.spr.after && after .push(f.spr.after); | ||
} | ||
} | ||
} | ||
}); | ||
if (before.length > 1) { before.reverse(); } | ||
return {before: before, after: after}; | ||
} | ||
function makeStub (aroundStub, beforeChain, afterChain) { | ||
var beforeLength = beforeChain.length, afterLength = afterChain.length, | ||
stub = function () { | ||
var result, thrown, i; | ||
// running the before chain | ||
beforeChain.apply(this, arguments); | ||
for (i = 0; i < beforeLength; ++i) { | ||
beforeChain[i].apply(this, arguments); | ||
} | ||
// running the around chain | ||
try{ | ||
r = aroundChain.apply(this, arguments); | ||
}catch(e){ | ||
r = e; | ||
thrown = true; | ||
if (aroundStub) { | ||
try { | ||
result = aroundStub.apply(this, arguments); | ||
} catch (error) { | ||
result = error; | ||
thrown = true; | ||
} | ||
} | ||
// running the after chain | ||
afterChain.call(this, arguments, r); | ||
if(thrown){ | ||
throw r; | ||
for (i = 0; i < afterLength; ++i) { | ||
afterChain[i].call(this, arguments, result, makeReturn, makeThrow); | ||
} | ||
return r; | ||
if (thrown) { | ||
throw result; | ||
} | ||
return result; | ||
function makeReturn (value) { result = value; thrown = false; } | ||
function makeThrow (value) { result = value; thrown = true; } | ||
}; | ||
stub.advices = {before: before, after: after, around: around}; | ||
stub.advices = {around: aroundStub, before: beforeChain, after: afterChain}; | ||
return stub; | ||
} | ||
function chain(id){ | ||
return function(ctor, name){ | ||
var meta = ctor._meta, rule; | ||
if(meta){ | ||
rule = +meta.weaver[name] || 0; | ||
if(rule && rule != id){ | ||
dcl._error("set chaining", name, ctor, id, rule); | ||
} | ||
meta.weaver[name] = id; | ||
function makeCtr (baseClass, finalProps, meta) { | ||
var proto = baseClass ? | ||
Object.create(baseClass[pname], finalProps) : | ||
Object.defineProperties({}, finalProps), | ||
ctr = proto[cname]; | ||
ctr[mname] = meta; | ||
ctr[pname] = proto; | ||
meta.bases[meta.bases.length - 1] = ctr; | ||
return ctr; | ||
} | ||
// MODULE: weavers | ||
function weaveAround (chain, utils) { | ||
var newProp = utils.cloneDescriptor(chain[chain.length - 1]); | ||
if (newProp.get || newProp.set) { | ||
// convert to value | ||
newProp.value = utils.adaptGet(newProp.get); | ||
delete newProp.get; | ||
delete newProp.set; | ||
} | ||
return newProp; | ||
} | ||
function weaveChain (chain, utils) { | ||
if (this.reverse) { | ||
chain.reverse(); | ||
} | ||
var newProp = utils.cloneDescriptor(chain[chain.length - 1]); | ||
// extract functions | ||
chain = chain.map(function (prop) { | ||
return prop.get || prop.set ? utils.adaptGet(prop.get) : prop.value; | ||
}); | ||
newProp.value = function () { | ||
for (var i = 0; i < chain.length; ++i) { | ||
chain[i].apply(this, arguments); | ||
} | ||
}; | ||
return newProp; | ||
} | ||
dcl.mix(dcl, { | ||
// public API | ||
Advice: Advice, | ||
advise: advise, | ||
// expose helper methods | ||
before: function(f){ return dcl.advise({before: f}); }, | ||
after: function(f){ return dcl.advise({after: f}); }, | ||
around: dcl.superCall, | ||
// chains | ||
chainBefore: chain(1), | ||
chainAfter: chain(2), | ||
isInstanceOf: function(o, ctor){ | ||
if(o instanceof ctor){ | ||
return true; | ||
// MODULE: dcl (the main function) | ||
function dcl (superClass, props, options) { | ||
// parse arguments | ||
if (superClass instanceof Array) { | ||
// skip | ||
} else if (typeof superClass == 'function') { | ||
superClass = [superClass]; | ||
} else if (!superClass) { | ||
superClass = []; | ||
} else { | ||
options = props; | ||
props = superClass; | ||
superClass = []; | ||
} | ||
props = toProperties(props || {}, options || {}); | ||
// find the base class, and mixins | ||
var bases = [], baseClass = superClass[0], mixins = [], baseIndex = -1; | ||
if (superClass.length) { | ||
if (superClass.length > 1) { | ||
bases = c3mro(superClass, props).reverse(); | ||
if (baseClass[mname]) { | ||
baseIndex = baseClass[mname].bases.length - 1; | ||
} else { | ||
mixins = bases.slice(1); | ||
baseIndex = 0; | ||
} | ||
} else { | ||
if (baseClass[mname]) { | ||
bases = baseClass[mname].bases.slice(0); | ||
baseIndex = bases.length - 1; | ||
} else { | ||
bases = [baseClass]; | ||
baseIndex = 0; | ||
} | ||
} | ||
var t = o.constructor._meta, i; | ||
if(t){ | ||
for(t = t.bases, i = t.length - 1; i >= 0; --i){ | ||
if(t[i] === ctor){ | ||
return true; | ||
if (bases[baseIndex] === baseClass) { | ||
mixins = bases.slice(baseIndex + 1); | ||
} else { | ||
baseClass = null; | ||
mixins = bases.slice(0); | ||
} | ||
} | ||
// add a stand-in for our future constructor | ||
var faux = {}, special = {}; | ||
faux[mname] = {bases: bases, props: props, special: special}; | ||
dcl.chainAfter(faux, cname); | ||
bases.push(faux); | ||
mixins.push(faux); | ||
// collect meta | ||
// merge from bases | ||
superClass.forEach(function (base) { | ||
if (base[mname]) { | ||
var baseSpecial = base[mname].special; | ||
Object.keys(baseSpecial).forEach(function (name) { | ||
dcl.chainWith(faux, name, baseSpecial[name]); | ||
}); | ||
} | ||
}); | ||
// inspect own props | ||
Object.keys(props).forEach(function (name) { | ||
if (!special.hasOwnProperty(name)) { | ||
var prop = props[name]; | ||
if (prop.get || prop.set) { | ||
if (isSuper(prop.get) || isSuper(prop.set)) { | ||
dcl.chainWith(faux, name, dcl.weaveSuper); | ||
} | ||
} else { | ||
if (isSuper(prop.value)) { | ||
dcl.chainWith(faux, name, dcl.weaveSuper); | ||
} | ||
} | ||
} | ||
return false; | ||
}, | ||
// protected API starts with _ (don't use it!) | ||
_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); | ||
}); | ||
// collect simple props, and a list of special props | ||
var finalProps = {}, finalSpecial = populateProps(finalProps, mixins, special); | ||
if (!finalSpecial.hasOwnProperty(cname)) { | ||
finalSpecial[cname] = special.hasOwnProperty(cname) ? special[cname] : dcl.weaveAfter; | ||
} | ||
// process special props | ||
Object.keys(finalSpecial).forEach(function (name) { | ||
var prop = weaveProp(name, bases, finalSpecial[name], props); | ||
if (!prop) { | ||
prop = {configurable: true, enumerable: false, writable: true, value: function nop () {}}; | ||
} | ||
var newProp = cloneDescriptor(prop), advices; | ||
if (prop.get || prop.set) { | ||
// accessor descriptor | ||
advices = getAccessorSideAdvices(name, bases, 'get'); | ||
newProp.get = dcl._makeStub(prop.get, advices.before, advices.after); | ||
advices = getAccessorSideAdvices(name, bases, 'set'); | ||
newProp.set = dcl._makeStub(prop.set, advices.before, advices.after); | ||
} else { | ||
// data descriptor | ||
advices = getDataSideAdvices(name, bases); | ||
var stub = dcl._makeStub(prop.value, advices.before, advices.after); | ||
advices = getAccessorSideAdvices(name, bases, 'set'); | ||
stub.advices.set = advices; | ||
newProp.value = stub; | ||
} | ||
finalProps[name] = newProp; | ||
}); | ||
return dcl._makeCtr(baseClass, finalProps, faux[mname]); | ||
} | ||
// build export | ||
// guts, do not use them! | ||
dcl._error = function (msg) { | ||
throw new Error(msg); | ||
}; | ||
dcl._makeSuper = makeSuper; | ||
dcl._makeCtr = makeCtr; | ||
dcl._makeStub = makeStub; | ||
// utilities | ||
dcl.collectPropertyDescriptors = collectPropertyDescriptors; | ||
dcl.getPropertyDescriptor = getPropertyDescriptor; | ||
// meta | ||
dcl.Prop = function Prop (x) { this.x = x; }; | ||
dcl.prop = function prop(x) { return new dcl.Prop(x); }; | ||
dcl.isInstanceOf = function isInstanceOf (o, ctr) { | ||
if (o instanceof ctr) { | ||
return true; | ||
} | ||
if (o && o[cname] && o[cname][mname]) { | ||
for (var bases = o[cname][mname].bases, i = bases.length - 2; i >= 0; --i) { | ||
var base = bases[i]; | ||
if (base === ctr || !base[mname] && base[pname] instanceof ctr) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}; | ||
// chains | ||
function chainWith (ctr, name, weaver) { | ||
if (ctr && ctr[mname]) { | ||
var special = ctr[mname].special; | ||
if (special.hasOwnProperty(name)) { | ||
var own = special[name]; | ||
if (own === weaver || own.name === weaver.name || weaver.name === 'super') { | ||
return true; | ||
} | ||
if (own.name !== 'super') { | ||
dcl._error('different weavers: ' + name, ctr, name, weaver, own); | ||
} | ||
} | ||
special[name] = weaver; | ||
return true; | ||
} | ||
return false; | ||
} | ||
dcl.weaveBefore = {name: 'before', weave: weaveChain, reverse: true}; | ||
dcl.weaveAfter = {name: 'after', weave: weaveChain}; | ||
dcl.weaveSuper = {name: 'super', weave: weaveAround}; | ||
dcl.chainWith = chainWith; | ||
dcl.chainBefore = function (ctr, name) { return dcl.chainWith(ctr, name, dcl.weaveBefore); }; | ||
dcl.chainAfter = function (ctr, name) { return dcl.chainWith(ctr, name, dcl.weaveAfter); }; | ||
// super & AOP | ||
function makeSuper (advice, S) { | ||
var f = function superNop () {}; | ||
f.spr = new S(advice); | ||
return f; | ||
} | ||
function isSuper (f) { return f && f.spr instanceof dcl.Super; } | ||
dcl.Super = function Super (f) { this.around = f; }; | ||
dcl.isSuper = isSuper; | ||
dcl.Super[pname].declaredClass = 'dcl.Super'; | ||
dcl.Advice = dcl(dcl.Super, { | ||
declaredClass: 'dcl.Advice', | ||
constructor: function () { | ||
this.before = this.around.before; | ||
this.after = this.around.after; | ||
this.around = this.around.around; | ||
} | ||
}); | ||
dcl.advise = function (advice) { return dcl._makeSuper(advice, dcl.Advice); }; | ||
dcl.superCall = dcl.around = function (f) { return dcl._makeSuper(f, dcl.Super); }; | ||
dcl.before = function (f) { return dcl.advise({before: f}); }; | ||
dcl.after = function (f) { return dcl.advise({after: f}); }; | ||
// export | ||
return dcl; | ||
}); |
353
debug.js
@@ -1,23 +0,14 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define(["./mini", "./advise"], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(require("./mini"), require("./advise")); | ||
}else{ | ||
dclDebug = factory(dcl, advise); | ||
/* 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)}))}) | ||
(['./dcl', './advise'], function (dcl, advise) { | ||
'use strict'; | ||
// set up custom names | ||
var mname = '_meta', pname = 'prototype', cname = 'constructor'; | ||
function DclError (message) { | ||
this.name = 'DclError'; | ||
this.message = message || 'Default Message'; | ||
this.stack = (new Error()).stack; | ||
} | ||
})(function(dcl, advise){ | ||
function DclError(message){ | ||
if(Error.captureStackTrace){ | ||
Error.captureStackTrace(this, DclError); | ||
} | ||
var e = Error.call(this, message), name; | ||
dcl.allKeys(e).forEach(function(name){ | ||
if(e.hasOwnProperty(name)){ | ||
this[name] = e[name]; | ||
} | ||
}); | ||
this.message = message; | ||
} | ||
DclError.prototype = dcl.delegate(Error.prototype); | ||
DclError.prototype = Object.create(Error.prototype); | ||
DclError.prototype.constructor = DclError; | ||
@@ -27,211 +18,159 @@ | ||
ChainingError = dcl(DclError, {declaredClass: "dcl/debug/ChainingError"}), | ||
SetChainingError = dcl(DclError, {declaredClass: "dcl/debug/SetChainingError"}), | ||
SuperCallError = dcl(DclError, {declaredClass: "dcl/debug/SuperCallError"}), | ||
SuperError = dcl(DclError, {declaredClass: "dcl/debug/SuperError"}), | ||
SuperResultError = dcl(DclError, {declaredClass: "dcl/debug/SuperResultError"}); | ||
SuperError = dcl(DclError, {declaredClass: "dcl/debug/SuperError"}); | ||
var chainNames = ["UNCHAINED BUT CONTAINS ADVICE(S)", "CHAINED BEFORE", "CHAINED AFTER", | ||
"ERRONEOUSLY CHAINED BEFORE AND AFTER"]; | ||
function chainName(id){ | ||
return id >= 0 && id <= 3 ? chainNames[id] : "UNKNOWN (" + id + ")"; | ||
} | ||
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){ | ||
var cName, someUnknown, i, base, name, names = [], c = {}; | ||
switch(reason){ | ||
case "cycle": | ||
cName = a1.hasOwnProperty("declaredClass") && a1.declaredClass; | ||
someUnknown = !cName; | ||
for(i = a2.length - 1; i >= 0; --i){ | ||
base = a2[i][0]; | ||
name = base.prototype.hasOwnProperty("declaredClass") && base.prototype.declaredClass; | ||
if(!name){ | ||
name = "UNNAMED_" + base._uniqueId; | ||
someUnknown = true; | ||
} | ||
if(!c[name]){ | ||
names.push(name); | ||
c[name] = 1; | ||
} | ||
} | ||
throw new CycleError("dcl: base class cycle found in: " + (cName || "UNNAMED") + | ||
" - bases: " + names.join(", ") + " are mutually dependent" + | ||
(someUnknown ? noDecls : "")); | ||
case "chain": | ||
cName = a2.prototype.hasOwnProperty("declaredClass") && a2.prototype.declaredClass; | ||
name = a4.prototype.hasOwnProperty("declaredClass") && a4.prototype.declaredClass; | ||
someUnknown = !(cName && name); | ||
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._uniqueId)) + " sets it to " + chainName(a5) + | ||
(someUnknown ? noDecls : "")); | ||
case "set chaining": | ||
cName = a2.prototype.hasOwnProperty("declaredClass") && a2.prototype.declaredClass; | ||
someUnknown = !cName; | ||
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) + | ||
(someUnknown ? noDecls : "")); | ||
case "wrong super call": | ||
cName = a1.prototype.hasOwnProperty("declaredClass") && a1.prototype.declaredClass; | ||
someUnknown = !cName; | ||
throw new SuperCallError("dcl: argument of around advice or supercall decorator should be a function in: " + | ||
(cName || ("UNNAMED_" + a1._uniqueId)) + ", method: " + a2 + (someUnknown ? noDecls : "")); | ||
case "wrong super": | ||
cName = a1.prototype.hasOwnProperty("declaredClass") && a1.prototype.declaredClass; | ||
someUnknown = !cName; | ||
throw new SuperError("dcl: super method should be a function in: " + | ||
(cName || ("UNNAMED_" + a1._uniqueId)) + ", method: " + a2 + (someUnknown ? noDecls : "")); | ||
case "wrong super result": | ||
cName = a1.prototype.hasOwnProperty("declaredClass") && a1.prototype.declaredClass; | ||
someUnknown = !cName; | ||
throw new SuperResultError("dcl: around advice or supercall should return a function in: " + | ||
(cName || ("UNNAMED_" + a1._uniqueId)) + ", method: " + a2 + (someUnknown ? noDecls : "")); | ||
} | ||
throw new DclError("dcl: " + reason); | ||
}; | ||
}); | ||
advise.after(dcl, "_postprocess", function(args, ctor){ | ||
// validate that chaining is consistent | ||
var meta = ctor._meta, weaver = meta.weaver, bases = meta.bases, | ||
name, chain, base, i, rule; | ||
dcl.allKeys(weaver).forEach(function(name){ | ||
chain = (+weaver[name] || 0); | ||
for(i = bases.length - 1; i >= 0; --i){ | ||
base = bases[i]; | ||
meta = base._meta; | ||
if(meta){ | ||
rule = (+meta.weaver[name] || 0); | ||
if(chain != rule && (!chain || rule)){ | ||
dcl._error("chain", name, ctor, chain, base, rule); | ||
} | ||
advise.around(dcl, '_error', function (sup) { | ||
return function (reason) { | ||
var name, ctr, method, props; | ||
if (reason === 'cycle') { | ||
var bases = arguments[1], | ||
names = bases.map(function (base, index) { | ||
return base[pname].declaredClass || ('UNNAMED_' + index); | ||
}); | ||
props = arguments[2]; | ||
name = props.declaredClass && props.declaredClass.value; | ||
if (!name || typeof name != 'string') { | ||
name = 'UNNAMED'; | ||
} | ||
throw new CycleError('dcl: base class cycle in ' + name + | ||
', bases (' + names.join(', ') + ') are mutually dependent'); | ||
} | ||
}); | ||
}); | ||
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 (/^different weavers\b/.test(reason)) { | ||
var weaver = arguments[3], own = arguments[4]; | ||
ctr = arguments[1]; | ||
method = arguments[2]; | ||
name = ctr[mname].props.declaredClass && ctr[mname].props.declaredClass.value || 'UNNAMED'; | ||
throw new ChainingError('dcl: conflicting chain directives in ' + | ||
name + ' for ' + method + ', was ' + own.name + ', set to ' + weaver.name); | ||
} | ||
if(previous && typeof previous != "function"){ | ||
dcl._error("wrong super", advice.ctr, node); | ||
if (/^wrong super\b/.test(reason)) { | ||
var index = arguments[3]; | ||
ctr = arguments[1]; | ||
method = arguments[2]; | ||
props = arguments[4]; | ||
name = props.declaredClass && props.declaredClass.value; | ||
if (!name || typeof name != 'string') { | ||
name = 'UNNAMED'; | ||
} | ||
var re = /^wrong super (\w+) (\w+)$/.exec(reason), | ||
baseName = ctr[mname].props.declaredClass && | ||
ctr[mname].props.declaredClass.value || | ||
('UNNAMED_' + index); | ||
throw new SuperError('dcl: super call error in ' + | ||
name + ', while weaving ' + baseName + ', method ' + method + | ||
' (' + re[1] + ') wrong ' + re[2]); | ||
} | ||
var t = advice.spr.around(previous); | ||
if(typeof t != "function"){ | ||
dcl._error("wrong super result", advice.ctr, node); | ||
} | ||
t.ctr = advice.ctr; | ||
return t; | ||
return sup.apply(this, arguments); | ||
}; | ||
}); | ||
advise(advise, "_instantiate", { | ||
before: function(advice, previous, node){ | ||
if(typeof advice != "function"){ | ||
dcl._error("wrong super call", node.instance.constructor, node.name); | ||
advise.around(advise, '_error', function (sup) { | ||
return function (reason, instance, method, type) { | ||
var re = /^wrong super (\w+)$/.exec(reason); | ||
if (re) { | ||
var baseName = instance.declaredClass; | ||
if (!baseName || typeof baseName != 'string') { | ||
baseName = 'UNNAMED'; | ||
} | ||
throw new SuperError('dcl: super call error in object of ' + | ||
baseName + ', while weaving method ' + method + | ||
' (' + type + ') wrong ' + re[1]); | ||
} | ||
if(previous && typeof previous != "function"){ | ||
dcl._error("wrong super", node.instance.constructor, node.name); | ||
} | ||
}, | ||
after: function(a, result){ | ||
if(typeof result != "function"){ | ||
dcl._error("wrong super result", a[2].instance.constructor, a[2].name); | ||
} | ||
} | ||
return sup.apply(this, arguments); | ||
}; | ||
}); | ||
function logCtor(ctor){ | ||
var meta = ctor._meta; | ||
if(!meta){ | ||
console.log("*** class does not have meta information compatible with dcl"); | ||
function logCtor (ctor) { | ||
var meta = ctor[mname]; | ||
if (!meta) { | ||
console.log('*** class does not have meta information compatible with dcl'); | ||
return; | ||
} | ||
var weaver = meta.weaver, bases = meta.bases, chains = meta.chains, names = [], base, name, someUnknown, i; | ||
for(i = 0; i < bases.length; ++i){ | ||
base = bases[i]; | ||
name = base.prototype.hasOwnProperty("declaredClass") && base.prototype.declaredClass; | ||
if(!name){ | ||
name = "UNNAMED_" + (base.hasOwnProperty("_uniqueId") ? base._uniqueId : ""); | ||
someUnknown = true; | ||
} | ||
names.push(name); | ||
var names = meta.bases.map(function (base, index) { | ||
return base[pname].declaredClass || ('UNNAMED_' + index); | ||
}); | ||
console.log('*** class ' + names[names.length - 1] + ' depends on ' + | ||
(names.length - 1) + (names.length == 2 ? ' class' : ' classes') + | ||
(names.length > 1 ? ': ' + names.slice(0, -1).join(', ') : '') | ||
); | ||
var specialKeys = Object.keys(meta.special); | ||
if (specialKeys.length) { | ||
console.log('*** class ' + names[names.length - 1] + ' has ' + | ||
specialKeys.length + (specialKeys.length == 1 ? ' weaver: ' : ' weavers: ') + | ||
specialKeys.map(function (name) { | ||
return name + ': ' + meta.special[name].name; | ||
}).join(', ') | ||
); | ||
} | ||
console.log("*** class " + names[0] + " depends on " + (names.length - 1) + " classes"); | ||
if(names.length > 1){ | ||
console.log(" dependencies: " + names.slice(1).join(", ")); | ||
} | ||
if(someUnknown){ | ||
console.log(" " + noDecls); | ||
} | ||
dcl.allKeys(weaver).forEach(function(name){ | ||
i = +weaver[name]; | ||
if(!isNaN(i)){ | ||
var hasStub = typeof ctor.prototype[name].advices == "object"; | ||
if(hasStub){ | ||
var b = dcl._extractChain(bases, name, "b").length, | ||
f = dcl._extractChain(bases, name, "f").length, | ||
a = dcl._extractChain(bases, name, "a").length; | ||
} | ||
console.log(" class method " + name + " is " + chainName(i) + | ||
(hasStub ? | ||
", and has an AOP stub (before: " + b + ", around: " + f + ", after: " + a + ")" : | ||
" (length: " + chains[name].length + ")" )); | ||
} | ||
}); | ||
} | ||
function countAdvices(node, chain){ | ||
for(var counter = 0, p = node[chain]; p != node; p = p[chain], ++counter); | ||
return counter; | ||
function logAdvices (advices) { | ||
return 'class-level advice (before ' + advices.before.length + | ||
', after ' + advices.after.length + ')'; | ||
} | ||
function log(o, suppressCtor){ | ||
switch(typeof o){ | ||
case "function": | ||
logCtor(o); | ||
return; | ||
case "object": | ||
var base = o.constructor, | ||
name = base.prototype.hasOwnProperty("declaredClass") && base.prototype.declaredClass; | ||
if(!name){ | ||
name = "UNNAMED_" + (base.hasOwnProperty("_uniqueId") ? base._uniqueId : ""); | ||
} | ||
console.log("*** object of class " + name); | ||
// log the constructor | ||
if(!suppressCtor){ | ||
logCtor(base); | ||
} | ||
// log methods | ||
dcl.allKeys(o).forEach(function(name){ | ||
var f = o[name], b, r, a; | ||
if(typeof f == "function"){ | ||
if(f.adviceNode && f.adviceNode instanceof advise.Node){ | ||
b = countAdvices(f.adviceNode, "pb"); | ||
r = countAdvices(f.adviceNode, "pf"); | ||
a = countAdvices(f.adviceNode, "pa"); | ||
console.log(" object method " + name + " has an AOP stub (before: " + | ||
b + ", around: " + r + ", after: " + a + ")"); | ||
function countAdvices (root, chain) { | ||
var total = 0; | ||
for (var node = root[chain]; node && node !== root; node = node[chain], ++total); | ||
return total; | ||
} | ||
function logNode (node) { | ||
return 'object-level advice (before ' + countAdvices(node, 'next_before') + | ||
', after ' + countAdvices(node, 'next_after') + ')'; | ||
} | ||
function log (o, suppressCtor) { | ||
if (typeof o == 'function') { | ||
logCtor(o); | ||
} else if (o && typeof o == 'object') { | ||
var base = o[cname]; | ||
if (base[pname].declaredClass) { | ||
console.log('*** object of class ' + base[pname].declaredClass); | ||
} | ||
if (!suppressCtor) { | ||
logCtor(base); | ||
} | ||
allKeys(o).forEach(function (name) { | ||
var prop = dcl.getPropertyDescriptor(o, name); | ||
if (prop.get || prop.set) { | ||
if (prop.get) { | ||
if (prop.get.node instanceof advise.Node) { | ||
console.log(' ' + name + ': getter with ' + logNode(prop.get.node)); | ||
} else if (typeof prop.get.advices == 'object') { | ||
console.log(' ' + name + ': getter with ' + logAdvices(prop.get.advices)); | ||
} | ||
} | ||
}); | ||
return; | ||
if (prop.set) { | ||
if (prop.set.node instanceof advise.Node) { | ||
console.log(' ' + name + ': setter with ' + logNode(prop.set.node)); | ||
} else if (typeof prop.set.advices == 'object') { | ||
console.log(' ' + name + ': setter with ' + logAdvices(prop.set.advices)); | ||
} | ||
} | ||
} else { | ||
if (prop.value.node instanceof advise.Node) { | ||
console.log(' ' + name + ': ' + logNode(prop.value.node)); | ||
} else if (typeof prop.value.advices == 'object') { | ||
console.log(' ' + name + ': ' + logAdvices(prop.value.advices)); | ||
} | ||
} | ||
}); | ||
} | ||
console.log(o); | ||
} | ||
return { | ||
log: log, | ||
DclError: DclError, | ||
CycleError: CycleError, | ||
ChainingError: ChainingError, | ||
SetChainingError: SetChainingError, | ||
SuperCallError: SuperCallError, | ||
SuperError: SuperError, | ||
SuperResultError: SuperResultError | ||
}; | ||
dcl.log = log; | ||
dcl.DclError = DclError; | ||
dcl.CycleError = CycleError; | ||
dcl.ChainingError = ChainingError; | ||
dcl.SuperError = SuperError; | ||
return dcl; | ||
function allKeys (o) { | ||
var keys = []; | ||
for (var key in o) { | ||
keys.push(key); | ||
} | ||
return keys; | ||
} | ||
}); |
@@ -1,23 +0,17 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define(["../dcl", "./Destroyable"], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(require("../dcl"), require("./Destroyable")); | ||
}else{ | ||
dclMixinsCleanup = factory(dcl, dclMixinsDestroyable); | ||
} | ||
})(function(dcl, Destroyable){ | ||
"use strict"; | ||
/* 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)}))}) | ||
(['../dcl', './Destroyable'], function (dcl, Destroyable) { | ||
'use strict'; | ||
return dcl(Destroyable, { | ||
declaredClass: "dcl/mixins/Cleanup", | ||
constructor: function(){ | ||
declaredClass: 'dcl/mixins/Cleanup', | ||
constructor: function () { | ||
this.__cleanupStack = []; | ||
}, | ||
pushCleanup: function(resource, cleanup){ | ||
var f = cleanup ? function(){ cleanup(resource); } : function(){ resource.destroy(); }; | ||
pushCleanup: function (resource, cleanup) { | ||
var f = cleanup ? function () { cleanup(resource); } : function () { resource.destroy(); }; | ||
this.__cleanupStack.push(f); | ||
return f; | ||
}, | ||
popCleanup: function(dontRun){ | ||
if(dontRun){ | ||
popCleanup: function (dontRun) { | ||
if (dontRun) { | ||
return this.__cleanupStack.pop(); | ||
@@ -27,5 +21,5 @@ } | ||
}, | ||
removeCleanup: function(f){ | ||
for(var i = this.__cleanupStack.length - 1; i >= 0; --i){ | ||
if(this.__cleanupStack[i] === f){ | ||
removeCleanup: function (f) { | ||
for (var i = this.__cleanupStack.length - 1; i >= 0; --i) { | ||
if (this.__cleanupStack[i] === f) { | ||
this.__cleanupStack.splice(i, 1); | ||
@@ -36,8 +30,8 @@ return true; | ||
}, | ||
cleanup: function(){ | ||
while(this.__cleanupStack.length){ | ||
cleanup: function () { | ||
while (this.__cleanupStack.length) { | ||
this.__cleanupStack.pop()(); | ||
} | ||
}, | ||
destroy: function(){ | ||
destroy: function () { | ||
this.cleanup(); | ||
@@ -44,0 +38,0 @@ } |
@@ -1,14 +0,9 @@ | ||
(function(factory){ | ||
if(typeof define != "undefined"){ | ||
define(["../dcl"], factory); | ||
}else if(typeof module != "undefined"){ | ||
module.exports = factory(require("../dcl")); | ||
}else{ | ||
dclMixinsDestroyable = factory(dcl); | ||
} | ||
})(function(dcl){ | ||
"use strict"; | ||
var Destroyable = dcl(null, {declaredClass: "dcl/mixins/Destroyable"}); | ||
dcl.chainBefore(Destroyable, "destroy"); | ||
/* 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)}))}) | ||
(['../dcl'], function (dcl) { | ||
'use strict'; | ||
var Destroyable = dcl(null, {declaredClass: 'dcl/mixins/Destroyable'}); | ||
dcl.chainBefore(Destroyable, 'destroy'); | ||
return Destroyable; | ||
}); |
{ | ||
"name": "dcl", | ||
"version": "1.1.3", | ||
"version": "2.0.0", | ||
"description": "Elegant minimalistic implementation of OOP with mixins + AOP.", | ||
"author": "Eugene Lazutkin <eugene.lazutkin@gmail.com> (http://lazutkin.com/)", | ||
"license": "BSD-3-Clause", | ||
"homepage": "http://www.dcljs.org", | ||
@@ -13,6 +15,8 @@ "bugs": "http://github.com/uhop/dcl/issues", | ||
"devDependencies": { | ||
"heya-unit": ">=0.1" | ||
"heya-unit": ">=0.1", | ||
"heya-globalize": "^1.0.3" | ||
}, | ||
"scripts": { | ||
"test": "node tests/tests.js" | ||
"test": "node tests/tests.js", | ||
"dist": "node node_modules/heya-globalize/index.js" | ||
}, | ||
@@ -32,15 +36,8 @@ "github": "http://github.com/uhop/dcl", | ||
], | ||
"author": "Eugene Lazutkin <eugene.lazutkin@gmail.com> (http://lazutkin.com/)", | ||
"licenses": [ | ||
{ | ||
"type": "New BSD", | ||
"url": "http://github.com/uhop/dcl/blob/master/LICENSE" | ||
}, | ||
{ | ||
"type": "AFL 2.1", | ||
"url": "http://github.com/uhop/dcl/blob/master/LICENSE" | ||
} | ||
], | ||
"icon": "http://www.dcljs.org/fav144.png", | ||
"dojoBuild": "package.js" | ||
"browserGlobals": { | ||
"!root": "dcl", | ||
"./dcl": "dcl", | ||
"./advise": "advise", | ||
"./debug": "!dcl" | ||
} | ||
} |
507
README.md
@@ -1,2 +0,2 @@ | ||
# DCL | ||
# `dcl` | ||
@@ -8,3 +8,2 @@ [![Build status][travis-image]][travis-url] | ||
A minimalistic yet complete JavaScript package for [node.js](http://nodejs.org) | ||
@@ -23,440 +22,236 @@ and modern browsers that implements OOP with mixins + AOP at both "class" and | ||
If you migrate your code from a legacy framework that implements dynamic (rather | ||
than static) supercalls, take a look at the module "inherited" that dispatches | ||
supercalls dynamically trading off the simplicity of the code for some run-time | ||
CPU use, and a little bit less convenient debugging of such calls due to an extra | ||
stub between your methods. | ||
Based on ES5, the `dcl 2.x` works on Node and all ES5-compatible browsers. It fully | ||
supports property descriptors, including AOP advices for getters and setters, | ||
as well as regular values. If your project needs to support legacy browsers, | ||
please consider `dcl 1.x`. | ||
The library includes a small library of useful base classes, mixins, and advices. | ||
The main hub of everything `dcl`-related is [dcljs.org](http://www.dcljs.org/), | ||
which hosts [extensive documentation](http://www.dcljs.org/docs/). | ||
## How to install | ||
# Examples | ||
If you plan to use it in your [node.js](http://nodejs.org) project, install it | ||
like this: | ||
Create simple class: | ||
```js | ||
var A = dcl({ | ||
constructor: function (x) { this.x = x; }, | ||
m: function () { return this.x; } | ||
}); | ||
``` | ||
npm install dcl | ||
``` | ||
For your browser-based projects I suggest to use [volo.js](http://volojs.org): | ||
Single inheritance: | ||
``` | ||
volo install uhop/dcl | ||
``` | ||
## How to use | ||
```js | ||
// if you run node.js, or CommonJS-compliant system | ||
var dcl = require("dcl"); | ||
var B = dcl(A, { | ||
// no constructor | ||
// constructor of A will be called automatically | ||
// if you use dcl in a browser with AMD (like RequireJS): | ||
require(["dcl"], function(dcl){ | ||
// the same code that uses dcl | ||
m: function () { return this.x + 1; } | ||
}); | ||
// or when you define your own module: | ||
define(["dcl"], function(dcl){ | ||
// your dcl-using code goes here | ||
}); | ||
``` | ||
### Inheritance, constructors, super calls | ||
Multiple inheritance with mixins: | ||
Let's continue with our coding example: | ||
```js | ||
// declare a class derived from Object: | ||
var Person = dcl(null, { | ||
// (optional, but recommended) name your class: | ||
declaredClass: "Person", | ||
// let's specify a default name as a class-level constant | ||
name: "Anonymous", | ||
// constructor is a method named ... 'constructor' | ||
constructor: function(name){ | ||
if(name){ | ||
this.name = name; | ||
} | ||
console.log("Person " + this.name + " is constructed"); | ||
} | ||
var M = dcl({ | ||
sqr: function () { var x = this.m(); return x * x; } | ||
}); | ||
// we can derive more classes from it using single inheritance | ||
var Bureaucrat = dcl(Person, { | ||
declaredClass: "Bureaucrat", | ||
constructor: function(name){ | ||
console.log("Bureaucrat " + this.name + " is constructed"); | ||
}, | ||
approve: function(document){ | ||
// NEVER! | ||
console.log("Rejected by " + this.name); | ||
return false; | ||
} | ||
}); | ||
var AM = dcl([A, M]); | ||
var BM = dcl([B, M]); | ||
var clerk = new Bureaucrat(); | ||
// Person Anonymous is constructed | ||
// Bureaucrat Anonymous is constructed | ||
clerk.approve(123); | ||
// Rejected by Anonymous | ||
var am = new AM(2); | ||
console.log(am.sqr()); // 4 | ||
var bm = new BM(2); | ||
console.log(bm.sqr()); // 9 | ||
``` | ||
As you can see it is trivial to define "classes" and derive them using | ||
single inheritance. Constructors are automatically chained and called from | ||
the farthest to the closest with the same arguments. Our Bureaucrat constructor | ||
ignores name, because it knows that Person will take care of it. | ||
Super call: | ||
Now let's do a mixin. | ||
```js | ||
// let's declare one more class that will be used as a mixin | ||
// any normal class would do | ||
var Speaker = dcl(null, { | ||
speak: function(msg){ | ||
// a method --- just a simple function | ||
console.log(this.name + ": " + msg); | ||
} | ||
var AMSuper = dcl([A, M], { | ||
m: dcl.superCall(function (sup) { | ||
return function () { | ||
return sup.call(this) + 1; | ||
}; | ||
}) | ||
}); | ||
// now we are ready to create Talker from Person + Speaker | ||
var Talker = dcl([Person, Speaker], { | ||
// no own methods for simplicity | ||
}); | ||
var alice = new Talker("Alice"); | ||
// Person Alice is constructed | ||
alice.speak("hello!"); | ||
// Alice: hello! | ||
var ams = new AMSuper(3); | ||
console.log(ams.sqr()); // 16 | ||
``` | ||
Now let's call a method of our super class. | ||
AOP advices: | ||
```js | ||
// let's declare another mixin, this time using a super call | ||
var Shouter = dcl(Speaker, { | ||
speak: dcl.superCall(function(sup){ | ||
// we use the double function technique to inject | ||
// "sup" --- a method from a super class | ||
return function(msg){ | ||
if(sup){ | ||
// theoretically it is possible that | ||
// there is no super method --- we can be last in line; | ||
// not in this case, though --- we are based | ||
// on Speaker meaning it will be always pulled in | ||
sup.call(this, msg.toUpperCase()); | ||
} | ||
}; | ||
}) | ||
var C = dcl(AMSuper, { | ||
constructor: dcl.advise({ | ||
before: function (x) { | ||
console.log('ctr arg:', x); | ||
}, | ||
after: function () { | ||
console.log('this.x:', this.x); | ||
} | ||
}), | ||
m: dcl.after(function (args, result, makeReturn) { | ||
console.log('m() returned:', result); | ||
// let's fix it | ||
makeReturn(5); | ||
}) | ||
}); | ||
var Sarge = dcl([Talker, Shouter], { | ||
// no own methods for simplicity | ||
}); | ||
var bob = new Sarge("Bob"); | ||
// Person Bob is constructed | ||
bob.speak("give me twenty!"); | ||
// Bob: GIVE ME TWENTY! | ||
var c = new C(1); | ||
// prints: | ||
// ctr arg: 1 | ||
// this.x: 1 | ||
console.log(c.sqr()); | ||
// prints: | ||
// m() returned: 2 | ||
// 25 | ||
``` | ||
The double function technique for a super call allows you to work directly with | ||
a next method in chain --- no intermediaries means that this call is as fast as | ||
it can be, no run-time penalties are involved during method calls, and it greatly | ||
simplifies debugging. | ||
Super call with getters: | ||
And, of course, our "classes" can be absolutely anonymous, like in this one-off "class": | ||
```js | ||
var loudBob = new (dcl([Talker, Shouter], {}))("Loud Bob"); | ||
// Person Loud Bob is constructed | ||
loudBob.speak("Anybody home?"); | ||
// Loud Bob: ANYBODY HOME? | ||
``` | ||
var G = dcl({ | ||
constructor: function (x) { this._x = x; }, | ||
get x () { return this._x; } | ||
}); | ||
### AOP | ||
var g = new G(1); | ||
console.log(g.x); // 1 | ||
We can use aspect-oriented advices to create our "classes": | ||
```js | ||
// one more mixin | ||
var Sick = dcl(Person, { | ||
speak: dcl.advise({ | ||
before: function(msg){ | ||
console.log(this.name + ": *hiccup* *hiccup* *hiccup*"); | ||
}, | ||
after: function(args, result){ | ||
console.log(this.name + ": *sniffle* I am so-o-o sick!"); | ||
} | ||
var F = dcl(G, { | ||
x: dcl.prop({ | ||
get: dcl.superCall(function (sup) { | ||
return function () { | ||
return sup.call(this) + 1; | ||
}; | ||
}) | ||
}) | ||
}); | ||
var SickTalker = dcl([Talker, Sick], { | ||
// no own methods for simplicity | ||
}); | ||
var clara = new SickTalker("Clara"); | ||
// Person Clara is constructed | ||
clara.speak("I want a glass of water!"); | ||
// Clara: *hiccup* *hiccup* *hiccup* | ||
// Clara: I want a glass of water! | ||
// Clara: *sniffle* I am so-o-o sick! | ||
var f = new F(1); | ||
console.log(f.x); // 2 | ||
``` | ||
Hmm, both `Talker` and `Sick` require the same "class" `Person`. How is it going | ||
to work? Don't worry, all duplicates are going to be eliminated by the underlying | ||
[C3 MRO](http://www.python.org/download/releases/2.3/mro/) algorithm. Read all | ||
about it in [the documentation](http://dcljs.org/docs/). | ||
Advise an object: | ||
Of course we can use an "around" advice as well, and it will behave just like | ||
a super call above. It will require the same double function technique to inject | ||
a method from a super class. | ||
```js | ||
// One more mixin | ||
var Martian = dcl(Speaker, { | ||
speak: dcl.around(function(sup){ | ||
return function(msg){ | ||
if(sup){ | ||
sup.call(this, "beep-beep-beep"); | ||
} | ||
}; | ||
}) | ||
}); | ||
function D (x) { this.x = x; } | ||
D.prototype.m = function (y) { return this.x + y; } | ||
// now we are ready for... | ||
var SickMartianSarge = dcl([Sarge, Sick, Martian], { | ||
// no own methods for simplicity | ||
var d = new D(1); | ||
console.log(d.m(2)); // 3 | ||
advise(d, 'm', { | ||
before: function (y) { console.log('y:', y); }, | ||
around: function (sup) { | ||
return function (y) { | ||
console.log('around'); | ||
return 2 * sup.call(this, y + 1); | ||
}; | ||
}, | ||
after: function (args, result) { | ||
console.log('# of args:', args.length); | ||
console.log('args[0]:', args[0]); | ||
console.log('result:', result); | ||
} | ||
}); | ||
var don = new SickMartianSarge("Don"); | ||
// Person Don is constructed | ||
don.speak("Doctor? Nurse? Anybody?"); | ||
// Don: *hiccup* *hiccup* *hiccup* | ||
// Don: BEEP-BEEP-BEEP | ||
// Don: *sniffle* I am so-o-o sick! | ||
console.log(d.m(2)); | ||
// prints: | ||
// y: 2 | ||
// around | ||
// # of args: 1 | ||
// args[0]: 2 | ||
// result: 8 | ||
``` | ||
For convenience, `dcl` provides shortcuts for singular advices: | ||
Additionally `dcl` provides a small library of predefined | ||
[base classes](http://www.dcljs.org/docs/bases/), | ||
[mixins](http://www.dcljs.org/docs/mixins/), | ||
and [useful advices](http://www.dcljs.org/docs/advices/). Check them out too. | ||
``` | ||
// pseudo code | ||
dcl.before(f) == dcl.advise({before: f}) | ||
dcl.around(f) == dcl.advise({around: f}) | ||
dcl.after (f) == dcl.advise({after: f}) | ||
``` | ||
For more examples, details, howtos, and why, please read [the docs](http://www.dcljs.org/docs/). | ||
### Chaining | ||
# How to install | ||
While constructors are chained by default you can chain any methods you like. | ||
Usually it works well for lifecycle methods, and event-like methods. | ||
With `npm`: | ||
```js | ||
// waker-upper and sleeper | ||
var BioOrganism = dcl(null, { | ||
// no methods for simplicity | ||
}); | ||
dcl.chainAfter(BioOrganism, "wakeUp"); | ||
dcl.chainBefore(BioOrganism, "sleep"); | ||
// now wakeUp() and sleep() are automatically chained | ||
// our mixins | ||
var SwitchOperator = dcl(null, { | ||
wakeUp: function(){ console.log("turn on lights"); }, | ||
sleep: function(){ console.log("turn off lights"); } | ||
}); | ||
var TeethBrusher = dcl(null, { | ||
wakeUp: function(){ console.log("brush my teeth"); }, | ||
sleep: function(){ console.log("brush my teeth again"); } | ||
}); | ||
var SmartDresser = dcl(null, { | ||
wakeUp: function(){ console.log("dress up for work"); }, | ||
sleep: function(){ console.log("switch to pajamas"); } | ||
}); | ||
// all together now | ||
var OfficeWorker = dcl([BioOrganism, SwitchOperator, TeethBrusher, SmartDresser], { | ||
// no methods for simplicity | ||
}); | ||
var ethel = OfficeWorker(); | ||
ethel.wakeUp(); | ||
// turn on lights | ||
// brush my teeth | ||
// dress up for work | ||
ethel.sleep(); | ||
// switch to pajamas | ||
// brush my teeth again | ||
// turn off lights | ||
``` | ||
npm install --save dcl | ||
``` | ||
### Advising objects | ||
With `yarn`: | ||
While class-level AOP is static, we can always advise any method dynamically, | ||
and unadvise it at will: | ||
```js | ||
// let's implement previous example with object-level AOP | ||
// for that we need to use a new module: | ||
var advise = require("dcl/advise"); | ||
// let's use one-off class | ||
var ethel = new (dcl(null, { | ||
wakeUp: function(){ /* nothing */ }, | ||
sleep: function(){ /* nothing */ } | ||
}))(); | ||
var wakeAd1 = advise(ethel, "wakeUp", { | ||
before: function(){ console.log("turn on lights"); } | ||
}); | ||
var wakeAd2 = advise(ethel, "wakeUp", { | ||
before: function(){ console.log("brush my teeth"); } | ||
}); | ||
var wakeAd3 = advise(ethel, "wakeUp", { | ||
before: function(){ console.log("dress up for work"); } | ||
}); | ||
// notice that after advices attached in the reverse order | ||
var sleepAd1 = advise(ethel, "sleep", { | ||
after: function(){ console.log("switch to pajamas"); } | ||
}); | ||
var sleepAd2 = advise(ethel, "sleep", { | ||
after: function(){ console.log("brush my teeth again"); } | ||
}); | ||
var sleepAd3 = advise(ethel, "sleep", { | ||
after: function(){ console.log("turn off lights"); } | ||
}); | ||
ethel.wakeUp(); | ||
// turn on lights | ||
// brush my teeth | ||
// dress up for work | ||
ethel.sleep(); | ||
// switch to pajamas | ||
// brush my teeth again | ||
// turn off lights | ||
// let's save on electricity | ||
wakeAd1.unadvise(); | ||
// brushing teeth more than once a day is overrated, right? | ||
sleepAd2.unadvise(); | ||
// no need to dress up for work either --- Ethel is CEO! | ||
wakeAd3.unadvise(); | ||
ethel.wakeUp(); | ||
// brush my teeth | ||
ethel.sleep(); | ||
// switch to pajamas | ||
// turn off lights | ||
``` | ||
yarn add dcl | ||
``` | ||
Again, for convenience, `dcl/advise` provides shortcuts for singular advices: | ||
With `bower`: | ||
``` | ||
// pseudo code | ||
advise.before(obj, methodName, f) == advise(obj, methodName, {before: f}) | ||
advise.around(obj, methodName, f) == advise(obj, methodName, {around: f}) | ||
advise.after (obj, methodName, f) == advise(obj, methodName, {after: f}) | ||
bower install --save dcl | ||
``` | ||
Naturally "around" advices use the same double function technique to be super | ||
light-weight. | ||
## How to use | ||
### Debugging helpers | ||
`dcl` can be installed with `npm`, `yarn`, or `bower` with files available from | ||
`node_modules/` or `bower_components/`. By default, it uses UMD, and ready | ||
to be used with Node's `require()`: | ||
There is a special module `dcl/debug` that adds better error checking and reporting | ||
for your "classes" and objects. All you need is to require it, and it will plug | ||
right in: | ||
```js | ||
var dclDebug = require("dcl/debug"); | ||
// if you run node.js, or CommonJS-compliant system | ||
var dcl = require('dcl'); | ||
var advise = require('dcl/advise'); | ||
``` | ||
In order to use it to its fullest, we should include a static class id in our | ||
"class" definitions like so: | ||
It can be used with AMD out of box: | ||
```js | ||
var OurClass = dcl(null, { | ||
declaredClass: "OurClass", | ||
// ... the rest of definitions | ||
// if you use dcl in a browser with AMD (like RequireJS): | ||
require(['dcl'], function (dcl) { | ||
// the same code that uses dcl | ||
}); | ||
// or when you define your own module: | ||
define(['dcl'], function (dcl) { | ||
// your dcl-using code goes here | ||
}); | ||
``` | ||
It is strongly suggested to specify `declaredClass` for every declaration in every | ||
real project. | ||
If you prefer to use globals in a browser, include files with `<script>` from `/dist/`: | ||
This `declaredClass` can be any unique string, but by convention it should be | ||
a human-readable name of your "class", which possibly indicate where this class can | ||
be found. For example, if you follow the convention "one class per file it can be | ||
something like `"myProject/aSubDir/aFileName"`. If you define several "classes" | ||
per file you can use a following schema: `"myProject/SubDirs/FileName/ClassName"`. | ||
Remember that this name is for you, it will be reported in error messages and logs. | ||
```html | ||
<script src='node_modules/dcl/dist/dcl.js'></script> | ||
``` | ||
Yes, logs. The debug module can log constructors and objects created by | ||
those constructors: | ||
Alternatively, you can use https://unpkg.com/ with AMD or globals. For example: | ||
```js | ||
var A = dcl(null, { | ||
declaredClass: "A", | ||
sleep: dcl.after(function(){ | ||
console.log("*zzzzzzzzzzzzz*"); | ||
}) | ||
}); | ||
```html | ||
<script src='https://unpkg.com/dcl@latest/dist/dcl.js'></script> | ||
``` | ||
var B = dcl(A, { | ||
declaredClass: "B", | ||
sleep: function(){ | ||
console.log("Time to hit the pillow!"); | ||
} | ||
}); | ||
# Documentation | ||
var fred = new B(); | ||
advise.after(fred, "sleep", function(){ | ||
console.log("*ZzZzZzZzZzZzZ*") | ||
}); | ||
fred.sleep(); | ||
// Time to hit the pillow! | ||
// *zzzzzzzzzzzzz* | ||
// *ZzZzZzZzZzZzZ* | ||
`dcl` is extensively documented in [the docs](http://www.dcljs.org/docs/). | ||
// now we can inspect all our objects: | ||
# Versions | ||
dclDebug.log(A); | ||
// *** class A depends on 0 classes | ||
// class method constructor is CHAINED AFTER (length: 0) | ||
// class method sleep is UNCHAINED BUT CONTAINS ADVICE(S), | ||
// and has an AOP stub (before: 0, around: 0, after: 1) | ||
## 2.x | ||
dclDebug.log(B); | ||
// *** class B depends on 1 classes | ||
// dependencies: A | ||
// class method constructor is CHAINED AFTER (length: 0) | ||
// class method sleep is UNCHAINED BUT CONTAINS ADVICE(S), | ||
// and has an AOP stub (before: 0, around: 1, after: 1) | ||
- 2.0.0 — *The initial release of 2.x* | ||
dclDebug.log(fred); | ||
// *** object of class B | ||
// *** class B depends on 1 classes | ||
// dependencies: A | ||
// class method constructor is CHAINED AFTER (length: 0) | ||
// class method sleep is UNCHAINED BUT CONTAINS ADVICE(S), | ||
// and has an AOP stub (before: 0, around: 1, after: 1) | ||
// object method sleep has an AOP stub (before: 0, around: 1, after: 2) | ||
``` | ||
## 1.x | ||
This way we can always know that we generated correct classes, inspect static | ||
chaining and advices, and even can monitor dynamically attached/removed advices. | ||
- 1.1.3 — *1.x version before forking for 2.x* | ||
## Summary | ||
# License | ||
Obviously this is a simple readme that was supposed to give an overview of `dcl`. | ||
For more details, please read [the docs](http://www.dcljs.org/docs/). | ||
BSD or AFL — your choice. | ||
Additionally `dcl` provides a small library of predefined | ||
[base classes](http://www.dcljs.org/docs/bases/), | ||
[mixins](http://www.dcljs.org/docs/mixins/), | ||
and [useful advices](http://www.dcljs.org/docs/advices/). Check them out too. | ||
Happy hacking! | ||
[npm-image]: https://img.shields.io/npm/v/dcl.svg | ||
@@ -467,4 +262,4 @@ [npm-url]: https://npmjs.org/package/dcl | ||
[dev-deps-image]: https://img.shields.io/david/dev/uhop/dcl.svg | ||
[dev-deps-url]: https://david-dm.org/uhop/dcl#info=devDependencies | ||
[dev-deps-url]: https://david-dm.org/uhop/dcl?type=dev | ||
[travis-image]: https://img.shields.io/travis/uhop/dcl.svg | ||
[travis-url]: https://travis-ci.org/uhop/dcl |
/* 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)}))}) | ||
(["module", "heya-unit", "../dcl", "../advise", "../advices/counter", "../advices/flow", | ||
"../advices/time", "../advices/memoize", "../advices/trace"], | ||
function(module, unit, dcl, advise, counter, flow, time, memoize, trace){ | ||
(['module', 'heya-unit', '../dcl', '../advise', '../advices/counter', '../advices/flow', | ||
'../advices/time', '../advices/memoize', '../advices/trace'], | ||
function (module, unit, dcl, advise, counter, flow, time, memoize, trace) { | ||
'use strict'; | ||
"use strict"; | ||
var Ackermann = dcl(null, { | ||
declaredName: "Ackermann", | ||
m0: function(n){ | ||
declaredName: 'Ackermann', | ||
m0: function (n) { | ||
return n + 1; | ||
}, | ||
n0: function(m){ | ||
n0: function (m) { | ||
return this.a(m - 1, 1); | ||
}, | ||
a: function(m, n){ | ||
if(m == 0){ | ||
a: function (m, n) { | ||
if (m == 0) { | ||
return this.m0(n); | ||
} | ||
if(n == 0){ | ||
if (n == 0) { | ||
return this.n0(m); | ||
@@ -31,14 +30,12 @@ } | ||
function test_counter(t){ | ||
"use strict"; | ||
var x = new Ackermann(); | ||
var counterM0 = counter(); | ||
advise(x, "m0", counterM0.advice()); | ||
advise(x, 'm0', counterM0.advice()); | ||
var counterN0 = counter(); | ||
advise(x, "n0", counterN0.advice()); | ||
advise(x, 'n0', counterN0.advice()); | ||
var counterA = counter(); | ||
advise(x, "a", counterA.advice()); | ||
advise(x, 'a', counterA.advice()); | ||
@@ -56,10 +53,8 @@ x.a(3, 2); | ||
test: function test_flow(t){ | ||
"use strict"; | ||
// our advised version: | ||
var AdvisedAckermann = dcl(Ackermann, { | ||
declaredName: "AdvisedAckermann", | ||
m0: dcl.advise(flow.advice("m0")), | ||
n0: dcl.advise(flow.advice("n0")), | ||
a: dcl.advise(flow.advice("a")) | ||
declaredName: 'AdvisedAckermann', | ||
m0: dcl.advise(flow.advice('m0')), | ||
n0: dcl.advise(flow.advice('n0')), | ||
a: dcl.advise(flow.advice('a')) | ||
}); | ||
@@ -69,10 +64,10 @@ | ||
var InstrumentedAckermann = dcl(AdvisedAckermann, { | ||
declaredName: "InstrumentedAckermann", | ||
m0: dcl.around(function(sup){ | ||
return function(n){ | ||
t.info("a() called: " + (flow.inFlowOf("a") || 0)); | ||
t.info("n0() called: " + (flow.inFlowOf("n0") || 0)); | ||
declaredName: 'InstrumentedAckermann', | ||
m0: dcl.around(function (sup) { | ||
return function (n) { | ||
t.info('a() called: ' + (flow.inFlowOf('a') || 0)); | ||
t.info('n0() called: ' + (flow.inFlowOf('n0') || 0)); | ||
var stack = flow.getStack(); | ||
var previous = stack[stack.length - 2] || "(none)"; | ||
t.info("m0() called from: " + previous); | ||
var previous = stack[stack.length - 2] || '(none)'; | ||
t.info('m0() called from: ' + previous); | ||
return sup.call(this, n); | ||
@@ -87,13 +82,11 @@ } | ||
logs: [ | ||
{text: "a() called: 3"}, | ||
{text: "n0() called: 1"}, | ||
{text: "m0() called from: a"}, | ||
{text: "a() called: 2"}, | ||
{text: "n0() called: 0"}, | ||
{text: "m0() called from: a"} | ||
{text: 'a() called: 3'}, | ||
{text: 'n0() called: 1'}, | ||
{text: 'm0() called from: a'}, | ||
{text: 'a() called: 2'}, | ||
{text: 'n0() called: 0'}, | ||
{text: 'm0() called from: a'} | ||
] | ||
}, | ||
function test_memoize(t){ | ||
"use strict"; | ||
// TODO: redirect console to ice | ||
@@ -104,3 +97,3 @@ | ||
advise(x, "a", time("x.a")); | ||
advise(x, 'a', time('x.a')); | ||
@@ -112,9 +105,9 @@ x.a(3, 3); | ||
advise(y, "m0", memoize.advice("m0")); | ||
advise(y, "n0", memoize.advice("n0")); | ||
advise(y, "a", memoize.advice("a", function(self, args){ | ||
return args[0] + "-" + args[1]; | ||
advise(y, 'm0', memoize.advice('m0')); | ||
advise(y, 'n0', memoize.advice('n0')); | ||
advise(y, 'a', memoize.advice('a', function (self, args) { | ||
return args[0] + '-' + args[1]; | ||
})); | ||
advise(y, "a", time("y.a")); | ||
advise(y, 'a', time('y.a')); | ||
@@ -126,4 +119,2 @@ y.a(3, 3); | ||
function test_trace(t){ | ||
"use strict"; | ||
// TODO: redirect console to ice | ||
@@ -134,5 +125,5 @@ | ||
advise(x, "m0", trace("m0", true)); | ||
advise(x, "n0", trace("n0", true)); | ||
advise(x, "a", trace("a", true)); | ||
advise(x, 'm0', trace('m0', true)); | ||
advise(x, 'n0', trace('n0', true)); | ||
advise(x, 'a', trace('a', true)); | ||
@@ -139,0 +130,0 @@ x.a(1, 1); |
/* 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)}))}) | ||
(["module", "heya-unit", "../dcl", "../advise"], function(module, unit, dcl, advise){ | ||
(['module', 'heya-unit', '../dcl', '../advise'], function (module, unit, dcl, advise) { | ||
'use strict'; | ||
"use strict"; | ||
// tests | ||
unit.add(module, [ | ||
function test_dclAdvise_with_advise(t){ | ||
"use strict"; | ||
function test_dclAdvise_with_advise (t) { | ||
'use strict'; | ||
var A = dcl(null, { | ||
m1: dcl.advise({ | ||
before: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "b"; | ||
before: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'b'; | ||
}, | ||
after: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "a"; | ||
after: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'a'; | ||
} | ||
@@ -25,4 +24,4 @@ }) | ||
var B = dcl(A, { | ||
m1: function(x){ | ||
if(!this.a){ this.a = ""; } | ||
m1: function (x) { | ||
if (!this.a) { this.a = ''; } | ||
this.a += x; | ||
@@ -33,63 +32,63 @@ } | ||
var x = new B; | ||
x.m1("-"); | ||
x.m1('-'); | ||
eval(t.TEST('x.a === "b-a"')); | ||
var h1 = advise(x, "m1", { | ||
after: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "A1"; | ||
var h1 = advise(x, 'm1', { | ||
after: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'A1'; | ||
} | ||
}); | ||
x.a = ""; | ||
x.m1("-"); | ||
x.a = ''; | ||
x.m1('-'); | ||
eval(t.TEST('x.a === "b-aA1"')); | ||
var h2 = advise(x, "m1", { | ||
before: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "B1"; | ||
var h2 = advise(x, 'm1', { | ||
before: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'B1'; | ||
} | ||
}); | ||
x.a = ""; | ||
x.m1("-"); | ||
x.a = ''; | ||
x.m1('-'); | ||
eval(t.TEST('x.a === "B1b-aA1"')); | ||
var h3 = advise(x, "m1", { | ||
around: function(sup){ | ||
return function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "F1"; | ||
if(sup){ sup.apply(this, arguments); } | ||
this.a += "F2"; | ||
var h3 = advise(x, 'm1', { | ||
around: function (sup) { | ||
return function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'F1'; | ||
if (sup) { sup.apply(this, arguments); } | ||
this.a += 'F2'; | ||
}; | ||
} | ||
}); | ||
x.a = ""; | ||
x.m1("-"); | ||
x.a = ''; | ||
x.m1('-'); | ||
eval(t.TEST('x.a === "B1bF1-F2aA1"')); | ||
h1.unadvise(); | ||
x.a = ""; | ||
x.m1("-"); | ||
x.a = ''; | ||
x.m1('-'); | ||
eval(t.TEST('x.a === "B1bF1-F2a"')); | ||
h2.unadvise(); | ||
x.a = ""; | ||
x.m1("-"); | ||
x.a = ''; | ||
x.m1('-'); | ||
eval(t.TEST('x.a === "bF1-F2a"')); | ||
h3.unadvise(); | ||
x.a = ""; | ||
x.m1("-"); | ||
x.a = ''; | ||
x.m1('-'); | ||
eval(t.TEST('x.a === "b-a"')); | ||
}, | ||
function test_advise(t){ | ||
"use strict"; | ||
function test_advise (t) { | ||
'use strict'; | ||
var x = new (dcl(null, { | ||
constructor: function(){ | ||
this.a = ""; | ||
constructor: function () { | ||
this.a = ''; | ||
}, | ||
m1: function(){ | ||
this.a += "*"; | ||
m1: function () { | ||
this.a += '*'; | ||
} | ||
@@ -101,8 +100,8 @@ })); | ||
var h1 = advise(x, "m1", { | ||
around: function(sup){ | ||
return function(){ | ||
this.a += "b1"; | ||
var h1 = advise(x, 'm1', { | ||
around: function (sup) { | ||
return function () { | ||
this.a += 'b1'; | ||
sup.call(this); | ||
this.a += "a1"; | ||
this.a += 'a1'; | ||
}; | ||
@@ -112,12 +111,12 @@ } | ||
x.a = ""; | ||
x.a = ''; | ||
x.m1(); | ||
eval(t.TEST('x.a === "b1*a1"')); | ||
var h2 = advise(x, "m1", { | ||
around: function(sup){ | ||
return function(){ | ||
this.a += "b2"; | ||
var h2 = advise(x, 'm1', { | ||
around: function (sup) { | ||
return function () { | ||
this.a += 'b2'; | ||
sup.call(this); | ||
this.a += "a2"; | ||
this.a += 'a2'; | ||
}; | ||
@@ -127,12 +126,12 @@ } | ||
x.a = ""; | ||
x.a = ''; | ||
x.m1(); | ||
eval(t.TEST('x.a === "b2b1*a1a2"')); | ||
var h3 = advise(x, "m1", { | ||
around: function(sup){ | ||
return function(){ | ||
this.a += "b3"; | ||
var h3 = advise(x, 'm1', { | ||
around: function (sup) { | ||
return function () { | ||
this.a += 'b3'; | ||
sup.call(this); | ||
this.a += "a3"; | ||
this.a += 'a3'; | ||
}; | ||
@@ -142,12 +141,12 @@ } | ||
x.a = ""; | ||
x.a = ''; | ||
x.m1(); | ||
eval(t.TEST('x.a === "b3b2b1*a1a2a3"')); | ||
var h4 = advise(x, "m1", { | ||
around: function(sup){ | ||
return function(){ | ||
this.a += "b4"; | ||
var h4 = advise(x, 'm1', { | ||
around: function (sup) { | ||
return function () { | ||
this.a += 'b4'; | ||
sup.call(this); | ||
this.a += "a4"; | ||
this.a += 'a4'; | ||
}; | ||
@@ -157,3 +156,3 @@ } | ||
x.a = ""; | ||
x.a = ''; | ||
x.m1(); | ||
@@ -163,3 +162,3 @@ eval(t.TEST('x.a === "b4b3b2b1*a1a2a3a4"')); | ||
h2.unadvise(); | ||
x.a = ""; | ||
x.a = ''; | ||
x.m1(); | ||
@@ -169,3 +168,3 @@ eval(t.TEST('x.a === "b4b3b1*a1a3a4"')); | ||
h1.unadvise(); | ||
x.a = ""; | ||
x.a = ''; | ||
x.m1(); | ||
@@ -175,3 +174,3 @@ eval(t.TEST('x.a === "b4b3*a3a4"')); | ||
h3.unadvise(); | ||
x.a = ""; | ||
x.a = ''; | ||
x.m1(); | ||
@@ -181,3 +180,3 @@ eval(t.TEST('x.a === "b4*a4"')); | ||
h4.unadvise(); | ||
x.a = ""; | ||
x.a = ''; | ||
x.m1(); | ||
@@ -184,0 +183,0 @@ eval(t.TEST('x.a === "*"')); |
@@ -1,19 +0,16 @@ | ||
/* 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)}))}) | ||
(["module", "heya-unit", "../dcl", "../bases/Mixer", "../bases/Replacer"], | ||
function(module, unit, dcl, Mixer, Replacer){ | ||
/* 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)}))}) | ||
(['module', 'heya-unit', '../dcl', '../bases/Mixer', '../bases/Replacer'], | ||
function (module, unit, dcl, Mixer, Replacer) { | ||
'use strict'; | ||
"use strict"; | ||
// tests | ||
unit.add(module, [ | ||
function test_Mixer(t){ | ||
"use strict"; | ||
function test_Mixer (t) { | ||
var f = function () {}; | ||
var f = function(){} | ||
var A = dcl(Mixer, { | ||
declaredClass: "A", | ||
declaredClass: 'A', | ||
a: 1, | ||
b: "two", | ||
b: 'two', | ||
c: null, | ||
@@ -35,11 +32,9 @@ d: f | ||
}, | ||
function test_Replacer(t){ | ||
"use strict"; | ||
function test_Replacer (t) { | ||
var f = function () {}; | ||
var f = function(){} | ||
var A = dcl(Replacer, { | ||
declaredClass: "A", | ||
declaredClass: 'A', | ||
a: 1, | ||
b: "two", | ||
b: 'two', | ||
c: null, | ||
@@ -46,0 +41,0 @@ d: f |
/* 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)}))}) | ||
(["module", "heya-unit", "../dcl"], function(module, unit, dcl){ | ||
(['module', 'heya-unit', '../dcl'], function (module, unit, dcl) { | ||
'use strict'; | ||
"use strict"; | ||
// tests | ||
unit.add(module, [ | ||
function test_chaining(t){ | ||
"use strict"; | ||
function test_chaining (t) { | ||
var A = dcl(null, {}); | ||
dcl.chainBefore(A, "m1"); | ||
dcl.chainAfter(A, "m2"); | ||
dcl.chainBefore(A, 'm1'); | ||
dcl.chainAfter (A, 'm2'); | ||
var B = dcl(null, { | ||
m1: function(){ | ||
if(!this.b){ this.b = ""; } | ||
this.b += "B"; | ||
m1: function () { | ||
if (!this.b) { this.b = ''; } | ||
this.b += 'B'; | ||
}, | ||
m2: function(){ | ||
if(!this.c){ this.c = ""; } | ||
this.c += "B"; | ||
m2: function () { | ||
if (!this.c) { this.c = ''; } | ||
this.c += 'B'; | ||
} | ||
@@ -28,9 +25,9 @@ }); | ||
var C = dcl(null, { | ||
m1: function(){ | ||
if(!this.b){ this.b = ""; } | ||
this.b += "C"; | ||
m1: function () { | ||
if (!this.b) { this.b = ''; } | ||
this.b += 'C'; | ||
}, | ||
m2: function(){ | ||
if(!this.c){ this.c = ""; } | ||
this.c += "C"; | ||
m2: function () { | ||
if (!this.c) { this.c = ''; } | ||
this.c += 'C'; | ||
} | ||
@@ -40,9 +37,9 @@ }); | ||
var D = dcl(null, { | ||
m1: function(){ | ||
if(!this.b){ this.b = ""; } | ||
this.b += "D"; | ||
m1: function () { | ||
if (!this.b) { this.b = ''; } | ||
this.b += 'D'; | ||
}, | ||
m2: function(){ | ||
if(!this.c){ this.c = ""; } | ||
this.c += "D"; | ||
m2: function () { | ||
if (!this.c) { this.c = ''; } | ||
this.c += 'D'; | ||
} | ||
@@ -59,29 +56,29 @@ }); | ||
}, | ||
function test_chain_with_super(t){ | ||
"use strict"; | ||
function test_chain_with_super (t) { | ||
var A = dcl(null, { | ||
constructor: function(){ | ||
declaredClass: 'A', | ||
constructor: function () { | ||
this.reset(); | ||
this.flag = true; | ||
}, | ||
reset: function(){ | ||
this.b = this.c = ""; | ||
reset: function () { | ||
this.b = this.c = ''; | ||
}, | ||
m1: function(){ | ||
this.b += "A"; | ||
m1: function () { | ||
this.b += 'A'; | ||
}, | ||
m2: function(){ | ||
this.c += "A"; | ||
m2: function () { | ||
this.c += 'A'; | ||
} | ||
}); | ||
dcl.chainBefore(A, "m1"); | ||
dcl.chainAfter(A, "m2"); | ||
dcl.chainBefore(A, 'm1'); | ||
dcl.chainAfter (A, 'm2'); | ||
var B = dcl(null, { | ||
m1: function(){ | ||
this.b += "B"; | ||
declaredClass: 'B', | ||
m1: function () { | ||
this.b += 'B'; | ||
}, | ||
m2: function(){ | ||
this.c += "B"; | ||
m2: function () { | ||
this.c += 'B'; | ||
} | ||
@@ -91,14 +88,15 @@ }); | ||
var C = dcl(null, { | ||
m1: dcl.superCall(function(sup){ | ||
return function(){ | ||
this.b += "Cb"; | ||
if(this.flag && sup){ sup.call(this); } | ||
this.b += "Ca"; | ||
declaredClass: 'C', | ||
m1: dcl.superCall(function (sup) { | ||
return function () { | ||
this.b += 'Cb'; | ||
if (this.flag && sup) { sup.call(this); } | ||
this.b += 'Ca'; | ||
}; | ||
}), | ||
m2: dcl.superCall(function(sup){ | ||
return function(){ | ||
this.c += "Cb"; | ||
if(this.flag && sup){ sup.call(this); } | ||
this.c += "Ca"; | ||
m2: dcl.superCall(function (sup) { | ||
return function () { | ||
this.c += 'Cb'; | ||
if (this.flag && sup) { sup.call(this); } | ||
this.c += 'Ca'; | ||
}; | ||
@@ -109,7 +107,8 @@ }) | ||
var D = dcl(null, { | ||
m1: function(){ | ||
this.b += "D"; | ||
declaredClass: 'D', | ||
m1: function () { | ||
this.b += 'D'; | ||
}, | ||
m2: function(){ | ||
this.c += "D"; | ||
m2: function () { | ||
this.c += 'D'; | ||
} | ||
@@ -119,7 +118,8 @@ }); | ||
var E = dcl(null, { | ||
m1: function(){ | ||
this.b += "E"; | ||
declaredClass: 'E', | ||
m1: function () { | ||
this.b += 'E'; | ||
}, | ||
m2: function(){ | ||
this.c += "E"; | ||
m2: function () { | ||
this.c += 'E'; | ||
} | ||
@@ -143,5 +143,3 @@ }); | ||
}, | ||
function test_isInstanceOf(t){ | ||
"use strict"; | ||
function test_isInstanceOf (t) { | ||
var A = dcl(null, {}); | ||
@@ -167,17 +165,17 @@ var B = dcl(null, {}); | ||
}, | ||
function test_postscript(t){ | ||
function test_postscript (t) { | ||
var A = dcl(null, { | ||
constructor: dcl.advise({ | ||
around: function(sup){ | ||
return function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "A"; | ||
around: function (sup) { | ||
return function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'A'; | ||
}; | ||
}, | ||
after: function(){ | ||
after: function () { | ||
this.postscript(); | ||
} | ||
}), | ||
postscript: function(){ | ||
this.b = "A"; | ||
postscript: function () { | ||
this.b = 'A'; | ||
} | ||
@@ -187,8 +185,8 @@ }); | ||
var B = dcl(null, { | ||
constructor: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "B"; | ||
constructor: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'B'; | ||
}, | ||
postscript: function(){ | ||
this.b = "B"; | ||
postscript: function () { | ||
this.b = 'B'; | ||
} | ||
@@ -198,8 +196,8 @@ }); | ||
var C = dcl(null, { | ||
constructor: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "C"; | ||
constructor: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'C'; | ||
}, | ||
postscript: function(){ | ||
this.b = "C"; | ||
postscript: function () { | ||
this.b = 'C'; | ||
} | ||
@@ -220,20 +218,18 @@ }); | ||
}, | ||
function test_postscript2(t){ | ||
"use strict"; | ||
function test_postscript2 (t) { | ||
var A = dcl(null, { | ||
constructor: dcl.advise({ | ||
around: function(sup){ | ||
return function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "A"; | ||
around: function (sup) { | ||
return function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'A'; | ||
}; | ||
}, | ||
after: function(){ | ||
after: function () { | ||
this.postscript(); | ||
} | ||
}), | ||
postscript: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "P"; | ||
postscript: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'P'; | ||
} | ||
@@ -243,5 +239,5 @@ }); | ||
var B = dcl(null, { | ||
constructor: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "B"; | ||
constructor: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'B'; | ||
} | ||
@@ -251,5 +247,5 @@ }); | ||
var C = dcl(null, { | ||
constructor: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "C"; | ||
constructor: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'C'; | ||
} | ||
@@ -273,10 +269,8 @@ }); | ||
}, | ||
function test_advise(t){ | ||
"use strict"; | ||
function test_advise (t) { | ||
var A = dcl(null, { | ||
m1: dcl.advise({ | ||
after: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Aa"; | ||
after: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Aa'; | ||
} | ||
@@ -287,5 +281,5 @@ }) | ||
m1: dcl.advise({ | ||
before: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Bb"; | ||
before: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Bb'; | ||
} | ||
@@ -295,10 +289,10 @@ }) | ||
var C = dcl(null, { | ||
m1: dcl.superCall(function(sup){ | ||
return function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Cfb"; | ||
if(sup){ | ||
m1: dcl.superCall(function (sup) { | ||
return function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Cfb'; | ||
if (sup) { | ||
sup.apply(this, arguments); | ||
} | ||
this.a += "Cfa"; | ||
this.a += 'Cfa'; | ||
}; | ||
@@ -309,19 +303,19 @@ }) | ||
m1: dcl.advise({ | ||
before: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Db"; | ||
before: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Db'; | ||
}, | ||
around: function(sup){ | ||
return function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Dfb"; | ||
if(sup){ | ||
around: function (sup) { | ||
return function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Dfb'; | ||
if (sup) { | ||
sup.apply(this, arguments); | ||
} | ||
this.a += "Dfa"; | ||
this.a += 'Dfa'; | ||
}; | ||
}, | ||
after: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Da"; | ||
after: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Da'; | ||
} | ||
@@ -331,5 +325,5 @@ }) | ||
var E = dcl(null, { | ||
m1: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "E"; | ||
m1: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'E'; | ||
} | ||
@@ -346,14 +340,12 @@ }); | ||
}, | ||
function test_advise2(t){ | ||
"use strict"; | ||
function test_advise2 (t) { | ||
var A = dcl(null, { | ||
m1: dcl.advise({ | ||
before: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Ab"; | ||
before: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Ab'; | ||
}, | ||
after: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Aa"; | ||
after: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Aa'; | ||
} | ||
@@ -364,9 +356,9 @@ }) | ||
m1: dcl.advise({ | ||
before: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Bb"; | ||
before: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Bb'; | ||
}, | ||
after: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "Ba"; | ||
after: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'Ba'; | ||
} | ||
@@ -373,0 +365,0 @@ }) |
/* 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)}))}) | ||
(["module", "heya-unit", "../dcl", "../debug"], function(module, unit, dcl, dclDebug){ | ||
(['module', 'heya-unit', '../dcl', '../debug'], function(module, unit, dcl){ | ||
"use strict"; | ||
'use strict'; | ||
@@ -9,93 +9,98 @@ // tests | ||
unit.add(module, [ | ||
function test_imposible_cycle(t){ | ||
"use strict"; | ||
function test_imposible_cycle (t) { | ||
'use strict'; | ||
var A = dcl(null, { | ||
declaredClass: "A" | ||
declaredClass: 'A' | ||
}); | ||
var B = dcl(null, { | ||
declaredClass: "B" | ||
declaredClass: 'B' | ||
}); | ||
var AB = dcl([A, B], { | ||
declaredClass: "AB" | ||
declaredClass: 'AB' | ||
}); | ||
var BA = dcl([B, A], { | ||
declaredClass: "BA" | ||
declaredClass: 'BA' | ||
}); | ||
try{ | ||
try { | ||
var Impossible = dcl([AB, BA], { | ||
declaredClass: "Impossible" | ||
declaredClass: 'Impossible' | ||
}); | ||
// we should never be there | ||
t.assert(false, "cycle error should be triggered"); | ||
}catch(e){ | ||
eval(t.TEST('e instanceof dclDebug.DclError')); | ||
eval(t.TEST('e instanceof dclDebug.CycleError')); | ||
t.assert(false, 'cycle error should be triggered'); | ||
} catch (e) { | ||
eval(t.TEST('e instanceof dcl.DclError')); | ||
eval(t.TEST('e instanceof dcl.CycleError')); | ||
} | ||
}, | ||
function test_chaining_conflict(t){ | ||
"use strict"; | ||
function test_chaining_conflict (t) { | ||
'use strict'; | ||
var A = dcl(null, { | ||
declaredClass: "A" | ||
declaredClass: 'A' | ||
}); | ||
dcl.chainAfter(A, "m"); | ||
dcl.chainAfter(A, 'm'); | ||
var B = dcl(null, { | ||
declaredClass: "B" | ||
declaredClass: 'B' | ||
}); | ||
dcl.chainBefore(B, "m"); | ||
dcl.chainBefore(B, 'm'); | ||
try{ | ||
try { | ||
var ChainConflict = dcl([A, B], { | ||
declaredClass: "ChainConflict" | ||
declaredClass: 'ChainConflict' | ||
}); | ||
// we should never be there | ||
t.assert(false, "chain error is triggered"); | ||
}catch(e){ | ||
eval(t.TEST('e instanceof dclDebug.DclError')); | ||
eval(t.TEST('e instanceof dclDebug.ChainingError')); | ||
t.assert(false, 'chain error is triggered'); | ||
} catch (e) { | ||
eval(t.TEST('e instanceof dcl.DclError')); | ||
eval(t.TEST('e instanceof dcl.ChainingError')); | ||
} | ||
}, | ||
function test_chaining_error(t){ | ||
"use strict"; | ||
function test_chaining_error (t) { | ||
'use strict'; | ||
var A = dcl(null, { | ||
declaredClass: "A" | ||
declaredClass: 'A' | ||
}); | ||
dcl.chainAfter(A, "m"); | ||
dcl.chainAfter(A, 'm'); | ||
try{ | ||
dcl.chainBefore(A, "m"); | ||
try { | ||
dcl.chainBefore(A, 'm'); | ||
// we should never be there | ||
t.assert(false, "set chaining error is triggered"); | ||
}catch(e){ | ||
eval(t.TEST('e instanceof dclDebug.DclError')); | ||
eval(t.TEST('e instanceof dclDebug.SetChainingError')); | ||
t.assert(false, 'set chaining error is triggered'); | ||
} catch (e) { | ||
eval(t.TEST('e instanceof dcl.DclError')); | ||
eval(t.TEST('e instanceof dcl.ChainingError')); | ||
} | ||
}, | ||
function test_superCall_argument_error(t){ | ||
"use strict"; | ||
try{ | ||
function test_superCall_argument_error (t) { | ||
'use strict'; | ||
try { | ||
var A = dcl(null, { | ||
declaredClass: "A", | ||
m: dcl.superCall("Should be a function, but it is a string.") | ||
declaredClass: 'A', | ||
m: dcl.superCall('Should be a function, but it is a string.') | ||
}); | ||
// we should never be there | ||
t.assert(false, "supercall error is triggered"); | ||
}catch(e){ | ||
eval(t.TEST('e instanceof dclDebug.DclError')); | ||
eval(t.TEST('e instanceof dclDebug.SuperCallError')); | ||
t.assert(false, 'supercall error is triggered'); | ||
} catch (e) { | ||
eval(t.TEST('e instanceof dcl.DclError')); | ||
eval(t.TEST('e instanceof dcl.SuperError')); | ||
} | ||
}, | ||
function test_superCall_super_error(t){ | ||
"use strict"; | ||
function test_superCall_super_error (t) { | ||
'use strict'; | ||
var A = dcl(null, { | ||
declaredClass: "A", | ||
declaredClass: 'A', | ||
m: 42 // not a function | ||
}); | ||
try{ | ||
try { | ||
var B = dcl(A, { | ||
declaredClass: "B", | ||
declaredClass: 'B', | ||
m: dcl.superCall(function(sup){ | ||
@@ -106,22 +111,23 @@ return sup ? sup.call(this) : 0; | ||
// we should never be there | ||
t.assert(false, "super error is triggered"); | ||
}catch(e){ | ||
eval(t.TEST('e instanceof dclDebug.DclError')); | ||
eval(t.TEST('e instanceof dclDebug.SuperError')); | ||
t.assert(false, 'super error is triggered'); | ||
} catch (e) { | ||
eval(t.TEST('e instanceof dcl.DclError')); | ||
eval(t.TEST('e instanceof dcl.SuperError')); | ||
} | ||
}, | ||
function test_superCall_wrapper(t){ | ||
"use strict"; | ||
try{ | ||
function test_superCall_wrapper (t) { | ||
'use strict'; | ||
try { | ||
var A = dcl(null, { | ||
declaredClass: "A", | ||
declaredClass: 'A', | ||
m: dcl.superCall(function(sup){ | ||
return "Instead of a function I return a string."; | ||
return 'Instead of a function I return a string.'; | ||
}) | ||
}); | ||
// we should never be there | ||
t.assert(false, "super result error is triggered"); | ||
}catch(e){ | ||
eval(t.TEST('e instanceof dclDebug.DclError')); | ||
eval(t.TEST('e instanceof dclDebug.SuperResultError')); | ||
t.assert(false, 'super result error is triggered'); | ||
} catch (e) { | ||
eval(t.TEST('e instanceof dcl.DclError')); | ||
eval(t.TEST('e instanceof dcl.SuperError')); | ||
} | ||
@@ -128,0 +134,0 @@ } |
/* 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)}))}) | ||
(["module", "heya-unit", "../mini"], function(module, unit, dcl){ | ||
(['module', 'heya-unit', '../dcl'], function (module, unit, dcl) { | ||
'use strict'; | ||
"use strict"; | ||
function getNames(ctor){ | ||
var b = ctor._meta.bases, r = []; | ||
for(var i = 0, l = b.length; i < l; ++i){ | ||
r.push(b[i].prototype.declaredClass); | ||
} | ||
return r.join(","); | ||
function getNames(ctr) { | ||
return ctr._meta.bases.map(function (base) { | ||
return base.prototype.declaredClass; | ||
}).join(','); | ||
} | ||
@@ -17,34 +14,32 @@ | ||
unit.add(module, [ | ||
function test_si(t){ | ||
"use strict"; | ||
var A = dcl(null, {declaredClass: "A"}); | ||
var B = dcl(A, {declaredClass: "B"}); | ||
var C = dcl(B, {declaredClass: "C"}); | ||
function test_si (t) { | ||
var A = dcl(null, {declaredClass: 'A'}); | ||
var B = dcl(A, {declaredClass: 'B'}); | ||
var C = dcl(B, {declaredClass: 'C'}); | ||
eval(t.TEST('getNames(A) === "A"')); | ||
eval(t.TEST('getNames(B) === "B,A"')); | ||
eval(t.TEST('getNames(C) === "C,B,A"')); | ||
eval(t.TEST('getNames(B) === "A,B"')); | ||
eval(t.TEST('getNames(C) === "A,B,C"')); | ||
}, | ||
function test_superCall(t){ | ||
"use strict"; | ||
function test_superCall (t) { | ||
var A = dcl(null, { | ||
constructor: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "A"; | ||
constructor: function () { | ||
if(!this.a){ this.a = ''; } | ||
this.a += 'A'; | ||
}, | ||
m1: function(){ | ||
this.b = "X"; | ||
m1: function () { | ||
this.b = 'X'; | ||
}, | ||
m2: dcl.superCall(function(sup){ | ||
return function(){ | ||
if(sup){ sup.call(this); } | ||
if(!this.c){ this.c = ""; } | ||
this.c += "1"; | ||
m2: dcl.superCall(function (sup) { | ||
return function () { | ||
if (sup) { sup.call(this); } | ||
if (!this.c) { this.c = ''; } | ||
this.c += '1'; | ||
}; | ||
}), | ||
m3: dcl.superCall(function(sup){ | ||
return function(){ | ||
if(!this.d){ this.d = ""; } | ||
this.d += "M"; | ||
if(sup){ sup.call(this); } | ||
m3: dcl.superCall(function (sup) { | ||
return function () { | ||
if (!this.d) { this.d = ''; } | ||
this.d += 'M'; | ||
if (sup) { sup.call(this); } | ||
}; | ||
@@ -58,2 +53,3 @@ }) | ||
a.m3(); | ||
eval(t.TEST('a.a === "A"')); | ||
@@ -65,21 +61,21 @@ eval(t.TEST('a.b === "X"')); | ||
var B = dcl(A, { | ||
constructor: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "B"; | ||
constructor: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'B'; | ||
}, | ||
m1: function(){ | ||
this.b = "Y"; | ||
m1: function () { | ||
this.b = 'Y'; | ||
}, | ||
m2: dcl.superCall(function(sup){ | ||
return function(){ | ||
if(sup){ sup.call(this); } | ||
if(!this.c){ this.c = ""; } | ||
this.c += "2"; | ||
m2: dcl.superCall(function (sup) { | ||
return function () { | ||
if (sup) { sup.call(this); } | ||
if (!this.c) { this.c = ''; } | ||
this.c += '2'; | ||
}; | ||
}), | ||
m3: dcl.superCall(function(sup){ | ||
return function(){ | ||
if(!this.d){ this.d = ""; } | ||
this.d += "N"; | ||
if(sup){ sup.call(this); } | ||
m3: dcl.superCall(function (sup) { | ||
return function () { | ||
if (!this.d) { this.d = ''; } | ||
this.d += 'N'; | ||
if (sup) { sup.call(this); } | ||
}; | ||
@@ -93,2 +89,3 @@ }) | ||
b.m3(); | ||
eval(t.TEST('b.a === "AB"')); | ||
@@ -100,21 +97,21 @@ eval(t.TEST('b.b === "Y"')); | ||
var C = dcl(B, { | ||
constructor: function(){ | ||
if(!this.a){ this.a = ""; } | ||
this.a += "C"; | ||
constructor: function () { | ||
if (!this.a) { this.a = ''; } | ||
this.a += 'C'; | ||
}, | ||
m1: function(){ | ||
this.b = "Z"; | ||
m1: function () { | ||
this.b = 'Z'; | ||
}, | ||
m2: dcl.superCall(function(sup){ | ||
return function(){ | ||
if(sup){ sup.call(this); } | ||
if(!this.c){ this.c = ""; } | ||
this.c += "3"; | ||
m2: dcl.superCall(function (sup) { | ||
return function () { | ||
if (sup) { sup.call(this); } | ||
if (!this.c) { this.c = ''; } | ||
this.c += '3'; | ||
}; | ||
}), | ||
m3: dcl.superCall(function(sup){ | ||
return function(){ | ||
if(!this.d){ this.d = ""; } | ||
this.d += "O"; | ||
if(sup){ sup.call(this); } | ||
m3: dcl.superCall(function (sup) { | ||
return function () { | ||
if (!this.d) { this.d = ''; } | ||
this.d += 'O'; | ||
if (sup) { sup.call(this); } | ||
}; | ||
@@ -128,2 +125,3 @@ }) | ||
c.m3(); | ||
eval(t.TEST('c.a === "ABC"')); | ||
@@ -134,55 +132,50 @@ eval(t.TEST('c.b === "Z"')); | ||
}, | ||
function test_diamonds(t){ | ||
"use strict"; | ||
function test_diamonds (t) { | ||
var A = dcl(null, {declaredClass: 'A'}); | ||
var B = dcl(null, {declaredClass: 'B'}); | ||
var C = dcl(null, {declaredClass: 'C'}); | ||
var D = dcl(null, {declaredClass: 'D'}); | ||
var A = dcl(null, {declaredClass: "A"}); | ||
var B = dcl(null, {declaredClass: "B"}); | ||
var C = dcl(null, {declaredClass: "C"}); | ||
var D = dcl(null, {declaredClass: "D"}); | ||
var ABC = dcl([A, B, C], {declaredClass: 'ABC'}); | ||
var ADC = dcl([A, D, C], {declaredClass: 'ADC'}); | ||
var ABC = dcl([A, B, C], {declaredClass: "ABC"}); | ||
var ADC = dcl([A, D, C], {declaredClass: "ADC"}); | ||
eval(t.TEST('getNames(ABC) === "A,B,C,ABC"')); | ||
eval(t.TEST('getNames(ADC) === "A,D,C,ADC"')); | ||
eval(t.TEST('getNames(ABC) === "ABC,C,B,A"')); | ||
eval(t.TEST('getNames(ADC) === "ADC,C,D,A"')); | ||
var ABCD1 = dcl([ABC, ADC], {declaredClass: 'ABCD1'}); | ||
var ABCD2 = dcl([ADC, ABC], {declaredClass: 'ABCD2'}); | ||
var ABCD1 = dcl([ABC, ADC], {declaredClass: "ABCD1"}); | ||
var ABCD2 = dcl([ADC, ABC], {declaredClass: "ABCD2"}); | ||
eval(t.TEST('getNames(ABCD1) === "ABCD1,ADC,ABC,C,D,B,A"')); | ||
eval(t.TEST('getNames(ABCD2) === "ABCD2,ABC,ADC,C,B,D,A"')); | ||
eval(t.TEST('getNames(ABCD1) === "A,B,D,C,ABC,ADC,ABCD1"')); | ||
eval(t.TEST('getNames(ABCD2) === "A,D,B,C,ADC,ABC,ABCD2"')); | ||
}, | ||
function test_triangles(t){ | ||
"use strict"; | ||
function test_triangles (t) { | ||
var A = dcl(null, {declaredClass: 'A'}); | ||
var B = dcl(null, {declaredClass: 'B'}); | ||
var C = dcl(null, {declaredClass: 'C'}); | ||
var A = dcl(null, {declaredClass: "A"}); | ||
var B = dcl(null, {declaredClass: "B"}); | ||
var C = dcl(null, {declaredClass: "C"}); | ||
var ABC = dcl([A, B, C], {declaredClass: 'ABC'}); | ||
var AC = dcl([A, C], {declaredClass: 'AC'}); | ||
var BC = dcl([B, C], {declaredClass: 'BC'}); | ||
var ABC = dcl([A, B, C], {declaredClass: "ABC"}); | ||
var AC = dcl([A, C], {declaredClass: "AC"}); | ||
var BC = dcl([B, C], {declaredClass: "BC"}); | ||
eval(t.TEST('getNames(ABC) === "A,B,C,ABC"')); | ||
eval(t.TEST('getNames(AC) === "A,C,AC"')); | ||
eval(t.TEST('getNames(BC) === "B,C,BC"')); | ||
eval(t.TEST('getNames(ABC) === "ABC,C,B,A"')); | ||
eval(t.TEST('getNames(AC) === "AC,C,A"')); | ||
eval(t.TEST('getNames(BC) === "BC,C,B"')); | ||
var ABC1 = dcl([ABC, AC], {declaredClass: 'ABC1'}); | ||
var ABC2 = dcl([AC, ABC], {declaredClass: 'ABC2'}); | ||
var ABC1 = dcl([ABC, AC], {declaredClass: "ABC1"}); | ||
var ABC2 = dcl([AC, ABC], {declaredClass: "ABC2"}); | ||
eval(t.TEST('getNames(ABC1) === "A,B,C,ABC,AC,ABC1"')); | ||
eval(t.TEST('getNames(ABC2) === "A,B,C,AC,ABC,ABC2"')); | ||
eval(t.TEST('getNames(ABC1) === "ABC1,AC,ABC,C,B,A"')); | ||
eval(t.TEST('getNames(ABC2) === "ABC2,ABC,AC,C,B,A"')); | ||
var ABC3 = dcl([ABC, BC], {declaredClass: 'ABC3'}); | ||
var ABC4 = dcl([BC, ABC], {declaredClass: 'ABC4'}); | ||
var ABC3 = dcl([ABC, BC], {declaredClass: "ABC3"}); | ||
var ABC4 = dcl([BC, ABC], {declaredClass: "ABC4"}); | ||
eval(t.TEST('getNames(ABC3) === "ABC3,BC,ABC,C,B,A"')); | ||
eval(t.TEST('getNames(ABC4) === "ABC4,ABC,BC,C,B,A"')); | ||
eval(t.TEST('getNames(ABC3) === "A,B,C,ABC,BC,ABC3"')); | ||
eval(t.TEST('getNames(ABC4) === "A,B,C,BC,ABC,ABC4"')); | ||
}, | ||
function test_superCall_int(t){ | ||
"use strict"; | ||
function test_superCall_int (t) { | ||
var a = new (dcl(null, { | ||
toString: dcl.superCall(function(sup){ | ||
return function(){ | ||
return "PRE-" + sup.call(this) + "-POST"; | ||
toString: dcl.superCall(function (sup) { | ||
return function () { | ||
return 'PRE-' + sup.call(this) + '-POST'; | ||
}; | ||
@@ -193,17 +186,15 @@ }) | ||
}, | ||
function test_impossible(t){ | ||
"use strict"; | ||
function test_impossible (t) { | ||
var A = dcl(null, {declaredClass: 'A'}); | ||
var B = dcl(null, {declaredClass: 'B'}); | ||
var A = dcl(null, {declaredClass: "A"}); | ||
var B = dcl(null, {declaredClass: "B"}); | ||
var AB = dcl([A, B], {declaredClass: 'AB'}); | ||
var BA = dcl([B, A], {declaredClass: 'BA'}); | ||
var AB = dcl([A, B], {declaredClass: "AB"}); | ||
var BA = dcl([B, A], {declaredClass: "BA"}); | ||
var failed = false; | ||
try{ | ||
var X = dcl([AB, BA], {declaredClass: "X"}); | ||
}catch(e){ | ||
try { | ||
var X = dcl([AB, BA], {declaredClass: 'X'}); | ||
} catch (e) { | ||
failed = true; | ||
}finally{ | ||
} finally { | ||
eval(t.TEST('failed')); | ||
@@ -210,0 +201,0 @@ } |
/* 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)}))}) | ||
(["module", "heya-unit", "../dcl", "../mixins/Cleanup"], function(module, unit, dcl, Cleanup){ | ||
(['module', 'heya-unit', '../dcl', '../mixins/Cleanup'], function (module, unit, dcl, Cleanup) { | ||
'use strict'; | ||
"use strict"; | ||
// tests | ||
unit.add(module, [ | ||
function test_Cleanup(t){ | ||
"use strict"; | ||
function test_Cleanup (t) { | ||
var msgs = []; | ||
var A = dcl(null, { | ||
constructor: function(n){ | ||
constructor: function (n) { | ||
this.n = n; | ||
msgs.push(this.n); | ||
}, | ||
destroy: function(){ | ||
destroy: function () { | ||
msgs.push(-this.n); | ||
@@ -24,3 +21,3 @@ } | ||
var cleanup = function(n){ | ||
var cleanup = function (n) { | ||
msgs.push(-n); | ||
@@ -30,3 +27,3 @@ }; | ||
var B = dcl(Cleanup, { | ||
constructor: function(){ | ||
constructor: function () { | ||
var f1 = this.pushCleanup(new A(1)); | ||
@@ -40,4 +37,4 @@ this.f2 = this.pushCleanup(2, cleanup); | ||
}, | ||
remove2: function(){ | ||
if(this.removeCleanup(this.f2)){ | ||
remove2: function () { | ||
if (this.removeCleanup(this.f2)) { | ||
this.f2(); | ||
@@ -47,3 +44,3 @@ this.f2 = null; | ||
}, | ||
destroy: function(){ | ||
destroy: function () { | ||
msgs.push(-99); | ||
@@ -50,0 +47,0 @@ } |
/* 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)}))}) | ||
(["module", "heya-unit", "../dcl", "../inherited"], function(module, unit, dcl){ | ||
(['module', 'heya-unit', '../dcl'], function (module, unit, dcl) { | ||
'use strict'; | ||
"use strict"; | ||
// tests | ||
@@ -10,8 +9,6 @@ | ||
{ | ||
test: function test_si(t){ | ||
"use strict"; | ||
function A(x){ t.info("A: " + x); } | ||
test: function test_si (t) { | ||
function A (x) { t.info('A: ' + x); } | ||
A.prototype = { | ||
m: function(x){ t.info("A.m: " + x); } | ||
m: function (x) { t.info('A.m: ' + x); } | ||
}; | ||
@@ -23,7 +20,7 @@ | ||
var B = dcl(A, { | ||
constructor: function(x){ | ||
t.info("B: " + x); | ||
constructor: function (x) { | ||
t.info('B: ' + x); | ||
}, | ||
m: function(x){ | ||
t.info("B.m: " + x); | ||
m: function (x) { | ||
t.info('B.m: ' + x); | ||
} | ||
@@ -36,16 +33,14 @@ }); | ||
logs: [ | ||
{text: "A: 1"}, | ||
{text: "A.m: 2"}, | ||
{text: "A: 3"}, | ||
{text: "B: 3"}, | ||
{text: "B.m: 4"} | ||
{text: 'A: 1'}, | ||
{text: 'A.m: 2'}, | ||
{text: 'A: 3'}, | ||
{text: 'B: 3'}, | ||
{text: 'B.m: 4'} | ||
] | ||
}, | ||
{ | ||
test: function test_superCall(t){ | ||
"use strict"; | ||
function A(x){ t.info("A: " + x); } | ||
test: function test_superCall (t) { | ||
function A (x) { t.info('A: ' + x); } | ||
A.prototype = { | ||
m: function(x){ t.info("A.m: " + x); } | ||
m: function (x) { t.info('A.m: ' + x); } | ||
}; | ||
@@ -57,12 +52,12 @@ | ||
var B = dcl(A, { | ||
constructor: function(x){ | ||
t.info("B: " + x); | ||
constructor: function (x) { | ||
t.info('B: ' + x); | ||
}, | ||
m: dcl.superCall(function(sup){ | ||
return function(x){ | ||
t.info("B.m before: " + x); | ||
m: dcl.superCall(function (sup) { | ||
return function (x) { | ||
t.info('B.m before: ' + x); | ||
sup.apply(this, arguments); | ||
t.info("B.m middle: " + x); | ||
t.info('B.m middle: ' + x); | ||
sup.call(this, x + 1); | ||
t.info("B.m after: " + x); | ||
t.info('B.m after: ' + x); | ||
}; | ||
@@ -76,25 +71,23 @@ }) | ||
logs: [ | ||
{text: "A: 1"}, | ||
{text: "A.m: 2"}, | ||
{text: "A: 3"}, | ||
{text: "B: 3"}, | ||
{text: "B.m before: 4"}, | ||
{text: "A.m: 4"}, | ||
{text: "B.m middle: 4"}, | ||
{text: "A.m: 5"}, | ||
{text: "B.m after: 4"} | ||
{text: 'A: 1'}, | ||
{text: 'A.m: 2'}, | ||
{text: 'A: 3'}, | ||
{text: 'B: 3'}, | ||
{text: 'B.m before: 4'}, | ||
{text: 'A.m: 4'}, | ||
{text: 'B.m middle: 4'}, | ||
{text: 'A.m: 5'}, | ||
{text: 'B.m after: 4'} | ||
] | ||
}, | ||
function test_superCall_int(t){ | ||
"use strict"; | ||
function A(x){} | ||
function A (x) {} | ||
A.prototype = { | ||
toString: function(x){ return "[object A]"; } | ||
toString: function (x) { return '[object A]'; } | ||
}; | ||
var b = new (dcl(A, { | ||
toString: dcl.superCall(function(sup){ | ||
return function(){ | ||
return "PRE-" + sup.call(this) + "-POST"; | ||
toString: dcl.superCall(function (sup) { | ||
return function () { | ||
return 'PRE-' + sup.call(this) + '-POST'; | ||
}; | ||
@@ -106,100 +99,43 @@ }) | ||
{ | ||
test: function test_inherited(t){ | ||
"use strict"; | ||
function A(x){ t.info("A: " + x); } | ||
A.prototype = { | ||
m: function(x){ t.info("A.m: " + x); } | ||
}; | ||
var a = new A(1); | ||
a.m(2); | ||
var B = dcl(A, { | ||
constructor: function(x){ | ||
t.info("B: " + x); | ||
}, | ||
m: function(x){ | ||
t.info("B.m before: " + x); | ||
this.inherited(this.constructor, "m", arguments); | ||
t.info("B.m middle: " + x); | ||
this.inherited(this.constructor, "m", [x + 1]); | ||
t.info("B.m after: " + x); | ||
} | ||
}); | ||
var b = new B(3); | ||
b.m(4); | ||
}, | ||
logs: [ | ||
{text: "A: 1"}, | ||
{text: "A.m: 2"}, | ||
{text: "A: 3"}, | ||
{text: "B: 3"}, | ||
{text: "B.m before: 4"}, | ||
{text: "A.m: 4"}, | ||
{text: "B.m middle: 4"}, | ||
{text: "A.m: 5"}, | ||
{text: "B.m after: 4"} | ||
] | ||
}, | ||
function test_inherited_int(t){ | ||
"use strict"; | ||
function A(x){} | ||
A.prototype = { | ||
toString: function(x){ return "[object A]"; } | ||
}; | ||
var b = new (dcl(A, { | ||
toString: function(){ | ||
return "PRE-" + this.inherited(this.constructor, "toString", []) + "-POST"; | ||
} | ||
})); | ||
eval(t.TEST('b.toString() === "PRE-[object A]-POST"')); | ||
}, | ||
{ | ||
test: function test_mi(t){ | ||
"use strict"; | ||
function A(x){ t.info("A: " + x); } | ||
function A (x) { t.info('A: ' + x); } | ||
A.prototype = { | ||
m1: function(x){ t.info("A.m1: " + x); }, | ||
m2: function(x){ t.info("A.m2: " + x); }, | ||
m3: function(x){ t.info("A.m3: " + x); } | ||
m1: function (x) { t.info('A.m1: ' + x); }, | ||
m2: function (x) { t.info('A.m2: ' + x); }, | ||
m3: function (x) { t.info('A.m3: ' + x); } | ||
}; | ||
function B(x){ t.info("B: " + x); } | ||
function B (x) { t.info('B: ' + x); } | ||
B.prototype = { | ||
m1: function(x){ t.info("B.m1: " + x); }, | ||
m2: function(x){ t.info("B.m2: " + x); }, | ||
m3: function(x){ t.info("B.m3: " + x); } | ||
m1: function (x) { t.info('B.m1: ' + x); }, | ||
m2: function (x) { t.info('B.m2: ' + x); }, | ||
m3: function (x) { t.info('B.m3: ' + x); } | ||
}; | ||
function C(x){ t.info("C: " + x); } | ||
function C (x) { t.info('C: ' + x); } | ||
C.prototype = { | ||
m1: function(x){ t.info("C.m1: " + x); }, | ||
m2: function(x){ t.info("C.m2: " + x); }, | ||
m3: function(x){ t.info("C.m3: " + x); } | ||
m1: function (x) { t.info('C.m1: ' + x); }, | ||
m2: function (x) { t.info('C.m2: ' + x); }, | ||
m3: function (x) { t.info('C.m3: ' + x); } | ||
}; | ||
var abc = new (dcl([A, B, C], { | ||
constructor: function(x){ | ||
t.info("abc: " + x); | ||
constructor: function (x) { | ||
t.info('abc: ' + x); | ||
}, | ||
m1: dcl.superCall(function(sup){ | ||
return function(x){ | ||
t.info("abc.m1: " + x); | ||
m1: dcl.superCall(function (sup) { | ||
return function (x) { | ||
t.info('abc.m1: ' + x); | ||
sup.call(this, x); | ||
}; | ||
}), | ||
m2: dcl.superCall(function(sup){ | ||
return function(x){ | ||
t.info("abc.m2: " + x); | ||
m2: dcl.superCall(function (sup) { | ||
return function (x) { | ||
t.info('abc.m2: ' + x); | ||
sup.call(this, x); | ||
}; | ||
}), | ||
m3: dcl.superCall(function(sup){ | ||
return function(x){ | ||
t.info("abc.m3: " + x); | ||
m3: dcl.superCall(function (sup) { | ||
return function (x) { | ||
t.info('abc.m3: ' + x); | ||
sup.call(this, x); | ||
@@ -214,17 +150,17 @@ }; | ||
var O = dcl(null, {}); | ||
dcl.chainBefore(O, "m1"); | ||
dcl.chainAfter(O, "m3"); | ||
dcl.chainBefore(O, 'm1'); | ||
dcl.chainAfter (O, 'm3'); | ||
var oabc = new (dcl([O, A, B, C], { | ||
constructor: function(x){ | ||
t.info("oabc: " + x); | ||
constructor: function (x) { | ||
t.info('oabc: ' + x); | ||
}, | ||
m1: function(x){ | ||
t.info("oabc.m1: " + x); | ||
m1: function (x) { | ||
t.info('oabc.m1: ' + x); | ||
}, | ||
m2: function(x){ | ||
t.info("oabc.m2: " + x); | ||
m2: function (x) { | ||
t.info('oabc.m2: ' + x); | ||
}, | ||
m3: function(x){ | ||
t.info("oabc.m3: " + x); | ||
m3: function (x) { | ||
t.info('oabc.m3: ' + x); | ||
} | ||
@@ -238,26 +174,26 @@ }))(0); | ||
// abc | ||
{text: "A: 0"}, | ||
{text: "B: 0"}, | ||
{text: "C: 0"}, | ||
{text: "abc: 0"}, | ||
{text: "abc.m1: 1"}, | ||
{text: "C.m1: 1"}, | ||
{text: "abc.m2: 2"}, | ||
{text: "C.m2: 2"}, | ||
{text: "abc.m3: 3"}, | ||
{text: "C.m3: 3"}, | ||
{text: 'A: 0'}, | ||
{text: 'B: 0'}, | ||
{text: 'C: 0'}, | ||
{text: 'abc: 0'}, | ||
{text: 'abc.m1: 1'}, | ||
{text: 'C.m1: 1'}, | ||
{text: 'abc.m2: 2'}, | ||
{text: 'C.m2: 2'}, | ||
{text: 'abc.m3: 3'}, | ||
{text: 'C.m3: 3'}, | ||
// oabc | ||
{text: "A: 0"}, | ||
{text: "B: 0"}, | ||
{text: "C: 0"}, | ||
{text: "oabc: 0"}, | ||
{text: "oabc.m1: 1"}, | ||
{text: "C.m1: 1"}, | ||
{text: "B.m1: 1"}, | ||
{text: "A.m1: 1"}, | ||
{text: "oabc.m2: 2"}, | ||
{text: "A.m3: 3"}, | ||
{text: "B.m3: 3"}, | ||
{text: "C.m3: 3"}, | ||
{text: "oabc.m3: 3"} | ||
{text: 'A: 0'}, | ||
{text: 'B: 0'}, | ||
{text: 'C: 0'}, | ||
{text: 'oabc: 0'}, | ||
{text: 'oabc.m1: 1'}, | ||
{text: 'C.m1: 1'}, | ||
{text: 'B.m1: 1'}, | ||
{text: 'A.m1: 1'}, | ||
{text: 'oabc.m2: 2'}, | ||
{text: 'A.m3: 3'}, | ||
{text: 'B.m3: 3'}, | ||
{text: 'C.m3: 3'}, | ||
{text: 'oabc.m3: 3'} | ||
] | ||
@@ -264,0 +200,0 @@ } |
/* 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)}))}) | ||
(["heya-unit", "./test_mini", "./test_dcl", "./test_advise", "./test_inherited", "./test_debug", | ||
"./test_raw", "./test_bases", "./test_mixins", "./test_advices"], | ||
function(unit){ | ||
"use strict"; | ||
([ | ||
'heya-unit', | ||
'./test_mini', | ||
'./test_dcl', | ||
'./test_advise', | ||
'./test_raw', | ||
'./test_bases', | ||
'./test_mixins', | ||
'./test_advices', | ||
'./test_accessors', | ||
'./test_advise_accessors', | ||
'./test_debug' | ||
], | ||
function (unit) { | ||
'use strict'; | ||
unit.run(); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
156764
55
4689
2
1
263
47
148