Skip to content
This repository has been archived by the owner on Jul 21, 2020. It is now read-only.

Commit

Permalink
Implement web linking
Browse files Browse the repository at this point in the history
  • Loading branch information
devxoul committed Sep 13, 2019
1 parent df02053 commit 43d5d62
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 3 deletions.
12 changes: 12 additions & 0 deletions Drrrible.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
03E147691F2478860018D96D /* StubShotTileCellDependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E147681F2478860018D96D /* StubShotTileCellDependency.swift */; };
03E1DC7D1F42E890003E9F7A /* UICollectionView+TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E1DC7C1F42E890003E9F7A /* UICollectionView+TestUtils.swift */; };
03E1DC7F1F42FACC003E9F7A /* Matchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E1DC7E1F42FACC003E9F7A /* Matchers.swift */; };
03EC354E232BD076008202E6 /* Moya+RxSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03EC354D232BD076008202E6 /* Moya+RxSpec.swift */; };
03ED15691EEABA92006E1638 /* AnalyticsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03ED15681EEABA92006E1638 /* AnalyticsEvent.swift */; };
03EE6F791F250B0600C2C6D8 /* UIGestureRecognizer+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03EE6F781F250B0600C2C6D8 /* UIGestureRecognizer+Test.swift */; };
03EF17891F9292130042C431 /* StubNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03EF17881F9292130042C431 /* StubNavigator.swift */; };
Expand Down Expand Up @@ -271,6 +272,7 @@
03E147681F2478860018D96D /* StubShotTileCellDependency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StubShotTileCellDependency.swift; sourceTree = "<group>"; };
03E1DC7C1F42E890003E9F7A /* UICollectionView+TestUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UICollectionView+TestUtils.swift"; sourceTree = "<group>"; };
03E1DC7E1F42FACC003E9F7A /* Matchers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matchers.swift; sourceTree = "<group>"; };
03EC354D232BD076008202E6 /* Moya+RxSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Moya+RxSpec.swift"; sourceTree = "<group>"; };
03ED15681EEABA92006E1638 /* AnalyticsEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsEvent.swift; sourceTree = "<group>"; };
03EE6F781F250B0600C2C6D8 /* UIGestureRecognizer+Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Test.swift"; sourceTree = "<group>"; };
03EF17881F9292130042C431 /* StubNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubNavigator.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -395,6 +397,7 @@
03D996E81E811BAB004773AE /* Sources */ = {
isa = PBXGroup;
children = (
03EC354C232BD067008202E6 /* Rx */,
031F92851EA55FA00025D5FB /* TestMain.swift */,
034D335B1EA69C95004498FB /* TestConfiguration.swift */,
03D9971F1E817C13004773AE /* Fixtures */,
Expand Down Expand Up @@ -666,6 +669,14 @@
path = Views;
sourceTree = "<group>";
};
03EC354C232BD067008202E6 /* Rx */ = {
isa = PBXGroup;
children = (
03EC354D232BD076008202E6 /* Moya+RxSpec.swift */,
);
path = Rx;
sourceTree = "<group>";
};
03ED15671EEABA86006E1638 /* Analytics */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1114,6 +1125,7 @@
036CDD751F235EB4006C91CC /* SplashViewControllerSpec.swift in Sources */,
03D997291E819012004773AE /* ShotListViewReactorSpec.swift in Sources */,
036CDD931F239A02006C91CC /* StubShotService.swift in Sources */,
03EC354E232BD076008202E6 /* Moya+RxSpec.swift in Sources */,
037142591F64F0010055F0C1 /* StubShotViewImageCellDependency.swift in Sources */,
034D832F1F246BD700975F2F /* StubImageDownloader.swift in Sources */,
0303CACC1F43267B00FF2E77 /* ShotViewControllerSpec.swift in Sources */,
Expand Down
33 changes: 30 additions & 3 deletions Drrrible/Sources/Rx/Moya+Rx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ extension PrimitiveSequence where Trait == SingleTrait, Element == Moya.Response
return self
.map { response -> List<T> in
let items = try response.map([T].self, using: T.decoder)
let nextURL = response.response?
.findLink(relation: "next")
.flatMap { URL(string: $0.uri) }
let nextURL = Self.findNextURL(response: response)
return List<T>(items: items, nextURL: nextURL)
}
.do(onError: { error in
Expand All @@ -29,6 +27,35 @@ extension PrimitiveSequence where Trait == SingleTrait, Element == Moya.Response
}
})
}

private static func findNextURL(response: Moya.Response) -> URL? {
guard let linkString = response.response?.allHeaderFields["Link"] as? String else { return nil }
return self.links(from: linkString)
.first { url, relation in relation == "next" }
.map { url, relation in url }
}

private static func links(from linkString: String) -> [(url: URL, relation: String)] {
return linkString
.components(separatedBy: ",")
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.compactMap { part in
guard let urlString = self.firstMatch(in: part, pattern: "^<(.*)>") else { return nil }
guard let url = URL(string: urlString) else { return nil }
guard let relation = self.firstMatch(in: part, pattern: "rel=\"(.*)\"") else { return nil }
return (url: url, relation: relation)
}
}

private static func firstMatch(in string: String, pattern: String) -> String? {
guard let regex = try? NSRegularExpression(pattern: pattern) else { return nil }

let nsString = string as NSString
let range = NSMakeRange(0, nsString.length)

guard let result = regex.firstMatch(in: string, range: range) else { return nil }
return nsString.substring(with: result.range(at: 1))
}
}

// TODO: Temporary implementation
Expand Down
44 changes: 44 additions & 0 deletions DrrribleTests/Sources/Rx/Moya+RxSpec.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// Moya+RxSpec.swift
// DrrribleTests
//
// Created by Suyeol Jeon on 13/09/2019.
// Copyright © 2019 Suyeol Jeon. All rights reserved.
//

import Moya
import Nimble
import Quick
import RxSwift
@testable import Drrrible

final class Moya_RxSpec: QuickSpec {
override func spec() {
it("parses next url from Link header") {
// given
let disposeBag = DisposeBag()

// when
let url = URL(string: "https://example.com/page/2")!
let headers = [
"Link": "<https://example.com/page/1>; rel=\"prev\", <https://example.com/page/3>; rel=\"next\""
]
let data = "[{}, {}, {}]".data(using: .utf8)!
let urlResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: headers)
let moyaResponse = Moya.Response(statusCode: 200, data: data, request: nil, response: urlResponse)

var receivedList: List<DummyMode>?
Single.just(moyaResponse)
.map(List<DummyMode>.self)
.subscribe(onSuccess: { receivedList = $0 })
.disposed(by: disposeBag)

// then
expect(receivedList?.nextURL?.absoluteString) == "https://example.com/page/3"
}
}
}

private struct DummyMode: ModelType {
typealias Event = Never
}

0 comments on commit 43d5d62

Please sign in to comment.