1 /* 2 * MeasurementFactory.js - Function to instantiate the appropriate subclasses of 3 * the Measurement class. 4 * 5 * Copyright © 2015, 2018, JEDLSoft 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 /* 22 !depends 23 UnknownUnit.js 24 AreaUnit.js 25 DigitalStorageUnit.js 26 DigitalSpeedUnit.js 27 EnergyUnit.js 28 FuelConsumptionUnit.js 29 LengthUnit.js 30 MassUnit.js 31 TemperatureUnit.js 32 TimeUnit.js 33 VelocityUnit.js 34 VolumeUnit.js 35 Measurement.js 36 */ 37 38 // TODO: make these dependencies dynamic or at least generate them in the build 39 // These will each add themselves to Measurement._constructors[] 40 var UnknownUnit = require("./UnknownUnit.js"); 41 var AreaUnit = require("./AreaUnit.js"); 42 var DigitalStorageUnit = require("./DigitalStorageUnit.js"); 43 var DigitalSpeedUnit = require("./DigitalSpeedUnit.js"); 44 var EnergyUnit = require("./EnergyUnit.js"); 45 var FuelConsumptionUnit = require("./FuelConsumptionUnit.js"); 46 var LengthUnit = require("./LengthUnit.js"); 47 var MassUnit = require("./MassUnit.js"); 48 var TemperatureUnit = require("./TemperatureUnit.js"); 49 var TimeUnit = require("./TimeUnit.js"); 50 var VelocityUnit = require("./VelocityUnit.js"); 51 var VolumeUnit = require("./VolumeUnit.js"); 52 53 var Measurement = require("./Measurement.js"); 54 55 /** 56 * Create a measurement subclass instance based on a particular measure 57 * required. The measurement is immutable once 58 * it is created, but it can be converted to other measurements later.<p> 59 * 60 * The options may contain any of the following properties: 61 * 62 * <ul> 63 * <li><i>amount</i> - either a numeric amount for this measurement given 64 * as a number of the specified units, or another Measurement instance 65 * to convert to the requested units. If converting to new units, the type 66 * of measure between the other instance's units and the current units 67 * must be the same. That is, you can only convert one unit of mass to 68 * another. You cannot convert a unit of mass into a unit of length. 69 * 70 * <li><i>unit</i> - units of this measurement. Use the 71 * static call {@link MeasurementFactory.getAvailableUnits} 72 * to find out what units this version of ilib supports. If the given unit 73 * is not a base unit, the amount will be normalized to the number of base units 74 * and stored as that number of base units. 75 * For example, if an instance is constructed with 1 kg, this will be converted 76 * automatically into 1000 g, as grams are the base unit and kg is merely a 77 * commonly used scale of grams. 78 * </ul> 79 * 80 * Here are some examples of converting a length into new units. 81 * The first method is via this factory function by passing the old measurement 82 * in as the "amount" property.<p> 83 * 84 * <pre> 85 * var measurement1 = MeasurementFactory({ 86 * amount: 5, 87 * units: "kilometers" 88 * }); 89 * var measurement2 = MeasurementFactory({ 90 * amount: measurement1, 91 * units: "miles" 92 * }); 93 * </pre> 94 * 95 * The value in measurement2 will end up being about 3.125 miles.<p> 96 * 97 * The second method uses the convert method.<p> 98 * 99 * <pre> 100 * var measurement1 = MeasurementFactory({ 101 * amount: 5, 102 * units: "kilometers" 103 * }); 104 * var measurement2 = measurement1.convert("miles"); 105 * }); 106 * </pre> 107 * 108 * The value in measurement2 will again end up being about 3.125 miles. 109 * 110 * @static 111 * @param {Object=} options options that control the construction of this instance 112 */ 113 var MeasurementFactory = function(options) { 114 if (!options || typeof(options.unit) === 'undefined') { 115 return undefined; 116 } 117 118 var measurement, measure = undefined; 119 120 // first try in the existing case 121 for (var c in Measurement._constructors) { 122 measurement = Measurement._constructors[c]; 123 if (Measurement.getUnitId(measurement, options.unit)) { 124 measure = c; 125 break; 126 } 127 } 128 129 if (!measure) { 130 // if it wasn't found before, try again in lower case -- this may recognize incorrectly because some 131 // units can differ only in their case like "mm" and "Mm" 132 for (var c in Measurement._constructors) { 133 measurement = Measurement._constructors[c]; 134 if (typeof(Measurement.getUnitIdCaseInsensitive(measurement, options.unit)) !== 'undefined') { 135 measure = c; 136 break; 137 } 138 } 139 } 140 141 if (!measure || typeof(measure) === 'undefined') { 142 return new UnknownUnit({ 143 unit: options.unit, 144 amount: options.amount 145 }); 146 } else { 147 return new Measurement._constructors[measure](options); 148 } 149 }; 150 151 /** 152 * Return a list of all possible units that this version of ilib supports. 153 * Typically, the units are given as their full names in English. Unit names 154 * are case-insensitive. 155 * 156 * @static 157 * @return {Array.<string>} an array of strings containing names of measurement 158 * units available 159 */ 160 MeasurementFactory.getAvailableUnits = function () { 161 var units = []; 162 for (var c in Measurement._constructors) { 163 var measure = Measurement._constructors[c]; 164 units = units.concat(measure.getMeasures()); 165 } 166 return units; 167 }; 168 169 module.exports = MeasurementFactory; 170