-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from MFB-Technologies-Inc/feature/improve-decod…
…able-configuration Feature/improve decodable configuration
- Loading branch information
Showing
6 changed files
with
191 additions
and
10 deletions.
There are no files selected for viewing
55 changes: 55 additions & 0 deletions
55
Sources/ArgumentEncoding/DecoderUserInfo+OptionHelpers.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// DecoderUserInfo+OptionHelpers.swift | ||
// ArgumentEncoding | ||
// | ||
// Copyright © 2023 MFB Technologies, Inc. All rights reserved. | ||
|
||
import Foundation | ||
|
||
/// Helper functions for configuring a decoder's `userInfo` dictionary for decoding `Option`. | ||
/// Each of the overloads that does not require the configuration closure, will configure both | ||
/// `Option<T>` and `Option<T?>`. | ||
/// | ||
/// ```swift | ||
/// struct Container: ArgumentGroup, FormatterNode { | ||
/// let flagFormatter: FlagFormatter = .init(prefix: .doubleDash) | ||
/// let optionFormatter: OptionFormatter = .init(prefix: .doubleDash) | ||
/// @Option var option: String = "value" | ||
/// } | ||
/// let encoded = try JSONEncoder().encode(Container()) | ||
/// let decoder = JSONDecoder() | ||
/// decoder.userInfo.addOptionConfiguration(for: String.self) | ||
/// let decoded = try decoder.decode(Container.self, from: encoded) | ||
/// // decoded = ["--option", "value"] | ||
/// ``` | ||
extension [CodingUserInfoKey: Any] { | ||
public mutating func addOptionConfiguration<T>( | ||
for _: T.Type, | ||
configuration: @escaping Option<T>.DecodingConfiguration | ||
) where T: Decodable { | ||
guard let key = Option<T>.configurationCodingUserInfoKey() else { | ||
return | ||
} | ||
self[key] = configuration | ||
} | ||
|
||
public mutating func addOptionConfiguration<T>(for _: T.Type) where T: Decodable, | ||
T: CustomStringConvertible | ||
{ | ||
addOptionConfiguration(for: T.self, configuration: Option<T>.unwrap(_:)) | ||
addOptionConfiguration(for: T.self, configuration: Option<T?>.unwrap(_:)) | ||
} | ||
|
||
public mutating func addOptionConfiguration<T>(for _: T.Type) where T: Decodable, T: RawRepresentable, | ||
T.RawValue: CustomStringConvertible | ||
{ | ||
addOptionConfiguration(for: T.self, configuration: Option<T>.unwrap(_:)) | ||
addOptionConfiguration(for: T.self, configuration: { $0.rawValue.description }) | ||
} | ||
|
||
public mutating func addOptionConfiguration<T>(for _: T.Type) where T: Decodable, T: CustomStringConvertible, | ||
T: RawRepresentable, T.RawValue: CustomStringConvertible | ||
{ | ||
addOptionConfiguration(for: T.self, configuration: Option<T>.unwrap(_:)) | ||
addOptionConfiguration(for: T.self, configuration: Option<T?>.unwrap(_:)) | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
Sources/ArgumentEncoding/DecoderUserInfo+OptionSetHelpers.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// DecoderUserInfo+OptionSetHelpers.swift | ||
// ArgumentEncoding | ||
// | ||
// Copyright © 2023 MFB Technologies, Inc. All rights reserved. | ||
|
||
import Foundation | ||
|
||
/// Helper functions for configuring a decoder's `userInfo` dictionary for decoding `OptionSet`. | ||
/// Each of the overloads that does not require the configuration closure, will configure both | ||
/// `OptionSet<T>` and `OptionSet<T?>`. | ||
/// | ||
/// ```swift | ||
/// struct Container: ArgumentGroup, FormatterNode { | ||
/// let flagFormatter: FlagFormatter = .init(prefix: .doubleDash) | ||
/// let optionFormatter: OptionFormatter = .init(prefix: .doubleDash) | ||
/// @OptionSet var option: [String] = ["value1", "value2"] | ||
/// } | ||
/// let encoded = try JSONEncoder().encode(Container()) | ||
/// let decoder = JSONDecoder() | ||
/// decoder.userInfo.addOptionConfiguration(for: String.self) | ||
/// let decoded = try decoder.decode(Container.self, from: encoded) | ||
/// // decoded = ["--option", "value1", "--option", "value2"] | ||
/// ``` | ||
extension [CodingUserInfoKey: Any] { | ||
public mutating func addOptionSetConfiguration<T>( | ||
for _: OptionSet<T>.Type, | ||
configuration: @escaping OptionSet<T>.DecodingConfiguration | ||
) where T: Decodable { | ||
guard let key = OptionSet<T>.configurationCodingUserInfoKey() else { | ||
return | ||
} | ||
self[key] = configuration | ||
} | ||
|
||
public mutating func addOptionSetConfiguration<T>(for _: T.Type) where T: Decodable, T: Sequence, | ||
T.Element: CustomStringConvertible | ||
{ | ||
addOptionSetConfiguration(for: OptionSet<T>.self, configuration: OptionSet<T>.unwrap(_:)) | ||
} | ||
|
||
public mutating func addOptionSetConfiguration<T>(for _: T.Type) where T: Decodable, T: Sequence, | ||
T.Element: RawRepresentable, T.Element.RawValue: CustomStringConvertible | ||
{ | ||
addOptionSetConfiguration(for: OptionSet<T>.self, configuration: OptionSet<T>.unwrap(_:)) | ||
} | ||
|
||
public mutating func addOptionSetConfiguration<T>(for _: T.Type) where T: Decodable, T: Sequence, | ||
T.Element: CustomStringConvertible, T.Element: RawRepresentable, T.Element.RawValue: CustomStringConvertible | ||
{ | ||
addOptionSetConfiguration(for: OptionSet<T>.self, configuration: OptionSet<T>.unwrap(_:)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// OptionDecodingTests.swift | ||
// ArgumentEncoding | ||
// | ||
// Copyright © 2023 MFB Technologies, Inc. All rights reserved. | ||
|
||
import ArgumentEncoding | ||
import Foundation | ||
import XCTest | ||
|
||
final class OptionDecodingTests: XCTestCase { | ||
let encoder = JSONEncoder() | ||
|
||
func testDecodeOption() throws { | ||
let option = Option(wrappedValue: "value") | ||
let data = try encoder.encode(option) | ||
let decoder = JSONDecoder() | ||
decoder.userInfo.addOptionConfiguration(for: String.self) | ||
let decoded = try decoder.decode(Option<String>.self, from: data) | ||
XCTAssertEqual(decoded, option) | ||
} | ||
|
||
func testDecodeOptionContainer() throws { | ||
let container = OptionContainer(option: "value") | ||
let data = try encoder.encode(container) | ||
let decoder = JSONDecoder() | ||
decoder.userInfo.addOptionConfiguration(for: String.self) | ||
let decoded = try decoder.decode(OptionContainer.self, from: data) | ||
XCTAssertEqual(decoded, container) | ||
} | ||
} | ||
|
||
private struct OptionContainer: ArgumentGroup, Codable, Equatable { | ||
@Option var option: String | ||
|
||
init(option: String) { | ||
_option = Option(wrappedValue: option) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// OptionSetDecodingTests.swift | ||
// ArgumentEncoding | ||
// | ||
// Copyright © 2023 MFB Technologies, Inc. All rights reserved. | ||
|
||
import ArgumentEncoding | ||
import Foundation | ||
import XCTest | ||
|
||
final class OptionSetDecodingTests: XCTestCase { | ||
let encoder = JSONEncoder() | ||
|
||
func testDecodeOptionSet() throws { | ||
let optionSet = OptionSet(wrappedValue: ["value1", "value2"]) | ||
let data = try encoder.encode(optionSet) | ||
let decoder = JSONDecoder() | ||
decoder.userInfo.addOptionSetConfiguration(for: [String].self) | ||
let decoded = try decoder.decode(OptionSet<[String]>.self, from: data) | ||
XCTAssertEqual(decoded, optionSet) | ||
} | ||
|
||
func testDecodeOptionSetContainer() throws { | ||
let container = OptionSetContainer(option: ["value1", "value2"]) | ||
let data = try encoder.encode(container) | ||
let decoder = JSONDecoder() | ||
decoder.userInfo.addOptionSetConfiguration(for: [String].self) | ||
let decoded = try decoder.decode(OptionSetContainer.self, from: data) | ||
XCTAssertEqual(decoded, container) | ||
} | ||
} | ||
|
||
private struct OptionSetContainer: ArgumentGroup, Codable, Equatable { | ||
@OptionSet var option: [String] | ||
|
||
init(option: [String]) { | ||
_option = OptionSet(wrappedValue: option) | ||
} | ||
} |