You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+18-51Lines changed: 18 additions & 51 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,12 +1,8 @@
1
1
# Units 📏
2
2
3
-
Units is a Swift package to manipulate, compare, and convert between physical quantities. This package models measurements,
4
-
which are a numerical value with a unit of measure. It has been designed so that users don't need to worry whether they are
5
-
using a defined unit (like `Newton`) or a complex composite unit (like `kg*m/s^2`). Both should be easy to convert to and from
6
-
different units, perform arithmetic operations, check dimensionality, or serialize to and from a string format.
3
+
Units is a Swift package to manipulate, compare, and convert between physical quantities. This package models measurements, which are a numerical value with a unit of measure. It has been designed so that users don't need to worry whether they are using a defined unit (like `Newton`) or a complex composite unit (like `kg*m/s^2`). Both should be easy to convert to and from different units, perform arithmetic operations, check dimensionality, or serialize to and from a string format.
7
4
8
-
This approach allows us to easily handle any permutation of units. You want to convert `12 km³/hr/N` to
9
-
`ft²*s/lb`? We've got you covered!
5
+
This approach allows us to easily handle any permutation of units. You want to convert `12 km³/hr/N` to `ft²*s/lb`? We've got you covered!
10
6
11
7
Included is a convenient command-line tool for performing quick unit conversions. See the [CLI section](#cli) for details.
12
8
@@ -36,9 +32,7 @@ print(drivingDistance.convert(to: .mile)) // Prints 30 mi
36
32
37
33
Note that a measurement may be multiplied or divided by another measurement with any unit, resulting in a measurement that has a new-dimensioned unit (5 meters / 10 seconds ✅). However, addition and subtraction requires that both measurements have the same dimensionality (5 meters - 10 seconds ❌), otherwise a runtime error is thrown. If adding or subtracting two measurements with different units but the same dimensionality, the result retains the first measurement's unit (5 meters - 5 millimeters = 4.995 meters).
38
34
39
-
The type names in this package align closely with the unit system provided by `Foundation`. This was intentional to provide a
40
-
familiar nomenclature for Swift developers. The APIs have been designed to avoid namespace ambiguity in files where both `Units`
41
-
and `Foundation` are imported as much as possible. However, if an issue arises, just qualify the desired package like so:
35
+
The type names in this package align closely with the unit system provided by `Foundation`. This was intentional to provide a familiar nomenclature for Swift developers. The APIs have been designed to avoid namespace ambiguity in files where both `Units` and `Foundation` are imported as much as possible. However, if an issue arises, just qualify the desired package like so:
42
36
43
37
```swift
44
38
let measurement = Units.Measurement(value: 5, unit: .mile)
@@ -74,41 +68,25 @@ print(distance) // Prints '15 m/s'
74
68
75
69
## Conversion
76
70
77
-
Only linear conversions are supported. The vast majority of unit conversions are simply changes in scale, represented by a single
78
-
conversion coefficient, sometimes with a constant shift. Units that don't match this format (like currency conversions, which are
79
-
typically time-based functions) are not supported.
71
+
Only linear conversions are supported. The vast majority of unit conversions are simply changes in scale, represented by a single conversion coefficient, sometimes with a constant shift. Units that don't match this format (like currency conversions, which are typically time-based functions) are not supported.
80
72
81
-
Composite units are those that represent complex quantities and dimensions. A good example is `horsepower`, whose quantity is
82
-
`mass * length^2 / time^2`.
73
+
Composite units are those that represent complex quantities and dimensions. A good example is `horsepower`, whose quantity is `mass * length^2 / time^2`.
83
74
84
75
### Coefficients
85
76
86
-
Each quantity has a single "base unit", through which the units of that quantity may be converted. SI units have been
87
-
chosen to be these base units for all quantities.
77
+
Each quantity has a single "base unit", through which the units of that quantity may be converted. SI units have been chosen to be these base units for all quantities.
88
78
89
-
Non-base units require a conversion coefficient to convert between them and other units of the same dimension. This coefficient
90
-
is the number of base units there are in one of the defined unit. For example, `kilometer` has a coefficient of `1000`
91
-
because there are 1000 meters in 1 kilometer.
79
+
Non-base units require a conversion coefficient to convert between them and other units of the same dimension. This coefficient is the number of base units there are in one of the defined unit. For example, `kilometer` has a coefficient of `1000` because there are 1000 meters in 1 kilometer.
92
80
93
-
Composite units must have a coefficient that converts to the composte SI units of those dimensions. That is, `horsepower` should
94
-
have a conversion to `kilogram * meter^2 / second^2` (otherwise known as `watt`). This is natural for SI quantities and units, but
95
-
care should be taken that a single, absolute base unit is chosen for all non-SI quantities since they will impact all composite
96
-
conversions.
81
+
Composite units must have a coefficient that converts to the composte SI units of those dimensions. That is, `horsepower` should have a conversion to `kilogram * meter^2 / second^2` (otherwise known as `watt`). This is natural for SI quantities and units, but care should be taken that a single, absolute base unit is chosen for all non-SI quantities since they will impact all composite conversions.
97
82
98
83
### Constants
99
84
100
-
Units that include a constant value, such as Fahrenheit, cannot be used within composite unit conversions. For example,
101
-
you may not convert `5m/°F` to `m/°C` because its unclear how to handle their shifted scale. Instead use the
102
-
non-shifted Kelvin and Rankine temperature units to refer to temperature differentials.
85
+
Units that include a constant value, such as Fahrenheit, cannot be used within composite unit conversions. For example, you may not convert `5m/°F` to `m/°C` because its unclear how to handle their shifted scale. Instead use the non-shifted Kelvin and Rankine temperature units to refer to temperature differentials.
103
86
104
87
## Serialization
105
88
106
-
Each defined unit must have a unique symbol, which is used to identify and serialize/deserialize it. Defined unit symbols are not
107
-
allowed to contain the `*`, `/`, `^`, or `` characters because those are used in the symbol representation of complex units.
108
-
Complex units are represented by their arithmetic combination of simple units using `*` for multiplication, `/` for division,
109
-
and `^` for exponentiation. Order of operations treats exponentiation first, and multiplication and division equally, from left-
110
-
to-right. This means that, unless negatively exponentiated, units following a `*` can always be considered to be "in the numerator",
111
-
and those following `/` can always be considered to be "in the denominator".
89
+
Each defined unit must have a unique symbol, which is used to identify and serialize/deserialize it. Defined unit symbols are not allowed to contain the `*`, `/`, `^`, or `` characters because those are used in the symbol representation of complex units. Complex units are represented by their arithmetic combination of simple units using `*` for multiplication, `/` for division, and `^` for exponentiation. Order of operations treats exponentiation first, and multiplication and division equally, from left-to-right. This means that, unless negatively exponentiated, units following a `*` can always be considered to be "in the numerator", and those following `/` can always be considered to be "in the denominator".
112
90
113
91
Here are a few examples:
114
92
@@ -136,8 +114,7 @@ There are few expression parsing rules to keep in mind:
136
114
137
115
## Default Units
138
116
139
-
For a list of the default units and their conversion factors, see the
For a list of the default units and their conversion factors, see the [`DefaultUnits.swift file`](https://github.com/NeedleInAJayStack/Units/blob/main/Sources/Units/Unit/DefaultUnits.swift)
141
118
142
119
## Custom Units
143
120
@@ -159,8 +136,7 @@ This returns a Unit object that can be used in arithmetic, conversions, and seri
159
136
160
137
### Non-scientific Units
161
138
162
-
For "non-scientific" units, it is typically appropriate to use the `Amount` quantity. Through this
163
-
approach, you can easily build up an impromptu conversion system on the fly. For example:
139
+
For "non-scientific" units, it is typically appropriate to use the `Amount` quantity. Through this approach, you can easily build up an impromptu conversion system on the fly. For example:
164
140
165
141
```swift
166
142
let apple =try Unit.define(
@@ -199,13 +175,9 @@ print(weeklyCartons) // Prints '350.0 carton/week'
199
175
200
176
### Adding custom units to the Registry
201
177
202
-
To support deserialization and runtime querying of available units, this package keeps a global
203
-
registry of the default units. The `Unit.define` method does not insert new definitions into this
204
-
registry. While this avoids conflicts and prevents race conditions, it also means that units created
205
-
using `Unit.define` cannot be deserialized correctly or looked up using `Unit(fromSymbol:)`
178
+
To support deserialization and runtime querying of available units, this package keeps a global registry of the default units. The `Unit.define` method does not insert new definitions into this registry. While this avoids conflicts and prevents race conditions, it also means that units created using `Unit.define` cannot be deserialized correctly or looked up using `Unit(fromSymbol:)`
206
179
207
-
If these features are absolutely needed, and the implications are understood, custom units can be
208
-
added to the registry using `Unit.register`:
180
+
If these features are absolutely needed, and the implications are understood, custom units can be added to the registry using `Unit.register`:
209
181
210
182
```swift
211
183
let centifoot =try Unit.register(
@@ -216,8 +188,7 @@ let centifoot = try Unit.register(
216
188
)
217
189
```
218
190
219
-
Note that you may only register the unit once globally, and afterwards it should be accessed
220
-
either by the assigned variable or using `Unit(fromSymbol: String)`.
191
+
Note that you may only register the unit once globally, and afterwards it should be accessed either by the assigned variable or using `Unit(fromSymbol: String)`.
221
192
222
193
To simplify access, `Unit` may be extended with a static property:
223
194
@@ -240,8 +211,7 @@ brew tap NeedleInAJayStack/tap
240
211
brew install units
241
212
```
242
213
243
-
Alternatively, you can build it from source and install it to `/usr/local/bin/` using the install script. Note that
244
-
[swift](https://www.swift.org/download/) must be installed, and you need write permissions to `/usr/local/bin/`.
214
+
Alternatively, you can build it from source and install it to `/usr/local/bin/` using the install script. Note that [swift](https://www.swift.org/download/) must be installed, and you need write permissions to `/usr/local/bin/`.
245
215
246
216
```bash
247
217
./install.sh
@@ -261,9 +231,7 @@ You can then perform unit conversions using the `unit convert` command:
261
231
unit convert 5m/s mi/hr # Returns 11.184681460272012 mi/hr
262
232
```
263
233
264
-
This command uses the unit and expression [serialization format](#serialization). Note that for
265
-
convenience, you may use an underscore `_` to represent the normally serialized space. Also,
266
-
`*` characters may need to be escaped.
234
+
This command uses the unit and expression [serialization format](#serialization). Note that for convenience, you may use an underscore `_` to represent the normally serialized space. Also, `*` characters may need to be escaped.
267
235
268
236
You can also evaulate math in the first argument. For example:
269
237
@@ -281,5 +249,4 @@ unit list
281
249
282
250
## Contributing
283
251
284
-
Contributions are absolutely welcome! If you find yourself using a custom unit a lot, feel free
285
-
to stick it in an MR, and we can add it to the default list!
252
+
Contributions are absolutely welcome! If you find yourself using a custom unit a lot, feel free to stick it in an MR, and we can add it to the default list!
0 commit comments