Added baseName option to createUnit (#1708)

* Fixed unit base recognition and formatting for user-defined units

* Added baseName option to createUnit

* Trailing spaces

* Fixed line in docs
This commit is contained in:
Eric Mansfield 2020-01-08 02:23:23 -07:00 committed by Jos de Jong
parent 0f36dd24d4
commit 97ff95b32c
3 changed files with 36 additions and 9 deletions

View File

@ -115,7 +115,7 @@ math.createUnit('furlong', '220 yards')
math.evaluate('1 mile to furlong') // 8 furlong
```
If you cannot express the new unit in terms of any existing unit, then the second argument can be omitted. In this case, a new base unit is created:
If you cannot express the new unit in terms of any existing unit, then the second argument can be omitted. In this case, a new *base unit* is created:
```js
// A 'foo' cannot be expressed in terms of any other unit.
@ -129,6 +129,7 @@ The second argument to `createUnit` can also be a configuration object consistin
* **prefixes** A `string` indicating which prefixes math.js should use with the new unit. Possible values are `'none'`, `'short'`, `'long'`, `'binary_short'`, or `'binary_long'`. Default is `'none'`.
* **offset** A value applied when converting to the unit. This is very helpful for temperature scales that do not share a zero with the absolute temperature scale. For example, if we were defining fahrenheit for the first time, we would use: `math.createUnit('fahrenheit', {definition: '0.555556 kelvin', offset: 459.67})`
* **aliases** An array of strings to alias the new unit. Example: `math.createUnit('knot', {definition: '0.514444 m/s', aliases: ['knots', 'kt', 'kts']})`
* **baseName** A `string` that specifies the name of the new dimension in case one needs to be created. Every unit in math.js has a dimension: length, time, velocity, etc. If the unit's `definition` doesn't match any existing dimension, or it is a new base unit, then `createUnit` will create a new dimension with the name `baseName` and assign it to the new unit. The default is to append `'_STUFF'` to the unit's name. If the unit already matches an existing dimension, this option has no effect.
An optional `options` object can also be supplied as the last argument to `createUnits`. Currently only the `override` option is supported:
@ -145,7 +146,8 @@ For example:
```js
math.createUnit( {
foo: {
prefixes: 'long'
prefixes: 'long',
baseName: 'essence-of-foo'
},
bar: '40 foo',
baz: {

View File

@ -3095,11 +3095,24 @@ export const createUnitClass = /* #__PURE__ */ factory(name, dependencies, ({
* createUnitSingle('acre', new Unit(43560, 'ft^2'))
*
* @param {string} name The name of the new unit. Must be unique. Example: 'knot'
* @param {string, Unit} definition Definition of the unit in terms of existing units. For example, '0.514444444 m / s'.
* @param {Object} options (optional) An object containing any of the following properties:
* prefixes {string} "none", "short", "long", "binary_short", or "binary_long". The default is "none".
* aliases {Array} Array of strings. Example: ['knots', 'kt', 'kts']
* offset {Numeric} An offset to apply when converting from the unit. For example, the offset for celsius is 273.15 and the offset for farhenheit is 459.67. Default is 0.
* @param {string, Unit, Object} definition Definition of the unit in terms
* of existing units. For example, '0.514444444 m / s'. Can be a Unit, a string,
* or an Object. If an Object, may have the following properties:
* - definition {string|Unit} The definition of this unit.
* - prefixes {string} "none", "short", "long", "binary_short", or "binary_long".
* The default is "none".
* - aliases {Array} Array of strings. Example: ['knots', 'kt', 'kts']
* - offset {Numeric} An offset to apply when converting from the unit. For
* example, the offset for celsius is 273.15 and the offset for farhenheit
* is 459.67. Default is 0.
* - baseName {string} If the unit's dimension does not match that of any other
* base unit, the name of the newly create base unit. Otherwise, this property
* has no effect.
*
* @param {Object} options (optional) An object containing any of the following
* properties:
* - override {boolean} Whether this unit should be allowed to override existing
* units.
*
* @return {Unit}
*/
@ -3126,6 +3139,7 @@ export const createUnitClass = /* #__PURE__ */ factory(name, dependencies, ({
let offset = 0
let definition
let prefixes
let baseName
if (obj && obj.type === 'Unit') {
defUnit = obj.clone()
} else if (typeof (obj) === 'string') {
@ -3136,6 +3150,7 @@ export const createUnitClass = /* #__PURE__ */ factory(name, dependencies, ({
definition = obj.definition
prefixes = obj.prefixes
offset = obj.offset
baseName = obj.baseName
if (obj.aliases) {
aliases = obj.aliases.valueOf() // aliases could be a Matrix, so convert to Array
}
@ -3171,7 +3186,7 @@ export const createUnitClass = /* #__PURE__ */ factory(name, dependencies, ({
let newUnit = {}
if (!defUnit) {
// Add a new base dimension
const baseName = name + '_STUFF' // foo --> foo_STUFF, or the essence of foo
baseName = baseName || name + '_STUFF' // foo --> foo_STUFF, or the essence of foo
if (BASE_DIMENSIONS.indexOf(baseName) >= 0) {
throw new Error('Cannot create new base unit "' + name + '": a base unit with that name already exists (and cannot be overridden)')
}
@ -3234,7 +3249,7 @@ export const createUnitClass = /* #__PURE__ */ factory(name, dependencies, ({
}
}
if (!anyMatch) {
const baseName = name + '_STUFF' // foo --> foo_STUFF, or the essence of foo
baseName = baseName || name + '_STUFF' // foo --> foo_STUFF, or the essence of foo
// Add the new base unit
const newBaseUnit = { dimensions: defUnit.dimensions.slice(0) }
newBaseUnit.key = baseName

View File

@ -1164,6 +1164,16 @@ describe('Unit', function () {
assert.strictEqual('jabberwocky_STUFF' in Unit.BASE_UNITS, true)
assert.strictEqual(math.evaluate('4 mile^5/minute').format(4), '240 jabberwocky')
})
it('should use baseName', function () {
Unit.createUnitSingle('truck', { baseName: 'VEHICLE' })
Unit.createUnitSingle('speedy', { definition: '1 truck/day', baseName: 'VEHICLE_PRODUCTION_RATE' })
assert('VEHICLE' in Unit.BASE_UNITS)
assert('VEHICLE_PRODUCTION_RATE' in Unit.BASE_UNITS)
assert(new Unit(1, 'truck').hasBase('VEHICLE'))
assert(new Unit(1, 'truck/day').hasBase('VEHICLE_PRODUCTION_RATE'))
assert.strictEqual(math.evaluate('10 truck/hr').format(4), '240 speedy')
})
})
describe('createUnit', function () {