Skip to content

Commit 7086c41

Browse files
authored
doc: improved usage documentation (#5)
- added minimal usage example in README - added API availability data
1 parent 323a94a commit 7086c41

File tree

7 files changed

+159
-28
lines changed

7 files changed

+159
-28
lines changed

README.md

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ Supercharge `Swift`'s `Codable` implementations with macros.
3535

3636
## Installation
3737

38-
### Swift Package Manager
38+
<details>
39+
<summary><h3>Swift Package Manager</h3></summary>
3940

4041
The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler.
4142

@@ -50,10 +51,132 @@ Then you can add the `MetaCodable` module product as dependency to the `target`s
5051
```swift
5152
.product(name: "MetaCodable", package: "MetaCodable"),
5253
```
54+
</details>
5355

5456
## Usage
5557

56-
See the full [documentation](https://swiftylab.github.io/MetaCodable/documentation/metacodable/) for API details and articles on sample scenarios.
58+
`MetaCodable` allows to get rid of boiler plate that was often needed in some typical `Codable` implementations with features like:
59+
60+
<details>
61+
<summary>Custom `CodingKey` value declaration per variable, instead of requiring you to write for all fields.</summary>
62+
63+
i.e. in the official [docs](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types#2904057), to define custom `CodingKey` for 2 fields of `Landmark` type you had to write:
64+
```swift
65+
struct Landmark: Codable {
66+
var name: String
67+
var foundingYear: Int
68+
var location: Coordinate
69+
var vantagePoints: [Coordinate]
70+
71+
enum CodingKeys: String, CodingKey {
72+
case name = "title"
73+
case foundingYear = "founding_date"
74+
case location
75+
case vantagePoints
76+
}
77+
}
78+
```
79+
But with `MetaCodable` all you have to write is this:
80+
```swift
81+
@Codable
82+
struct Landmark {
83+
@CodablePath("title")
84+
var name: String
85+
@CodablePath("founding_date")
86+
var foundingYear: Int
87+
88+
var location: Coordinate
89+
var vantagePoints: [Coordinate]
90+
}
91+
```
92+
</details>
93+
94+
<details>
95+
<summary>Create flattened model for nested `CodingKey` values.</summary>
96+
97+
i.e. in official [docs](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types#2904058) to decode a JSON like this:
98+
```json
99+
{
100+
"latitude": 0,
101+
"longitude": 0,
102+
"additionalInfo": {
103+
"elevation": 0
104+
}
105+
}
106+
```
107+
You had to write all these boilerplate:
108+
```swift
109+
struct Coordinate {
110+
var latitude: Double
111+
var longitude: Double
112+
var elevation: Double
113+
114+
enum CodingKeys: String, CodingKey {
115+
case latitude
116+
case longitude
117+
case additionalInfo
118+
}
119+
120+
enum AdditionalInfoKeys: String, CodingKey {
121+
case elevation
122+
}
123+
}
124+
125+
extension Coordinate: Decodable {
126+
init(from decoder: Decoder) throws {
127+
let values = try decoder.container(keyedBy: CodingKeys.self)
128+
latitude = try values.decode(Double.self, forKey: .latitude)
129+
longitude = try values.decode(Double.self, forKey: .longitude)
130+
131+
let additionalInfo = try values.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
132+
elevation = try additionalInfo.decode(Double.self, forKey: .elevation)
133+
}
134+
}
135+
136+
extension Coordinate: Encodable {
137+
func encode(to encoder: Encoder) throws {
138+
var container = encoder.container(keyedBy: CodingKeys.self)
139+
try container.encode(latitude, forKey: .latitude)
140+
try container.encode(longitude, forKey: .longitude)
141+
142+
var additionalInfo = container.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
143+
try additionalInfo.encode(elevation, forKey: .elevation)
144+
}
145+
}
146+
```
147+
But with `MetaCodable` all you have to write is this:
148+
```swift
149+
@Codable
150+
struct Coordinate {
151+
var latitude: Double
152+
var longitude: Double
153+
154+
@CodablePath("additionalInfo", "elevation")
155+
var elevation: Double
156+
}
157+
```
158+
</details>
159+
160+
<details>
161+
<summary>Provide default value in case of decoding failures and member-wise initializer generated considers these default values.</summary>
162+
163+
Instead of throwing error in case of missing data or type mismatch, you can provide a default value that will be assigned in this case. The memberwise initializer generated also uses this default value for the field. The following definition with `MetaCodable`:
164+
```swift
165+
@Codable
166+
struct CodableData {
167+
@CodablePath(default: "some")
168+
let field: String
169+
}
170+
```
171+
will not throw any error when empty JSON(`{}`) or JSON with type mismatch(`{ "field": 5 }`) is provided. The default value will be assigned in such case. Also, the memberwise initializer generated will look like this:
172+
```swift
173+
init(field: String = "some") {
174+
self.field = field
175+
}
176+
```
177+
</details>
178+
179+
See the full [documentation](https://swiftylab.github.io/MetaCodable/documentation/metacodable/) for API details and advanced use cases.
57180

58181
## Contributing
59182

Sources/CodableMacroPlugin/CodableFieldMacro.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import SwiftSyntaxMacros
1313
/// to remove it.
1414
struct CodableFieldMacro: PeerMacro {
1515
/// The name of macro that allows `CodingKey`
16-
/// path customizations
16+
/// path customizations.
1717
static var path: String { "CodablePath" }
1818
/// The name of macro that allows
19-
/// composition of decoding/encoding
19+
/// composition of decoding/encoding.
2020
static var compose: String { "CodableCompose" }
2121

2222
/// Argument label used to provide a default value

Sources/MetaCodable/Codable.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
/// - Important: The attached declaration must be of a struct type.
3232
@attached(member, names: named(CodingKeys), named(init(from:)), named(encode(to:)), arbitrary)
3333
@attached(conformance)
34+
@available(swift 5.9)
3435
public macro Codable() = #externalMacro(
3536
module: "CodableMacroPlugin",
3637
type: "CodableMacro"

Sources/MetaCodable/CodableCompose.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
///
6161
/// - Important: The field type must confirm to `Codable`.
6262
@attached(peer)
63+
@available(swift 5.9)
6364
public macro CodableCompose() = #externalMacro(
6465
module: "CodableMacroPlugin",
6566
type: "CodableFieldMacro"
@@ -90,6 +91,7 @@ public macro CodableCompose() = #externalMacro(
9091
/// default value type `T` must be the same as
9192
/// field type.
9293
@attached(peer)
94+
@available(swift 5.9)
9395
public macro CodableCompose<T>(
9496
default: T
9597
) = #externalMacro(module: "CodableMacroPlugin", type: "CodableFieldMacro")
@@ -114,6 +116,7 @@ public macro CodableCompose<T>(
114116
/// - Important: The `helper`'s `T.Coded` associated type
115117
/// must be the same as field type.
116118
@attached(peer)
119+
@available(swift 5.9)
117120
public macro CodableCompose<T: ExternalHelperCoder>(
118121
helper: T
119122
) = #externalMacro(module: "CodableMacroPlugin", type: "CodableFieldMacro")
@@ -145,6 +148,7 @@ public macro CodableCompose<T: ExternalHelperCoder>(
145148
/// - Important: The `helper`'s `T.Coded` associated type
146149
/// must be the same as field type.
147150
@attached(peer)
151+
@available(swift 5.9)
148152
public macro CodableCompose<T: ExternalHelperCoder>(
149153
default: T.Coded,
150154
helper: T

Sources/MetaCodable/CodablePath.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
///
3737
/// - Important: The field type must confirm to `Codable`.
3838
@attached(peer)
39+
@available(swift 5.9)
3940
public macro CodablePath(
4041
_ path: StaticString...
4142
) = #externalMacro(
@@ -77,6 +78,7 @@ public macro CodablePath(
7778
/// default value type `T` must be the same as
7879
/// field type.
7980
@attached(peer)
81+
@available(swift 5.9)
8082
public macro CodablePath<T>(
8183
default: T,
8284
_ path: StaticString...
@@ -105,6 +107,7 @@ public macro CodablePath<T>(
105107
/// - Important: The `helper`'s `T.Coded` associated type
106108
/// must be the same as field type.
107109
@attached(peer)
110+
@available(swift 5.9)
108111
public macro CodablePath<T: ExternalHelperCoder>(
109112
helper: T,
110113
_ path: StaticString...
@@ -133,6 +136,7 @@ public macro CodablePath<T: ExternalHelperCoder>(
133136
/// - Important: The `helper`'s `T.Coded` associated type
134137
/// must be the same as field type.
135138
@attached(peer)
139+
@available(swift 5.9)
136140
public macro CodablePath<T: ExternalHelperCoder>(
137141
default: T.Coded,
138142
helper: T,

Sources/MetaCodable/ExternalHelperCoder/ExternalHelperCoder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/// decoding/encoding customizations or to provide decoding/encoding
77
/// to non-`Codable` types.
88
///
9-
/// - Tip: Use this type to refactor scenarios where `prpertyWraaper`s
9+
/// - Tip: Use this type to refactor scenarios where `propertyWraaper`s
1010
/// were used to have custom decoding/encoding functionality.
1111
public protocol ExternalHelperCoder {
1212
/// The actual type of value that is going to be decoded/encoded.

Sources/MetaCodable/MetaCodable.docc/MetaCodable.md

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# ``MetaCodable``
22

3+
@Metadata {
4+
@Available(swift, introduced: "5.9")
5+
}
6+
37
Supercharge `Swift`'s `Codable` implementations with macros.
48

59
## Overview
@@ -16,31 +20,26 @@ Supercharge `Swift`'s `Codable` implementations with macros.
1620
- Generates member-wise initializer considering the above default value syntax as well.
1721
- Allows to create custom decoding/encoding strategies with ``ExternalHelperCoder``. i.e. ``LossySequenceCoder`` etc.
1822

19-
## Requirements
20-
21-
| Platform | Minimum Swift Version | Installation | Status |
22-
| --- | --- | --- | --- |
23-
| iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+ | 5.9 | Swift Package Manager | Fully Tested |
24-
| Linux | 5.9 | Swift Package Manager | Fully Tested |
25-
| Windows | 5.9 | Swift Package Manager | Fully Tested |
26-
2723
## Installation
2824

29-
### Swift Package Manager
30-
31-
The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler.
32-
33-
Once you have your Swift package set up, adding `MetaCodable` as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.
34-
35-
```swift
36-
.package(url: "https://github.com/SwiftyLab/MetaCodable.git", from: "1.0.0"),
37-
```
38-
39-
Then you can add the `MetaCodable` module product as dependency to the `target`s of your choosing, by adding it to the `dependencies` value of your `target`s.
40-
41-
```swift
42-
.product(name: "MetaCodable", package: "MetaCodable"),
43-
```
25+
@TabNavigator {
26+
@Tab("Swift Package Manager") {
27+
28+
The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler.
29+
30+
Once you have your Swift package set up, adding `MetaCodable` as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.
31+
32+
```swift
33+
.package(url: "https://github.com/SwiftyLab/MetaCodable.git", from: "1.0.0"),
34+
```
35+
36+
Then you can add the `MetaCodable` module product as dependency to the `target`s of your choosing, by adding it to the `dependencies` value of your `target`s.
37+
38+
```swift
39+
.product(name: "MetaCodable", package: "MetaCodable"),
40+
```
41+
}
42+
}
4443

4544
## Topics
4645

0 commit comments

Comments
 (0)