Skip to content

Commit

Permalink
Transform inherited methods & bind methods to original object
Browse files Browse the repository at this point in the history
Fixes #14
Closes #27
Closes #16
  • Loading branch information
kevinoid authored and sindresorhus committed May 27, 2017
1 parent 1fc9ec7 commit 1701541
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 9 deletions.
24 changes: 15 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,23 @@ module.exports = (obj, opts) => {
return opts.include ? opts.include.some(match) : !opts.exclude.some(match);
};

const ret = typeof obj === 'function' ? function () {
if (opts.excludeMain) {
return obj.apply(this, arguments);
}
let ret;
if (typeof obj === 'function') {
ret = function () {
if (opts.excludeMain) {
return obj.apply(this, arguments);
}

return processFn(obj, opts).apply(this, arguments);
} : {};
return processFn(obj, opts).apply(this, arguments);
};
} else {
ret = Object.create(Object.getPrototypeOf(obj));
}

return Object.keys(obj).reduce((ret, key) => {
for (const key in obj) { // eslint-disable-line guard-for-in
const x = obj[key];
ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x;
return ret;
}, ret);
}

return ret;
};
116 changes: 116 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import util from 'util';
import fs from 'fs';
import stream from 'stream';
import test from 'ava';
Expand Down Expand Up @@ -27,6 +28,23 @@ const fixtureModule = {
method3: fixture5
};

function FixtureGrandparent() {}
FixtureGrandparent.prototype.grandparentMethod1 = fixture;
FixtureGrandparent.prototype.overriddenMethod1 = fixture;
function FixtureParent() {}
util.inherits(FixtureParent, FixtureGrandparent);
FixtureParent.prototype.parentMethod1 = fixture;
FixtureParent.prototype.overriddenMethod1 = fixture2;
FixtureParent.prototype.overriddenValue1 = 2;
function FixtureClass() {
this.instanceMethod1 = fixture;
this.instanceValue1 = 72;
}
util.inherits(FixtureClass, FixtureParent);
FixtureClass.prototype.method1 = fixture;
FixtureParent.prototype.overriddenValue1 = 4;
FixtureClass.prototype.value1 = 'neo';

test('main', async t => {
t.is(typeof m(fixture)().then, 'function');
t.is(await m(fixture)(), 'unicorn');
Expand Down Expand Up @@ -142,3 +160,101 @@ test('`errorFirst` option and `multiArgs`', async t => {
multiArgs: true
})('🦄', '🌈'), ['🦄', '🌈']);
});

test('class support - creates a copy', async t => {
const obj = {
x: 'foo',
y(cb) {
setImmediate(() => {
cb(null, this.x);
});
}
};

const pified = m(obj, {bind: false});
obj.x = 'bar';

t.is(await pified.y(), 'foo');
t.is(pified.x, 'foo');
});

test('class support — transforms inherited methods', t => {
const instance = new FixtureClass();
const pInstance = m(instance);

const flattened = {};
for (let prot = instance; prot; prot = Object.getPrototypeOf(prot)) {
Object.assign(flattened, prot);
}

const keys = Object.keys(flattened);
keys.sort();
const pKeys = Object.keys(pInstance);
pKeys.sort();
t.deepEqual(keys, pKeys);

t.is(instance.value1, pInstance.value1);
t.is(typeof pInstance.instanceMethod1().then, 'function');
t.is(typeof pInstance.method1().then, 'function');
t.is(typeof pInstance.parentMethod1().then, 'function');
t.is(typeof pInstance.grandparentMethod1().then, 'function');
});

test('class support — preserves prototype', t => {
const instance = new FixtureClass();
const pInstance = m(instance);

t.true(pInstance instanceof FixtureClass);
});

test('class support — respects inheritance order', async t => {
const instance = new FixtureClass();
const pInstance = m(instance);

t.is(instance.overriddenValue1, pInstance.overriddenValue1);
t.is(await pInstance.overriddenMethod1('rainbow'), 'rainbow');
});

test('class support - transforms only members in options.include, copies all', t => {
const instance = new FixtureClass();
const pInstance = m(instance, {
include: ['parentMethod1']
});

const flattened = {};
for (let prot = instance; prot; prot = Object.getPrototypeOf(prot)) {
Object.assign(flattened, prot);
}

const keys = Object.keys(flattened);
keys.sort();
const pKeys = Object.keys(pInstance);
pKeys.sort();
t.deepEqual(keys, pKeys);

t.is(typeof pInstance.parentMethod1().then, 'function');
t.not(typeof pInstance.method1(() => {}).then, 'function');
t.not(typeof pInstance.grandparentMethod1(() => {}).then, 'function');
});

test('class support - doesn\'t transform members in options.exclude', t => {
const instance = new FixtureClass();
const pInstance = m(instance, {
exclude: ['grandparentMethod1']
});

t.not(typeof pInstance.grandparentMethod1(() => {}).then, 'function');
t.is(typeof pInstance.parentMethod1().then, 'function');
});

test('class support - options.include over options.exclude', t => {
const instance = new FixtureClass();
const pInstance = m(instance, {
include: ['method1', 'parentMethod1'],
exclude: ['parentMethod1', 'grandparentMethod1']
});

t.is(typeof pInstance.method1().then, 'function');
t.is(typeof pInstance.parentMethod1().then, 'function');
t.not(typeof pInstance.grandparentMethod1(() => {}).then, 'function');
});

0 comments on commit 1701541

Please sign in to comment.