[ADD] method to extend classes in place (w/o reassignment)

semantics similar to ruby's Module.include

bzr revid: xmo@openerp.com-20110808094030-qfmi2s14vqz2nybz
This commit is contained in:
Xavier Morel 2011-08-08 11:40:30 +02:00
parent 0056818c76
commit 2f94a513bd
2 changed files with 112 additions and 5 deletions

View File

@ -56,6 +56,35 @@ openerp.base.core = function(openerp) {
}
return this;
}
Class.mix = function (properties) {
for (var name in properties) {
if (typeof properties[name] !== 'function'
|| !fnTest.test(properties[name])) {
prototype[name] = properties[name];
} else if (typeof prototype[name] === 'function'
&& prototype.hasOwnProperty(name)) {
prototype[name] = (function (name, fn, previous) {
return function () {
var tmp = this._super;
this._super = previous;
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
}
})(name, properties[name], prototype[name]);
} else if (typeof _super[name] === 'function') {
prototype[name] = (function (name, fn) {
return function () {
var tmp = this._super;
this._super = _super[name];
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
}
})(name, properties[name]);
}
}
};
// Populate our constructed prototype object
Class.prototype = prototype;

View File

@ -1,6 +1,6 @@
$(document).ready(function () {
var openerp;
module('Base Class', {
module('base-class', {
setup: function () {
openerp = window.openerp.init();
window.openerp.base.core(openerp);
@ -12,11 +12,11 @@ $(document).ready(function () {
return this.somevar;
}
});
var i1 = new C();
i1.somevar = 3;
var instance = new C();
instance.somevar = 3;
ok(i1 instanceof C);
strictEqual(i1.foo(), 3);
ok(instance instanceof C);
strictEqual(instance.foo(), 3);
});
test('Class initialization', function () {
var C1 = openerp.base.Class.extend({
@ -57,4 +57,82 @@ $(document).ready(function () {
strictEqual(new C1().foo(), 2);
strictEqual(new C2().foo(), 3);
});
test('In-place extension', function () {
var C0 = openerp.base.Class.extend({
foo: function () {
return 3;
},
qux: function () {
return 3;
},
bar: 3
});
C0.mix({
foo: function () {
return 5;
},
qux: function () {
return 2 + this._super();
},
bar: 5,
baz: 5
});
strictEqual(new C0().bar, 5);
strictEqual(new C0().baz, 5);
strictEqual(new C0().foo(), 5);
strictEqual(new C0().qux(), 5);
});
test('In-place extension and inheritance', function () {
var C0 = openerp.base.Class.extend({
foo: function () { return 1; },
bar: function () { return 1; }
});
var C1 = C0.extend({
foo: function () { return 1 + this._super(); }
});
strictEqual(new C1().foo(), 2);
strictEqual(new C1().bar(), 1);
C1.mix({
foo: function () { return 2 + this._super(); },
bar: function () { return 1 + this._super(); }
});
strictEqual(new C1().foo(), 4);
strictEqual(new C1().bar(), 2);
});
test('In-place extensions alter existing instances', function () {
var C0 = openerp.base.Class.extend({
foo: function () { return 1; },
bar: function () { return 1; }
});
var instance = new C0();
strictEqual(instance.foo(), 1);
strictEqual(instance.bar(), 1);
C0.mix({
foo: function () { return 2; },
bar: function () { return 2 + this._super(); }
});
strictEqual(instance.foo(), 2);
strictEqual(instance.bar(), 3);
});
test('In-place extension of subclassed types', function () {
var C0 = openerp.base.Class.extend({
foo: function () { return 1; },
bar: function () { return 1; }
});
var C1 = C0.extend({
foo: function () { return 1 + this._super(); },
bar: function () { return 1 + this._super(); }
});
var instance = new C1();
strictEqual(instance.foo(), 2);
C0.mix({
foo: function () { return 2; },
bar: function () { return 2 + this._super(); }
});
strictEqual(instance.foo(), 3);
strictEqual(instance.bar(), 4);
});
});