Skip to content
Open
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
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,37 @@ m(12).inches;
m(12, inch);
```

##### Implicit conversion

Measurements created with `m` can also be implicitly converted.

###### `m(number, unit).as(unit)`

```js
const foot = createUnit('foot', {
convert: {
from: [inch, conversion.divideBy(12)],
},
});
const fourFeet = m`48 inches`.as(foot);
fourFeet.value === 4;
fourFeet.unit === foot;
```

###### `m(number, unit).in.<alias>`

```js
createUnit('foot', {
alias: 'feet',
convert: {
from: [inch, conversion.divideBy(12)],
},
});
const fourFeet = m`48 inches`.in.feet;
fourFeet.value === 4;
fourFeet.unit === foot;
```

#### `convert(measurement, unit)`

Given a `Measurement` and a `Unit`, `convert(measurement, unit)` will attempt to convert that measurement to the given unit. (see `UnitSystem#convert()` for details)
Expand Down
16 changes: 15 additions & 1 deletion src/UnitSystem/UnitSystem.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { add, subtract, multiply, divide } = require('../math');
const createAliasedMeasurementProxy = require('../createAliasedMeasurementProxy');
const Measurement = require('../Measurement');
const Unit = require('../Unit');
const Aliases = require('./Aliases');
Expand All @@ -10,6 +11,18 @@ class UnitSystem {
this._aliases = new Aliases();
this._converters = new Converters();

const system = this;
this.SystemMeasurement = class SystemMeasurement extends Measurement {
get in() {
return createAliasedMeasurementProxy(system, unit =>
system.convert(this, unit)
);
}
as(unit) {
return system.convert(this, unit);
}
};

this.registerAll(units);
}

Expand Down Expand Up @@ -102,7 +115,8 @@ class UnitSystem {
}`
);
}
return new Measurement(convert(measurement.value), endUnit);
const { SystemMeasurement } = this;
return new SystemMeasurement(convert(measurement.value), endUnit);
}

_normalizeUnits(measurements) {
Expand Down
21 changes: 21 additions & 0 deletions src/createAliasedMeasurementProxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Returns a proxy object. Any alias in the given unit system
// is a valid property, and getting one of those properties
// will return the result of calling `getValueForUnit` with
// the corresponding unit for that alias.
//
// For example:
// const obj = createAliasedMeasurementProxy(
// system,
// unit => `${unit.name.toUpperCase()}!!`
// );
// obj.ft // -> "FOOT!!", if "ft" was registered as an alias
// for `new Unit("foot")`
function createAliasedMeasurementProxy(system, getValueForUnit) {
return new Proxy(Object.create(null), {
get(target, alias) {
const unit = system.getUnitForAlias(alias);
return getValueForUnit(unit);
},
});
}
module.exports = createAliasedMeasurementProxy;
18 changes: 7 additions & 11 deletions src/createMeasurement.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
const createAliasedMeasurementProxy = require('./createAliasedMeasurementProxy');
const Unit = require('./Unit');
const Measurement = require('./Measurement');

function createMeasurement(system) {
function createAliasLookupObject(value) {
return new Proxy(Object.create(null), {
get(target, alias) {
const unit = system.getUnitForAlias(alias);
return new Measurement(value, unit);
},
});
}
const { SystemMeasurement } = system;

return function m(value, unit) {
if (Array.isArray(value)) {
Expand All @@ -20,9 +13,12 @@ function createMeasurement(system) {
}

if (!(unit instanceof Unit)) {
return createAliasLookupObject(value);
return createAliasedMeasurementProxy(
system,
unit => new SystemMeasurement(value, unit)
);
}
return new Measurement(value, unit);
return new SystemMeasurement(value, unit);
};
}

Expand Down
32 changes: 32 additions & 0 deletions src/createMeasurement.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const Unit = require('./Unit');
const Measurement = require('./Measurement');
const UnitSystem = require('./UnitSystem');
const { divideBy } = require('./conversion');
const createMeasurement = require('./createMeasurement');

describe(createMeasurement, () => {
Expand Down Expand Up @@ -35,4 +36,35 @@ describe(createMeasurement, () => {
it('can be called as a tagged template with an inline unit', () => {
expect(m`12 ${inch}`).toEqual(new Measurement(12, inch));
});

it('can convert a measurement to a different unit using an alias', () => {
system.register(inch, { alias: 'inches' });
const foot = new Unit('foot');
system.register(foot, {
alias: 'feet',
convert: { from: [inch, divideBy(12)] },
});
expect(m`48 inches`.in.feet).toEqual(new Measurement(4, foot));
});

it('can convert a measurement by passing in the desired unit', () => {
system.register(inch, { alias: 'inches' });
const foot = new Unit('foot');
system.register(foot, {
convert: { from: [inch, divideBy(12)] },
});
expect(m`60 inches`.as(foot)).toEqual(new Measurement(5, foot));
});

it('can repeatedly implicitly convert', () => {
system.register(inch, { alias: 'inches' });
const foot = new Unit('foot');
system.register(foot, {
alias: 'feet',
convert: { from: [inch, divideBy(12)] },
});
expect(m`60 inches`.as(foot).in.inches.in.feet).toEqual(
new Measurement(5, foot)
);
});
});