Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/expression/embeddedDocs/construction/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ export const indexDocs = {
'B[B>1 and B<3]'
],
seealso: [
'bignumber', 'boolean', 'complex', 'matrix,', 'number', 'range', 'string', 'unit'
'bignumber', 'boolean', 'complex', 'matrix', 'number', 'range', 'string', 'unit'
]
}
6 changes: 6 additions & 0 deletions src/expression/embeddedDocs/embeddedDocs.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ import { conjDocs } from './function/complex/conj.js'
import { imDocs } from './function/complex/im.js'
import { reDocs } from './function/complex/re.js'
import { evaluateDocs } from './function/expression/evaluate.js'
import { parserDocs } from './function/expression/parser.js'
import { parseDocs } from './function/expression/parse.js'
import { compileDocs } from './function/expression/compile.js'
import { helpDocs } from './function/expression/help.js'
import { distanceDocs } from './function/geometry/distance.js'
import { intersectDocs } from './function/geometry/intersect.js'
Expand Down Expand Up @@ -429,6 +432,9 @@ export const embeddedDocs = {
// functions - expression
evaluate: evaluateDocs,
help: helpDocs,
parse: parseDocs,
parser: parserDocs,
compile: compileDocs,

// functions - geometry
distance: distanceDocs,
Expand Down
16 changes: 16 additions & 0 deletions src/expression/embeddedDocs/function/expression/compile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const compileDocs = {
name: 'compile',
category: 'Expression',
syntax: [
'compile(expr) ',
'compile([expr1, expr2, expr3, ...])'
],
description: 'Parse and compile an expression. Returns a an object with a function evaluate([scope]) to evaluate the compiled expression.',
examples: [
'code1 = compile("sqrt(3^2 + 4^2)")',
'code1.evaluate() ',
'code2 = compile("a * b")',
'code2.evaluate({a: 3, b: 4})'
],
seealso: ['parser', 'parse', 'evaluate']
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ export const evaluateDocs = {
'evaluate("sin(x * pi)", { "x": 1/2 })',
'evaluate(["width=2", "height=4","width*height"])'
],
seealso: []
seealso: ['parser', 'parse', 'compile']
}
23 changes: 23 additions & 0 deletions src/expression/embeddedDocs/function/expression/parse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const parseDocs = {
name: 'parse',
category: 'Expression',
syntax: [
'parse(expr)',
'parse(expr, options)',
'parse([expr1, expr2, expr3, ...])',
'parse([expr1, expr2, expr3, ...], options)'
],
description: 'Parse an expression. Returns a node tree, which can be evaluated by invoking node.evaluate() or transformed into a functional object via node.compile().',
examples: [
'node1 = parse("sqrt(3^2 + 4^2)")',
'node1.evaluate()',
'code1 = node1.compile()',
'code1.evaluate()',
'scope = {a: 3, b: 4}',
'node2 = parse("a * b")',
'node2.evaluate(scope)',
'code2 = node2.compile()',
'code2.evaluate(scope)'
],
seealso: ['parser', 'evaluate', 'compile']
}
17 changes: 17 additions & 0 deletions src/expression/embeddedDocs/function/expression/parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const parserDocs = {
name: 'parser',
category: 'Expression',
syntax: [
'parser()'
],
description: 'Create a parser object that keeps a context of variables and their values, allowing the evaluation of expressions in that context.',
examples: [
'myParser = parser()',
'myParser.evaluate("sqrt(3^2 + 4^2)")',
'myParser.set("x", 3)',
'myParser.evaluate("y = x + 3")',
'myParser.evaluate(["y = x + 3", "y = y + 1"])',
'myParser.get("y")'
],
seealso: ['evaluate', 'parse', 'compile']
}
1 change: 0 additions & 1 deletion src/expression/embeddedDocs/function/statistics/sum.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export const sumDocs = {
'min',
'prod',
'std',
'sum',
'variance'
]
}
2 changes: 1 addition & 1 deletion src/expression/function/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const dependencies = ['typed', 'Parser']

