mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
Added Unit.createUnits and createUnits function, and tests.
This commit is contained in:
parent
1588b0ebe0
commit
b7978dee23
@ -370,11 +370,13 @@ function factory (type, config, load, typed, math) {
|
||||
}
|
||||
|
||||
// Replace the unit into the auto unit system
|
||||
var baseDim = res.unit.base.key;
|
||||
UNIT_SYSTEMS.auto[baseDim] = {
|
||||
unit: res.unit,
|
||||
prefix: res.prefix
|
||||
};
|
||||
if(res.unit.base) {
|
||||
var baseDim = res.unit.base.key;
|
||||
UNIT_SYSTEMS.auto[baseDim] = {
|
||||
unit: res.unit,
|
||||
prefix: res.prefix
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Has the string been entirely consumed?
|
||||
@ -538,6 +540,17 @@ function factory (type, config, load, typed, math) {
|
||||
* @private
|
||||
*/
|
||||
function _findUnit(str) {
|
||||
|
||||
// First, match units names exactly. For example, a user could define 'mm' as 10^-4 m, which is silly, but then we would want 'mm' to match the user-defined unit.
|
||||
if(UNITS.hasOwnProperty(str)) {
|
||||
var unit = UNITS[str];
|
||||
var prefix = unit.prefixes[''];
|
||||
return {
|
||||
unit: unit,
|
||||
prefix: prefix
|
||||
}
|
||||
}
|
||||
|
||||
for (var name in UNITS) {
|
||||
if (UNITS.hasOwnProperty(name)) {
|
||||
if (endsWith(str, name)) {
|
||||
@ -2863,6 +2876,78 @@ function factory (type, config, load, typed, math) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a user-defined unit and register it with the Unit type.
|
||||
* Example:
|
||||
* createUnit('knot', '0.514444444 m/s')
|
||||
* createUnit('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.
|
||||
*
|
||||
* @return {Unit}
|
||||
*/
|
||||
Unit.createUnit = function(name, definition, options) {
|
||||
|
||||
if(typeof(name) !== 'string') {
|
||||
throw new TypeError("createUnit expects first parameter to be of type 'string'");
|
||||
}
|
||||
|
||||
// Check collisions with existing units
|
||||
if(UNITS.hasOwnProperty(name)) {
|
||||
throw new Error("Cannot create unit '" + name + "': a unit with that name already exists");
|
||||
}
|
||||
|
||||
// TODO: Validate name for collisions with other built-in functions (like abs or cos, for example), and for acceptable variable names. For example, '42' is probably not a valid unit. Nor is '%', since it is also an operator.
|
||||
|
||||
var defUnit;
|
||||
if(typeof(definition) === 'string') {
|
||||
defUnit = Unit.parse(definition);
|
||||
}
|
||||
else if(definition && definition.type === 'Unit') {
|
||||
defUnit = definition.clone();
|
||||
}
|
||||
else {
|
||||
throw new TypeError("createUnit expects second parameter to be of type 'string' or 'Unit'");
|
||||
}
|
||||
|
||||
var prefixes = PREFIXES.NONE;
|
||||
var aliases = [];
|
||||
var offset = 0;
|
||||
if(options) {
|
||||
if(options.prefixes) {
|
||||
prefixes = PREFIXES[options.prefixes.toUpperCase()] || PREFIXES.NONE;
|
||||
}
|
||||
aliases = options.aliases || [];
|
||||
offset = options.offset || 0;
|
||||
}
|
||||
|
||||
var newUnit = {
|
||||
name: name,
|
||||
value: defUnit.value,
|
||||
dimensions: JSON.parse(JSON.stringify(defUnit.dimensions)),
|
||||
prefixes: prefixes,
|
||||
offset: offset
|
||||
}
|
||||
|
||||
Unit.UNITS[name] = newUnit;
|
||||
|
||||
for (var i=0; i<aliases.length; i++) {
|
||||
var name = aliases[i];
|
||||
var alias = Object.create(newUnit);
|
||||
alias.name = name;
|
||||
Unit.UNITS[name] = alias;
|
||||
}
|
||||
|
||||
return new Unit(null, name);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Unit.PREFIXES = PREFIXES;
|
||||
Unit.BASE_UNITS = BASE_UNITS;
|
||||
Unit.UNITS = UNITS;
|
||||
|
||||
39
lib/type/unit/function/createUnit.js
Normal file
39
lib/type/unit/function/createUnit.js
Normal file
@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
var deepMap = require('../../../utils/collection/deepMap');
|
||||
|
||||
function factory (type, config, load, typed) {
|
||||
/**
|
||||
* Create a user-defined unit and register it with the Unit type.
|
||||
*
|
||||
* Syntax:
|
||||
*
|
||||
* math.createUnit(string, unit : string, [object])
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* math.createUnit('knot', '0.514444444 m/s', {aliases: ['knots', 'kt', 'kts]})
|
||||
*
|
||||
* @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. Default is 0.
|
||||
*
|
||||
* @return {Unit} The new unit
|
||||
*/
|
||||
var createUnit = typed('createUnit', {
|
||||
'string, Unit | string': function (name, def) {
|
||||
return type.Unit.createUnit(name, def);
|
||||
},
|
||||
'string, Unit | string, Object': function (name, def, options) {
|
||||
return type.Unit.createUnit(name, def, options);
|
||||
}
|
||||
});
|
||||
|
||||
return createUnit;
|
||||
}
|
||||
|
||||
exports.name = 'createUnit';
|
||||
exports.factory = factory;
|
||||
@ -5,6 +5,9 @@ module.exports = [
|
||||
// construction function
|
||||
require('./function/unit'),
|
||||
|
||||
// create new units
|
||||
require('./function/createUnit'),
|
||||
|
||||
// physical constants
|
||||
require('./physicalConstants')
|
||||
];
|
||||
|
||||
@ -1040,4 +1040,60 @@ describe('Unit', function() {
|
||||
assert.equal(new Unit(1, 'eV') .equals(new Unit(1.602176565e-19, 'J')), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createUnit', function() {
|
||||
it('should create a custom unit from a string definition', function() {
|
||||
Unit.createUnit('widget', '5 kg bytes');
|
||||
assert.equal(new Unit(1, 'widget').equals(new Unit(5, 'kg bytes')), true);
|
||||
Unit.createUnit('woggle', '4 widget^2');
|
||||
assert.equal(new Unit(1, 'woggle').equals(new Unit(4, 'widget^2')), true);
|
||||
assert.equal(new Unit(2, 'woggle').equals(new Unit(200, 'kg^2 bytes^2')), true);
|
||||
});
|
||||
|
||||
it('should create a custom unit from a Unit definition', function() {
|
||||
var Unit1 = new Unit(5, 'N/woggle');
|
||||
Unit.createUnit('gadget', Unit1);
|
||||
assert.equal(new Unit(1, 'gadget').equals(new Unit(5, 'N/woggle')), true);
|
||||
});
|
||||
|
||||
it('should return the new (value-less) unit', function() {
|
||||
var Unit2 = new Unit(1000, 'N h kg^-2 bytes^-2');
|
||||
var newUnit = Unit.createUnit('whimsy', '8 gadget hours');
|
||||
assert.equal(Unit2.to(newUnit).toString(), '2500 whimsy');
|
||||
});
|
||||
|
||||
it('should not override an existing unit', function() {
|
||||
assert.throws(function () { Unit.createUnit('m', '1 kg'); }, /Cannot create unit .*: a unit with that name already exists/);
|
||||
assert.throws(function () { Unit.createUnit('gadget', '1 kg'); }, /Cannot create unit .*: a unit with that name already exists/);
|
||||
});
|
||||
|
||||
it('should throw an error for invalid parameters', function() {
|
||||
assert.throws(function() { Unit.createUnit(); }, /createUnit expects first parameter/);
|
||||
assert.throws(function() { Unit.createUnit(42); }, /createUnit expects first parameter/);
|
||||
assert.throws(function() { Unit.createUnit('42'); }, /createUnit expects second parameter/);
|
||||
assert.throws(function() { Unit.createUnit('42', 3.14); }, /createUnit expects second parameter/);
|
||||
});
|
||||
|
||||
it('should apply the correct prefixes', function() {
|
||||
Unit.createUnit('millizilch', '1e-3 m', {prefixes: 'long'});
|
||||
assert.equal(new Unit(1e-6, 'millizilch').toString(), '1 micromillizilch');
|
||||
});
|
||||
|
||||
it('should override prefixed built-in units', function() {
|
||||
Unit.createUnit('mm', '1e-4 m', {prefixes: 'short'}); // User is being silly
|
||||
assert.equal(new Unit(1e-3, 'mm').toString(), '1 mmm'); // Use the user's new definition
|
||||
assert.equal(new Unit(1e-3, 'mm').to('m').format(4), '1e-7 m'); // Use the user's new definition
|
||||
});
|
||||
|
||||
it('should create aliases', function() {
|
||||
Unit.createUnit('knot', '0.51444444 m/s', {aliases:['knots', 'kts', 'kt']});
|
||||
assert.equal(new Unit(1, 'knot').equals(new Unit(1, 'kts')), true);
|
||||
assert.equal(new Unit(1, 'kt').equals(new Unit(1, 'knots')), true);
|
||||
});
|
||||
|
||||
it('should apply offset correctly', function() {
|
||||
Unit.createUnit('whatsit', '3.14 kN', {offset:2});
|
||||
assert.equal(new Unit(1, 'whatsit').to('kN').toString(), '9.42 kN');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
33
test/type/unit/function/createUnit.test.js
Normal file
33
test/type/unit/function/createUnit.test.js
Normal file
@ -0,0 +1,33 @@
|
||||
var assert = require('assert');
|
||||
var math = require('../../../../index');
|
||||
var createUnit = math.createUnit;
|
||||
var Unit = math.type.Unit;
|
||||
|
||||
describe('createUnit', function() {
|
||||
|
||||
it('should create a unit', function () {
|
||||
var u = createUnit('flibbity', '4 hogshead');
|
||||
assert.equal(math.eval('2 flibbity to hogshead').toString(), '8 hogshead');
|
||||
});
|
||||
|
||||
it('should accept a unit as second parameter', function () {
|
||||
assert.equal(math.eval('50 in^2 to createUnit("bingo", 25 in^2)').toString(), '2 bingo');
|
||||
});
|
||||
|
||||
it('should accept a unit as second parameter', function () {
|
||||
assert.equal(math.eval('50 in^2 to createUnit("zingo", "25 in^2")').toString(), '2 zingo');
|
||||
});
|
||||
|
||||
it('should return the created unit', function() {
|
||||
assert.equal(math.eval('createUnit("giblet", "6 flibbity")').toString(), 'giblet');
|
||||
assert.equal(math.eval('120 hogshead to createUnit("fliblet", "0.25 giblet")').format(4), '20 fliblet');
|
||||
});
|
||||
|
||||
it('should accept options', function() {
|
||||
math.eval('createUnit("whosit", 3.14 kN, {prefixes:"long"})');
|
||||
assert.equal(math.eval('1e-9 whosit').toString(), '1 nanowhosit');
|
||||
|
||||
math.eval('createUnit("wheresit", 3.14 kN, {offset:2})');
|
||||
assert.equal(math.eval('1 wheresit to kN').toString(), '9.42 kN');
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user