pocomath/test/custom.mjs
Glen Whitney d9d7af961f refactor: Simpler merging mechanism
Merging of Pocomath modules is eased by allowing one PocomathInstance to
  be merged into another. That allows types, for example, to be exported
  as a PocomathInstance (so there is no need for a special identifier
  convention for types; they can be directly added with an installType
  method). Also, larger modules can just be exported as an instance, since
  there is more flexibility and more checking in merging PocomathInstances
  than raw modules.
2022-07-27 22:28:40 -07:00

99 lines
3.9 KiB
JavaScript

import assert from 'assert'
import math from '../src/pocomath.mjs'
import PocomathInstance from '../src/core/PocomathInstance.mjs'
import * as numbers from '../src/number/all.mjs'
import * as numberAdd from '../src/number/add.mjs'
import * as complex from '../src/complex/all.mjs'
import * as complexAdd from '../src/complex/add.mjs'
import * as complexNegate from '../src/complex/negate.mjs'
import * as complexComplex from '../src/complex/complex.mjs'
import * as concreteSubtract from '../src/generic/subtract.concrete.mjs'
import * as genericSubtract from '../src/generic/subtract.mjs'
import extendToComplex from '../src/complex/extendToComplex.mjs'
const bw = new PocomathInstance('backwards')
describe('A custom instance', () => {
it("works when partially assembled", () => {
bw.install(complex)
// Not much we can call without any number types:
assert.deepStrictEqual(bw.complex(0, 3), {re: 0, im: 3})
// Don't have a way to negate things, for example:
assert.throws(() => bw.negate(2), TypeError)
})
it("can be assembled in any order", () => {
bw.install(numbers)
bw.installType('string', {test: s => typeof s === 'string'})
assert.strictEqual(bw.subtract(16, bw.add(3,4,2)), 7)
assert.strictEqual(bw.negate('8'), -8)
assert.deepStrictEqual(bw.add(bw.complex(1,3), 1), {re: 2, im: 3})
assert.deepStrictEqual(
bw.subtract(16, bw.add(3, bw.complex(0,4), 2)),
math.complex(11, -4)) // note both instances coexist
assert.deepStrictEqual(bw.negate(math.complex(3, '8')).im, -8)
})
it("can be assembled piecemeal", () => {
const pm = new PocomathInstance('piecemeal')
pm.install(numbers)
assert.strictEqual(pm.subtract(5, 10), -5)
pm.install(complexAdd)
pm.install(complexNegate)
// Should be enough to allow complex subtraction, as subtract is generic:
assert.deepStrictEqual(
pm.subtract({re:5, im:0}, {re:10, im:1}), {re:-5, im: -1})
})
it("can defer definition of (even used) types", () => {
const dt = new PocomathInstance('Deferred Types')
dt.install(numberAdd)
dt.install({times: {
'number,number': () => (m,n) => m*n,
'Complex,Complex': ({complex}) => (w,z) => {
return complex(w.re*z.re - w.im*z.im, w.re*z.im + w.im*z.re)
}
}})
// complex type not present but should still be able to add numbers:
assert.strictEqual(dt.times(3,5), 15)
dt.install(complexComplex)
// times should now rebundle to allow complex:
assert.deepStrictEqual(
dt.times(dt.complex(2,3), dt.complex(2,-3)), dt.complex(13))
})
it("can selectively import in cute ways", async function () {
const cherry = new PocomathInstance('cherry')
cherry.install(numberAdd)
await extendToComplex(cherry)
/* Now we have an instance that supports addition for number and complex
and little else:
*/
assert.strictEqual(cherry.add(3, 4, 2), 9)
assert.deepStrictEqual(
cherry.add(cherry.complex(3, 3), 4, cherry.complex(2, 2)),
math.complex(9,5))
assert.strictEqual('subtract' in cherry, false)
assert.strictEqual('negate' in cherry, false)
})
it("can use bundles that are closed under dependency", () => {
const ok = new PocomathInstance('concrete')
ok.install(concreteSubtract)
assert.strictEqual(ok.subtract(7, 5), 2)
})
it("can load generics and then import their dependences", async function () {
const chase = new PocomathInstance('Chase Dependencies')
chase.install(genericSubtract)
chase.install(complexComplex) // for convenience to build complex numbers
await chase.importDependencies(['bigint', 'complex'])
/* Now we have an instance that supports subtraction for Gaussian
integers.
*/
assert.deepStrictEqual(
chase.subtract(chase.complex(3n, 2n), chase.complex(2n, 5n)),
math.complex(1n, -3n))
})
})