From e77f61309ee38940c9845802754b4cf945eb9a59 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 00:50:15 +0200 Subject: [PATCH 01/13] Add payload to location --- Sources/Location.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/Location.swift b/Sources/Location.swift index 5f26382..77bb213 100644 --- a/Sources/Location.swift +++ b/Sources/Location.swift @@ -3,14 +3,19 @@ public struct Location { public let path: String public let arguments: [String: String] public let fragments: [String: AnyObject] + public let payload: Any? public var scheme: String { return Compass.scheme } - public init(path: String, arguments: [String: String] = [:], fragments: [String: AnyObject] = [:]) { + public init(path: String, + arguments: [String: String] = [:], + fragments: [String: AnyObject] = [:], + payload: Any? = nil) { self.path = path self.arguments = arguments self.fragments = fragments + self.payload = payload } } From 000f4b6d28a2dffeaed5c74da381ae7f6810e7a0 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 00:52:49 +0200 Subject: [PATCH 02/13] Add payload to parse --- Sources/Compass.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Compass.swift b/Sources/Compass.swift index 256973d..983126b 100644 --- a/Sources/Compass.swift +++ b/Sources/Compass.swift @@ -18,11 +18,11 @@ public struct Compass { public static var routes = [String]() - public static func parse(url: NSURL, fragments: [String : AnyObject] = [:]) -> Location? { + public static func parse(url: NSURL, fragments: [String : AnyObject] = [:], payload: Any? = nil) -> Location? { let path = url.absoluteString.substringFromIndex(scheme.endIndex) guard !(path.containsString("?") || path.containsString("#")) else { - return parseAsURL(url, fragments: fragments) + return parseAsURL(url, fragments: fragments, payload: payload) } let results: [Result] = routes.flatMap { @@ -36,13 +36,13 @@ public struct Compass { } if let result = results.first { - return Location(path: result.route, arguments: result.arguments, fragments: fragments) + return Location(path: result.route, arguments: result.arguments, fragments: fragments, payload: payload) } return nil } - static func parseAsURL(url: NSURL, fragments: [String : AnyObject] = [:]) -> Location? { + static func parseAsURL(url: NSURL, fragments: [String : AnyObject] = [:], payload: Any? = nil) -> Location? { guard let route = url.host else { return nil } let urlComponents = NSURLComponents(URL: url, resolvingAgainstBaseURL: false) @@ -56,7 +56,7 @@ public struct Compass { arguments = fragment.queryParameters() } - return Location(path: route, arguments: arguments, fragments: fragments) + return Location(path: route, arguments: arguments, fragments: fragments, payload: payload) } static func findMatch(routeString: String, pathString: String) -> Result? { From b85f35eb00f41efa7c4e4ba43b2aae53b879319b Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 00:53:26 +0200 Subject: [PATCH 03/13] Refactor code --- Sources/Compass.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Sources/Compass.swift b/Sources/Compass.swift index 983126b..bc1de35 100644 --- a/Sources/Compass.swift +++ b/Sources/Compass.swift @@ -36,7 +36,10 @@ public struct Compass { } if let result = results.first { - return Location(path: result.route, arguments: result.arguments, fragments: fragments, payload: payload) + return Location(path: result.route, + arguments: result.arguments, + fragments: fragments, + payload: payload) } return nil @@ -56,7 +59,10 @@ public struct Compass { arguments = fragment.queryParameters() } - return Location(path: route, arguments: arguments, fragments: fragments, payload: payload) + return Location(path: route, + arguments: arguments, + fragments: fragments, + payload: payload) } static func findMatch(routeString: String, pathString: String) -> Result? { From 21b6031b0c64503aec09b44d6ba07ed6468dad34 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 00:57:55 +0200 Subject: [PATCH 04/13] Add payload tests --- Tests/Compass/CompassTests.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Tests/Compass/CompassTests.swift b/Tests/Compass/CompassTests.swift index d1deab3..fd87c6e 100644 --- a/Tests/Compass/CompassTests.swift +++ b/Tests/Compass/CompassTests.swift @@ -51,6 +51,22 @@ class CompassTests: XCTestCase { XCTAssertEqual("foo" , location.fragments["meta"] as? String) } + func testParsePayload() { + let url = NSURL(string: "compassTests://profile:testUser")! + + typealias Payload = (firstName: String, lastName: String) + + guard let location = Compass.parse(url, payload: Payload(firstName: "foo", lastName: "bar")) else { + XCTFail("Compass parsing failed") + return + } + + XCTAssertEqual("profile:{user}", location.path) + XCTAssertEqual(location.arguments["user"], "testUser") + XCTAssertEqual("foo" , (location.payload as? Payload)?.firstName) + XCTAssertEqual("bar" , (location.payload as? Payload)?.lastName) + } + func testParseRouteConcreateMatchCount() { let url = NSURL(string: "compassTests://profile:admin")! From ef6c25dfff2dfe4fd6b2ea1252da060905798d53 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 01:15:24 +0200 Subject: [PATCH 05/13] Handle errors --- Sources/Router.swift | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Sources/Router.swift b/Sources/Router.swift index ac05da5..fe80db4 100644 --- a/Sources/Router.swift +++ b/Sources/Router.swift @@ -1,16 +1,34 @@ public protocol Routable { - func navigate(to location: Location, from currentController: Controller) + func navigate(to location: Location, from currentController: Controller) throws +} + +public protocol ErrorRoutable { + + func handle(routeError: ErrorType, from currentController: Controller) +} + +public enum RouteError: ErrorType { + case NotFound } public struct Router: Routable { public var routes = [String: Routable]() + public var errorRoute: ErrorRoutable? public init() {} public func navigate(to location: Location, from currentController: Controller) { - guard let route = routes[location.path] else { return } - route.navigate(to: location, from: currentController) + guard let route = routes[location.path] else { + errorRoute?.handle(RouteError.NotFound, from: currentController) + return + } + + do { + try route.navigate(to: location, from: currentController) + } catch { + errorRoute?.handle(error, from: currentController) + } } } From 3fe58197bae7c183aac8df0ec331ee8a2a9dc1e1 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 01:18:03 +0200 Subject: [PATCH 06/13] Add more test helpers --- Tests/Compass/Helpers.swift | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Tests/Compass/Helpers.swift b/Tests/Compass/Helpers.swift index 2709968..bd83e5b 100644 --- a/Tests/Compass/Helpers.swift +++ b/Tests/Compass/Helpers.swift @@ -7,11 +7,27 @@ class TestRoute: Routable { var resolved = false - func navigate(to location: Location, from currentController: Controller) { + func navigate(to location: Location, from currentController: Controller) throws { resolved = true } } +class ThrowableRoute: Routable { + + func navigate(to location: Location, from currentController: Controller) throws { + throw RouteError.NotFound + } +} + +class ErrorRoute: ErrorRoutable { + + var error: ErrorType? + + func handle(routeError: ErrorType, from currentController: Controller) { + error = routeError + } +} + // MARK: - Shuffle extension CollectionType { From ce6829d443f38e01594138941a9d779021940c88 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 01:19:01 +0200 Subject: [PATCH 07/13] Init controller in setup --- Tests/Compass/RouterTests.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/Compass/RouterTests.swift b/Tests/Compass/RouterTests.swift index a14dd15..b41f5ab 100644 --- a/Tests/Compass/RouterTests.swift +++ b/Tests/Compass/RouterTests.swift @@ -5,12 +5,13 @@ import XCTest class RouterTests: XCTestCase { var router: Router! - var controller = Controller() var route: TestRoute! + var controller: Controller! override func setUp() { router = Router() route = TestRoute() + controller = Controller() } func testNavigateIfRouteRegistered() { From e6e453863c1b8191535226a9e4afaa24766552ef Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 01:21:38 +0200 Subject: [PATCH 08/13] Test if route is not registered --- Tests/Compass/RouterTests.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tests/Compass/RouterTests.swift b/Tests/Compass/RouterTests.swift index b41f5ab..1887f4c 100644 --- a/Tests/Compass/RouterTests.swift +++ b/Tests/Compass/RouterTests.swift @@ -7,11 +7,15 @@ class RouterTests: XCTestCase { var router: Router! var route: TestRoute! var controller: Controller! + var errorRoute: ErrorRoute! override func setUp() { router = Router() route = TestRoute() controller = Controller() + errorRoute = ErrorRoute() + + router.errorRoute = errorRoute } func testNavigateIfRouteRegistered() { @@ -19,11 +23,13 @@ class RouterTests: XCTestCase { router.navigate(to: Location(path: "test"), from: controller) XCTAssertTrue(route.resolved) + XCTAssertNil(errorRoute.error) } func testNavigateIfRouteNotRegistered() { router.navigate(to: Location(path: "test"), from: controller) XCTAssertFalse(route.resolved) + XCTAssertTrue(errorRoute.error is RouteError) } } From 41f6a248759b1668dfa4e69c6964603c93db1860 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 01:25:24 +0200 Subject: [PATCH 09/13] Test if route throws an error --- Tests/Compass/Helpers.swift | 6 +++++- Tests/Compass/RouterTests.swift | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Tests/Compass/Helpers.swift b/Tests/Compass/Helpers.swift index bd83e5b..68e7061 100644 --- a/Tests/Compass/Helpers.swift +++ b/Tests/Compass/Helpers.swift @@ -14,8 +14,12 @@ class TestRoute: Routable { class ThrowableRoute: Routable { + enum Error: ErrorType { + case Unknown + } + func navigate(to location: Location, from currentController: Controller) throws { - throw RouteError.NotFound + throw Error.Unknown } } diff --git a/Tests/Compass/RouterTests.swift b/Tests/Compass/RouterTests.swift index 1887f4c..4acd51e 100644 --- a/Tests/Compass/RouterTests.swift +++ b/Tests/Compass/RouterTests.swift @@ -32,4 +32,11 @@ class RouterTests: XCTestCase { XCTAssertFalse(route.resolved) XCTAssertTrue(errorRoute.error is RouteError) } + + func testNavigateIfRouteThrowsError() { + router.routes["throw"] = ThrowableRoute() + router.navigate(to: Location(path: "throw"), from: controller) + + XCTAssertTrue(errorRoute.error is ThrowableRoute.Error) + } } From 883816b0ec8de8e59abcda34fe21d7b3dec50c6d Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 09:29:25 +0200 Subject: [PATCH 10/13] Add more error types --- Sources/Router.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Sources/Router.swift b/Sources/Router.swift index fe80db4..94891a2 100644 --- a/Sources/Router.swift +++ b/Sources/Router.swift @@ -1,3 +1,9 @@ +public enum RouteError: ErrorType { + case NotFound + case InvalidArguments(Location) + case InvalidPayload(Location) +} + public protocol Routable { func navigate(to location: Location, from currentController: Controller) throws @@ -8,10 +14,6 @@ public protocol ErrorRoutable { func handle(routeError: ErrorType, from currentController: Controller) } -public enum RouteError: ErrorType { - case NotFound -} - public struct Router: Routable { public var routes = [String: Routable]() From 6dedbf40d82315fc22b1501f2945e3db43fae67a Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 10:18:12 +0200 Subject: [PATCH 11/13] Remove fragments --- Sources/Location.swift | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Sources/Location.swift b/Sources/Location.swift index 77bb213..28dce93 100644 --- a/Sources/Location.swift +++ b/Sources/Location.swift @@ -2,20 +2,15 @@ public struct Location { public let path: String public let arguments: [String: String] - public let fragments: [String: AnyObject] public let payload: Any? public var scheme: String { return Compass.scheme } - public init(path: String, - arguments: [String: String] = [:], - fragments: [String: AnyObject] = [:], - payload: Any? = nil) { + public init(path: String, arguments: [String: String] = [:], payload: Any? = nil) { self.path = path self.arguments = arguments - self.fragments = fragments self.payload = payload } } From e6c9f97486f42d735472d6e9ab2da15a61ac5603 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 10:19:10 +0200 Subject: [PATCH 12/13] Remove fragments from parse --- Sources/Compass.swift | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/Sources/Compass.swift b/Sources/Compass.swift index bc1de35..743296c 100644 --- a/Sources/Compass.swift +++ b/Sources/Compass.swift @@ -18,11 +18,11 @@ public struct Compass { public static var routes = [String]() - public static func parse(url: NSURL, fragments: [String : AnyObject] = [:], payload: Any? = nil) -> Location? { + public static func parse(url: NSURL, payload: Any? = nil) -> Location? { let path = url.absoluteString.substringFromIndex(scheme.endIndex) guard !(path.containsString("?") || path.containsString("#")) else { - return parseAsURL(url, fragments: fragments, payload: payload) + return parseAsURL(url, payload: payload) } let results: [Result] = routes.flatMap { @@ -36,16 +36,13 @@ public struct Compass { } if let result = results.first { - return Location(path: result.route, - arguments: result.arguments, - fragments: fragments, - payload: payload) + return Location(path: result.route, arguments: result.arguments, payload: payload) } return nil } - static func parseAsURL(url: NSURL, fragments: [String : AnyObject] = [:], payload: Any? = nil) -> Location? { + static func parseAsURL(url: NSURL, payload: Any? = nil) -> Location? { guard let route = url.host else { return nil } let urlComponents = NSURLComponents(URL: url, resolvingAgainstBaseURL: false) @@ -59,10 +56,7 @@ public struct Compass { arguments = fragment.queryParameters() } - return Location(path: route, - arguments: arguments, - fragments: fragments, - payload: payload) + return Location(path: route, arguments: arguments, payload: payload) } static func findMatch(routeString: String, pathString: String) -> Result? { From 28dbc2d33256f4698c870935b9701c11999f9679 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Wed, 24 Aug 2016 10:19:33 +0200 Subject: [PATCH 13/13] Update tests --- Tests/Compass/CompassTests.swift | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Tests/Compass/CompassTests.swift b/Tests/Compass/CompassTests.swift index fd87c6e..21a3fe0 100644 --- a/Tests/Compass/CompassTests.swift +++ b/Tests/Compass/CompassTests.swift @@ -38,19 +38,6 @@ class CompassTests: XCTestCase { XCTAssertEqual(location.arguments["user"], "testUser") } - func testParseFragments() { - let url = NSURL(string: "compassTests://profile:testUser")! - - guard let location = Compass.parse(url, fragments: ["meta" : "foo"]) else { - XCTFail("Compass parsing failed") - return - } - - XCTAssertEqual("profile:{user}", location.path) - XCTAssertEqual(location.arguments["user"], "testUser") - XCTAssertEqual("foo" , location.fragments["meta"] as? String) - } - func testParsePayload() { let url = NSURL(string: "compassTests://profile:testUser")!