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
To avoid data races, the internal `Registry` singleton has been removed, instead preferring an explicit user-defined `Registry`. For example, when parsing or querying units from Strings, a registry instance should be passed:
6
+
7
+
```swift
8
+
let meter =tryUnit(fromSymbol: "m") // old
9
+
let meter =tryUnit(fromSymbol: "m", registry: registry) // new
10
+
```
11
+
12
+
Note that if registry is omitted from these functions, the default unit database is used, which should provide a relatively smooth transition in the common case where custom units are not used.
13
+
14
+
## Registry builder
15
+
16
+
Registries should be defined and instantiated during startup, and must not be changed after creation. To enforce this lifecycle, a `RegistryBuilder` has been introduced that custom units may be registered to.
17
+
18
+
```swift
19
+
// old
20
+
let centifoot =try Unit.define(
21
+
name: "centifoot",
22
+
symbol: "cft",
23
+
dimension: [.Length:1],
24
+
coefficient: 0.003048
25
+
)
26
+
27
+
// new
28
+
let registryBuilder =RegistryBuilder()
29
+
registryBuilder.addUnit(
30
+
name: "centifoot",
31
+
symbol: "cft",
32
+
dimension: [.Length:1],
33
+
coefficient: 0.003048
34
+
)
35
+
let registry = registryBuilder.registry()
36
+
```
37
+
38
+
## Registry Encode/Decode support
39
+
40
+
To provide `Registry` lookup support inside `Encode`/`Decode` processes, a `userInfo` key has been added:
Copy file name to clipboardExpand all lines: README.md
+24-35Lines changed: 24 additions & 35 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -121,40 +121,57 @@ For a list of the default units and their conversion factors, see the [`DefaultU
121
121
122
122
## Custom Units
123
123
124
-
To extend this package, users can define their own custom units using `Unit.define`:
124
+
The unit system is backed by a `Registry` that maps unit symbols to their metadata. To add new units, use `RegistryBuilder`, and pass it to any operation that converts from a `String` to a `Unit`:
125
125
126
126
```swift
127
-
let centifoot =try Unit.define(
127
+
let registryBuilder =RegistryBuilder()
128
+
registryBuilder.addUnit(
128
129
name: "centifoot",
129
130
symbol: "cft",
130
131
dimension: [.Length:1],
131
132
coefficient: 0.003048// This is the conversion to meters
132
133
)
134
+
let registry = registryBuilder.registry()
135
+
let centifoot =tryUnit(fromSymbol: "cft", registry: registry)
133
136
134
137
let measurement =Measurement(value: 5, unit: centifoot)
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:
143
156
144
157
```swift
145
-
let apple =try Unit.define(
158
+
let registryBuilder =RegistryBuilder()
159
+
try registryBuilder.addUnit(
146
160
name: "apple",
147
161
symbol: "apple",
148
162
dimension: [.Amount:1],
149
163
coefficient: 1
150
164
)
151
-
152
-
let carton =try Unit.define(
165
+
try registryBuilder.addUnit(
153
166
name: "carton",
154
167
symbol: "carton",
155
168
dimension: [.Amount:1],
156
169
coefficient: 48
157
170
)
171
+
let registry = registryBuilder.registry()
172
+
173
+
let apple =tryUnit(fromSymbol: "apple", registry: registry)
174
+
let carton =tryUnit(fromSymbol: "carton", registry: registry)
158
175
159
176
let harvest =288.measured(in: apple)
160
177
print(harvest.convert(to: carton)) // Prints '6.0 carton'
@@ -163,48 +180,20 @@ print(harvest.convert(to: carton)) // Prints '6.0 carton'
163
180
We can extend this example to determine how many cartons a group of people can pick in a week:
164
181
165
182
```swift
166
-
let person =tryUnit.define(
183
+
tryregistryBuilder.addUnit(
167
184
name: "person",
168
185
symbol: "person",
169
186
dimension: [.Amount:1],
170
187
coefficient: 1
171
188
)
189
+
let person =tryUnit(fromSymbol: "person", registry: registryBuilder.registry())
172
190
173
191
let personPickRate =600.measured(in: apple / .day/ person)
174
192
let workforce =4.measured(in: person)
175
193
let weeklyCartons =try (workforce * personPickRate).convert(to: carton / .week)
176
194
print(weeklyCartons) // Prints '350.0 carton/week'
177
195
```
178
196
179
-
### Adding custom units to the Registry
180
-
181
-
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:)`
182
-
183
-
If these features are absolutely needed, and the implications are understood, custom units can be added to the registry using `Unit.register`:
184
-
185
-
```swift
186
-
let centifoot =try Unit.register(
187
-
name: "centifoot",
188
-
symbol: "cft",
189
-
dimension: [.Length:1],
190
-
coefficient: 0.003048// This is the conversion to meters
191
-
)
192
-
```
193
-
194
-
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)`.
195
-
196
-
To simplify access, `Unit` may be extended with a static property:
0 commit comments