Skip to content

Commit

Permalink
Conditionally conform to Combine.TopLevelDecoder (#132)
Browse files Browse the repository at this point in the history
This enables use of `XMLDecoder` with Combine's `decode(_:decoder:)` operator by conditionally conforming to `TopLevelDecoder` when Combine is available.

I explored doing the same for `TopLevelEncoder`, but `XMLEncoder` currently requires `rootKey:` to be specified at encoding time, so it's not possible to provide an implementation of `encode(_:)` without some design around how to dynamically determine the root key to use.

* Conditionally conform to Combine.TopLevelDecoder
* Add test and documentation for Combine integration
* Remove macCatalyst from CombineTests
This shouldn't be necessary because all versions of Mac Catalyst should
have a version of Combine available.
* Add CombineTests to the Xcode project
* Disable CombineTests on macOS
  • Loading branch information
sharplet authored and MaxDesiatov committed Oct 4, 2019
1 parent 149aafe commit c4b78cb
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 0 deletions.
19 changes: 19 additions & 0 deletions README.md
Expand Up @@ -269,6 +269,25 @@ extension IntOrString: Codable {
This is described in more details in PR [\#119](https://github.com/MaxDesiatov/XMLCoder/pull/119)
by [@jsbean](https://github.com/jsbean) and [@bwetherfield](https://github.com/bwetherfield).

## Integrating with [Combine](https://developer.apple.com/documentation/combine)

When Apple's Combine framework is available, `XMLDecoder` conforms to the
`TopLevelDecoder` protocol, which allows it to be used with the
`decode(type:decoder:)` operator:

```swift
import Combine
import Foundation
import XMLCoder

func fetchBook(from url: URL) -> AnyPublisher<Book, Error> {
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.decode(type: Book.self, decoder: XMLDecoder())
.eraseToAnyPublisher()
}
```

## Installation

### Requirements
Expand Down
8 changes: 8 additions & 0 deletions Sources/XMLCoder/Decoder/XMLDecoder.swift
Expand Up @@ -368,3 +368,11 @@ open class XMLDecoder {
return try decoder.unbox(topLevel)
}
}

// MARK: TopLevelDecoder

#if canImport(Combine)
import protocol Combine.TopLevelDecoder

extension XMLDecoder: TopLevelDecoder {}
#endif
37 changes: 37 additions & 0 deletions Tests/XMLCoderTests/CombineTests.swift
@@ -0,0 +1,37 @@
//
// CombineTests.swift
// XMLCoder
//
// Created by Adam Sharp on 9/29/19.
//

#if canImport(Combine) && !os(macOS)
import Combine
import Foundation
import XCTest
import XMLCoder

private let xml = """
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<name>Foo</name>
</foo>
""".data(using: .utf8)!

private struct Foo: Decodable {
var name: String
}

@available(iOS 13.0, macOS 10.15.0, tvOS 13.0, watchOS 6.0, *)
class CombineTests: XCTestCase {
func testDecodeFromXMLDecoder() {
let data = Just(xml)
var foo: Foo?
_ = data.decode(type: Foo.self, decoder: XMLDecoder()).sink(
receiveCompletion: { _ in },
receiveValue: { foo = $0 }
)
XCTAssertEqual(foo?.name, "Foo")
}
}
#endif
4 changes: 4 additions & 0 deletions XMLCoder.xcodeproj/project.pbxproj
Expand Up @@ -21,6 +21,7 @@
/* End PBXAggregateTarget section */

/* Begin PBXBuildFile section */
4A062D4F2341924E009BCAC1 /* CombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A062D4E2341924E009BCAC1 /* CombineTests.swift */; };
B5EA3BB6230F237800D8D69B /* NestedChoiceArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */; };
B5F74472233F74E400BBDB15 /* RootLevelAttributeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */; };
OBJ_148 /* BoolBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* BoolBox.swift */; };
Expand Down Expand Up @@ -154,6 +155,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
4A062D4E2341924E009BCAC1 /* CombineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombineTests.swift; sourceTree = "<group>"; };
B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedChoiceArrayTest.swift; sourceTree = "<group>"; };
B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootLevelAttributeTest.swift; sourceTree = "<group>"; };
OBJ_100 /* DecimalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecimalTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -428,6 +430,7 @@
OBJ_86 /* CDCatalog.swift */,
OBJ_87 /* CDTest.swift */,
OBJ_88 /* ClassTests.swift */,
4A062D4E2341924E009BCAC1 /* CombineTests.swift */,
OBJ_89 /* CompositeChoiceTests.swift */,
OBJ_90 /* DecodingContainerTests.swift */,
OBJ_91 /* DynamicNodeDecodingTest.swift */,
Expand Down Expand Up @@ -742,6 +745,7 @@
OBJ_269 /* RJITest.swift in Sources */,
OBJ_270 /* RelationshipsTest.swift in Sources */,
OBJ_271 /* SimpleChoiceTests.swift in Sources */,
4A062D4F2341924E009BCAC1 /* CombineTests.swift in Sources */,
OBJ_272 /* SingleChildTests.swift in Sources */,
OBJ_273 /* SpacePreserveTest.swift in Sources */,
);
Expand Down

0 comments on commit c4b78cb

Please sign in to comment.