Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conditionally conform to Combine.TopLevelDecoder #132

Merged
merged 7 commits into from Oct 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
MaxDesiatov marked this conversation as resolved.
Show resolved Hide resolved
.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, *)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the solution would be to remove macOS 10.15.0 clause until that's released? We would avoid crashing on CI until then too. After all I wouldn't mind tagging a minor release just for enabling that later when Catalina is released and available on CI.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing macOS from the availability annotation would instead result in a compiler error. The issue is that we successfully compile & link, but then attempt to run the tests on a platform where the framework doesn't exist and instead crash when the symbol can't be loaded.

If we want to exclude the test from macOS altogether, we could add #if !os(macOS) to the compiler directive at the top of the file. The tests won't be exercised on CI then, so it might still make sense to add a CI job that runs on Xcode 11 + iOS?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Xcode 11 job already tests on macOS, iOS and tvOS, so that should be fine.

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