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

Feature: location payload #34

Merged
merged 13 commits into from
Aug 24, 2016
10 changes: 5 additions & 5 deletions Sources/Compass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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, 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, payload: payload)
}

let results: [Result] = routes.flatMap {
Expand All @@ -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, payload: payload)
}

return nil
}

static func parseAsURL(url: NSURL, fragments: [String : AnyObject] = [:]) -> 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)
Expand All @@ -56,7 +56,7 @@ public struct Compass {
arguments = fragment.queryParameters()
}

return Location(path: route, arguments: arguments, fragments: fragments)
return Location(path: route, arguments: arguments, payload: payload)
}

static func findMatch(routeString: String, pathString: String) -> Result? {
Expand Down
6 changes: 3 additions & 3 deletions Sources/Location.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +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] = [:]) {
public init(path: String, arguments: [String: String] = [:], payload: Any? = nil) {
self.path = path
self.arguments = arguments
self.fragments = fragments
self.payload = payload
}
}
26 changes: 23 additions & 3 deletions Sources/Router.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
public enum RouteError: ErrorType {
case NotFound
case InvalidArguments(Location)
case InvalidPayload(Location)
}

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 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)
}
}
}
9 changes: 6 additions & 3 deletions Tests/Compass/CompassTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,20 @@ class CompassTests: XCTestCase {
XCTAssertEqual(location.arguments["user"], "testUser")
}

func testParseFragments() {
func testParsePayload() {
let url = NSURL(string: "compassTests://profile:testUser")!

guard let location = Compass.parse(url, fragments: ["meta" : "foo"]) else {
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.fragments["meta"] as? String)
XCTAssertEqual("foo" , (location.payload as? Payload)?.firstName)
XCTAssertEqual("bar" , (location.payload as? Payload)?.lastName)
}

func testParseRouteConcreateMatchCount() {
Expand Down
22 changes: 21 additions & 1 deletion Tests/Compass/Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,31 @@ 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 {

enum Error: ErrorType {
case Unknown
}

func navigate(to location: Location, from currentController: Controller) throws {
throw Error.Unknown
}
}

class ErrorRoute: ErrorRoutable {

var error: ErrorType?

func handle(routeError: ErrorType, from currentController: Controller) {
error = routeError
}
}

// MARK: - Shuffle

extension CollectionType {
Expand Down
16 changes: 15 additions & 1 deletion Tests/Compass/RouterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,38 @@ import XCTest
class RouterTests: XCTestCase {

var router: Router!
var controller = Controller()
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() {
router.routes["test"] = route
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)
}

func testNavigateIfRouteThrowsError() {
router.routes["throw"] = ThrowableRoute()
router.navigate(to: Location(path: "throw"), from: controller)

XCTAssertTrue(errorRoute.error is ThrowableRoute.Error)
}
}