export const createParser = /* #__PURE__ */ factory(name, dependencies, ({ typed, Parser }) => {
/**
* Create a parser. The function creates a new `math.Parser` object.
* Create a `math.Parser` object that keeps a context of variables and their values, allowing the evaluation of expressions in that context.
*
* Syntax:
*
Expand Down
3 changes: 2 additions & 1 deletion src/expression/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({
}) => {
/**
* Parse an expression. Returns a node tree, which can be evaluated by
* invoking node.evaluate().
* invoking node.evaluate() or transformed into a functional object via node.compile().
*
* Note the evaluating arbitrary expressions may involve security risks,
* see [https://mathjs.org/docs/expressions/security.html](https://mathjs.org/docs/expressions/security.html) for more information.
Expand All @@ -67,6 +67,7 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({
*
* let scope = {a:3, b:4}
* const node2 = math.parse('a * b') // 12
* node2.evaluate(scope) // 12
* const code2 = node2.compile()
* code2.evaluate(scope) // 12
* scope.a = 5
Expand Down
77 changes: 76 additions & 1 deletion test/unit-tests/expression/function/help.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,59 @@ import assert from 'assert'
import math from '../../../../src/defaultInstance.js'
import { embeddedDocs } from '../../../../src/expression/embeddedDocs/embeddedDocs.js'

let mathDocs = math.create(math.all)
const originalConfig = mathDocs.config()
// Add names to the skipDocs array if they are not meant to have embedded docs
const skipDocs = new Set(['import', 'addScalar', 'divideScalar', 'equalScalar', 'multiplyScalar',
'subtractScalar', 'apply', 'replacer', 'reviver'])

// Add names to skipExamples if their examples in the embedded docs contain acceptable errors
const skipExamples = new Set([])

const testDocs = new Set([
...Object.keys(embeddedDocs),
...Object.keys(math.expression.mathWithTransform)
].filter(name => { return !skipDocs.has(name) }))

const testExamples = new Set([...testDocs].filter(name => {
return !skipExamples.has(name)
}))

function runExamplesInDocs (name) {
mathDocs.config(originalConfig)
// every funciton should have doc.examples
const examples = mathDocs.evaluate(`help("${name}")`).doc.examples
try {
// validate if the examples run without errors
mathDocs.evaluate(examples)
return
} catch {
}
// if they still have errors try with a new math instance
mathDocs = math.create(math.all)
mathDocs.evaluate(examples)
}

function hasValidSeeAlso (name) {
let seeAlso = []
try {
seeAlso = mathDocs.evaluate(`help("${name}")`).doc.seealso
} catch (err) {
return
}
if (seeAlso && seeAlso.length > 0) {
seeAlso.forEach(see => {
if (testDocs.has(see)) {
if (see === name) {
throw new Error(`See also name "${see}" should not be the same as "${name}" in docs for "${name}".`)
}
} else {
throw new Error(`See also with name "${see}" is not a valid documentation name used in docs for "${name}".`)
}
})
}
}

describe('help', function () {
it('should find documentation for a function by its name', function () {
const help = math.help('sin')
Expand Down Expand Up @@ -59,11 +112,33 @@ describe('help', function () {
// assert.throws(function () {math.help(undefined)}, /No documentation found/);
assert.throws(function () { math.help(new Date()) }, /No documentation found/)
assert.throws(function () { math.help('nonExistingFunction') }, /No documentation found/)
assert.throws(function () { math.help('parse') }, /No documentation found/)
assert.throws(function () { math.help('addScalar') }, /No documentation found/)
})

it('should LaTeX help', function () {
const expression = math.parse('help(parse)')
assert.strictEqual(expression.toTex(), '\\mathrm{help}\\left( parse\\right)')
})

for (const name of testDocs) {
it(`should find documentation for ${name}`, function () {
assert.doesNotThrow(() => mathDocs.help(name).doc)
})
}

for (const name of testDocs) {
it(`should find examples for ${name}`, function () {
assert.doesNotThrow(() => mathDocs.help(name).doc.examples)
})
}
for (const name of testExamples) {
it(`should run examples for ${name} without errors`, function () {
assert.doesNotThrow(() => runExamplesInDocs(name))
})
}
for (const name of testDocs) {
it(`should have all valid See Also for ${name} that are not ${name}`, function () {
assert.doesNotThrow(() => hasValidSeeAlso(name))
})
}
})