feat(putility): trait method override support

Support for trait method overrides will make it possible to use putility
traits with the decorator pattern while using a proxy class to avoid
redundant re-implementation of proxy methods.

Use of the pattern described above will occur in the implementation of
client-side filesystem caching.
This commit is contained in:
KernelDeimos 2024-10-10 15:47:58 -04:00 committed by Eric Dubé
parent c12ae2a923
commit 43c5402b7c
2 changed files with 75 additions and 1 deletions

View File

@ -1,5 +1,6 @@
module.exports = {
install_in_instance: (instance, { parameters }) => {
// old implementation
install_in_instance_: (instance, { parameters }) => {
const impls = instance._get_merged_static_object('IMPLEMENTS');
instance._.impls = {};
@ -17,4 +18,28 @@ module.exports = {
instance.as = trait_name => instance._.impls[trait_name];
instance.list_traits = () => Object.keys(instance._.impls);
},
// new implementation
install_in_instance: (instance, { parameters }) => {
const chain = instance._get_inheritance_chain();
instance._.impls = {};
instance.as = trait_name => instance._.impls[trait_name];
instance.list_traits = () => Object.keys(instance._.impls);
for ( const cls of chain ) {
const cls_traits = cls.IMPLEMENTS;
if ( ! cls_traits ) continue;
for ( const trait_name in cls_traits ) {
const impl = instance._.impls[trait_name] ??
(instance._.impls[trait_name] = {});
const cls_impl = cls_traits[trait_name];
for ( const method_name in cls_impl ) {
const fn = cls_impl[method_name];
impl[method_name] = fn.bind(instance);
}
}
}
}
};

View File

@ -0,0 +1,49 @@
const { expect } = require('chai');
const { AdvancedBase } = require("../src/AdvancedBase");
class TestClass extends AdvancedBase {
static IMPLEMENTS = {
test_trait: {
test_method: () => 'A'
},
override_trait: {
preserved_method: () => 'B',
override_method: () => 'C',
},
}
}
class TestSubClass extends TestClass {
static IMPLEMENTS = {
override_trait: {
override_method: () => 'D',
}
}
}
describe('traits', () => {
it('instance.as', () => {
const o = new TestClass();
expect(o.as).to.be.a('function');
const ot = o.as('test_trait');
expect(ot.test_method).to.be.a('function');
expect(ot.test_method()).to.equal('A');
});
it('traits of parent', () => {
const o = new TestSubClass();
console.log(o._get_merged_static_object('IMPLEMENTS'))
expect(o.as).to.be.a('function');
const ot = o.as('test_trait');
expect(ot.test_method).to.be.a('function');
expect(ot.test_method()).to.equal('A');
})
it('trait method overrides', () => {
const o = new TestSubClass();
expect(o.as).to.be.a('function');
const ot = o.as('override_trait');
expect(ot.preserved_method).to.be.a('function');
expect(ot.override_method).to.be.a('function');
expect (ot.preserved_method()).to.equal('B');
expect (ot.override_method()).to.equal('D');
})
});