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

Functional routers & parsers #5

Merged
merged 16 commits into from
Nov 12, 2017
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions DeepLinkHandling/Configuration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// Configuration.swift
// Deeper
//
// Created by Ilya Puchka on 29/10/2017.
// Copyright © 2017 Ilya Puchka. All rights reserved.
//

import Foundation

var clearDeeplinkHandling = true

public func configure(clearDeeplinkHandling _clearDeeplinkHandling: Bool = true, logger _logger: Logger? = Logger()) {
clearDeeplinkHandling = _clearDeeplinkHandling
logger = _logger
}

File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,14 @@ extension DeepLinkHandler {

open class AnyDeepLinkHandler<Intent>: DeepLinkHandler {

open var deeplinkHandling: DeepLinkHandling<Intent>?
open var deeplinkHandling: DeepLinkHandling<Intent>? {
didSet {
_setDeeplinkHandling(deeplinkHandling)
}
}

private let _open: (DeepLink<Intent>, Bool) -> DeepLinkHandling<Intent>
private let _setDeeplinkHandling: (DeepLinkHandling<Intent>?) -> Void

public init() {
guard type(of: self) != AnyDeepLinkHandler<Intent>.self else {
Expand All @@ -61,11 +66,15 @@ open class AnyDeepLinkHandler<Intent>: DeepLinkHandler {
self._open = { _, _ in
fatalError("Do not call `super.open(deeplink:animated:) -> DeepLinkHandling<Intent>` when inheriting from AnyDeepLinkHandler")
}
self._setDeeplinkHandling = { _ in }
}

/// Use this initialiser to wrap instances that are not subclasses of `AnyDeepLinkHandler`.
public init<Handler: DeepLinkHandler>(_ handler: Handler) where Handler.Intent == Intent {
self._open = {
self._setDeeplinkHandling = { [unowned handler] deeplinkHandling in
handler.deeplinkHandling = deeplinkHandling
}
self._open = { [unowned handler] in
let handling = handler.open(deeplink: $0, animated: $1)
switch handling {
case let .delayed(deeplink, animated, effect):
Expand Down
File renamed without changes.
33 changes: 33 additions & 0 deletions DeepLinkHandling/DeepLinkRouter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// DeepLinkRouter.swift
// Deeper
//
// Created by Ilya Puchka on 29/10/2017.
// Copyright © 2017 Ilya Puchka. All rights reserved.
//

import Foundation

public protocol DeepLinkRouter {
associatedtype Intent

var rootDeepLinkHandler: AnyDeepLinkHandler<Intent>? { get }

func openURL(_ url: URL) -> Intent?
}

extension DeepLinkRouter {

public func canOpen(url: URL) -> Bool {
return openURL(url) != nil
}

@discardableResult
public func open(url: URL) -> Bool {
guard let intent = openURL(url) else { return false }
let deeplink = DeepLink(url: url, intent: intent)
rootDeepLinkHandler?.open(deeplink: deeplink, animated: true) as Void?
return true
}

}
21 changes: 21 additions & 0 deletions DeepLinkHandling/Logger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Logger.swift
// Deeper
//
// Created by Ilya Puchka on 29/10/2017.
// Copyright © 2017 Ilya Puchka. All rights reserved.
//

import Foundation

var logger: Logger? = Logger()

open class Logger {

public init() {}

open func log<Handler: DeepLinkHandler>(deeplink: DeepLink<Handler.Intent>, result: DeepLinkHandling<Handler.Intent>, handler: Handler) {
print(result)
}

}
13 changes: 0 additions & 13 deletions Deeper/Utils.swift → DeepLinkHandling/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,3 @@ extension String {
return items
}
}

extension Array where Element == DeepLinkPathPattern {

var route: DeepLinkRoute {
if count == 1, case .string(let str)? = first {
return [.string(str)]
} else {
return DeepLinkRoute(pattern: self)
}
}

}

369 changes: 345 additions & 24 deletions Deeper.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions Deeper.xcodeproj/xcshareddata/xcschemes/DeeperFunc.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0900"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6355F2081FA28632000A608E"
BuildableName = "DeeperFunc.framework"
BlueprintName = "DeeperFunc"
ReferencedContainer = "container:Deeper.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6355F2101FA28633000A608E"
BuildableName = "DeeperFuncTests.xctest"
BlueprintName = "DeeperFuncTests"
ReferencedContainer = "container:Deeper.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6355F2081FA28632000A608E"
BuildableName = "DeeperFunc.framework"
BlueprintName = "DeeperFunc"
ReferencedContainer = "container:Deeper.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6355F2081FA28632000A608E"
BuildableName = "DeeperFunc.framework"
BlueprintName = "DeeperFunc"
ReferencedContainer = "container:Deeper.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6355F2081FA28632000A608E"
BuildableName = "DeeperFunc.framework"
BlueprintName = "DeeperFunc"
ReferencedContainer = "container:Deeper.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
7 changes: 7 additions & 0 deletions Deeper.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions Deeper/DeepLinkRoute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,15 @@ extension String {
})
}
}

extension Array where Element == DeepLinkPathPattern {

var route: DeepLinkRoute {
if count == 1, case .string(let str)? = first {
return [.string(str)]
} else {
return DeepLinkRoute(pattern: self)
}
}

}
18 changes: 0 additions & 18 deletions Deeper/Deeper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,6 @@
// Copyright © 2017 Ilya Puchka. All rights reserved.
//

var clearDeeplinkHandling = true
var logger: Logger? = Logger()

public func configure(clearDeeplinkHandling: Bool = true, logger: Logger? = Logger()) {
Deeper.clearDeeplinkHandling = clearDeeplinkHandling
Deeper.logger = logger
}

open class Logger {

public init() {}

open func log<Handler: DeepLinkHandler>(deeplink: DeepLink<Handler.Intent>, result: DeepLinkHandling<Handler.Intent>, handler: Handler) {
print(result)
}

}

public func /(lhs: DeepLinkRoute, rhs: DeepLinkRoute) -> DeepLinkRoute {
return DeepLinkRoute(pattern: lhs.pattern + rhs.pattern)
}
Expand Down
27 changes: 8 additions & 19 deletions Deeper/DeepLinkRouter.swift → Deeper/Router.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
//
// DeepLinkRouter.swift
// Router.swift
// Deeper
//
// Created by Ilya Puchka on 09/10/2017.
// Copyright © 2017 Ilya Puchka. All rights reserved.
//

public class DeepLinkRouter<Handler: DeepLinkHandler> {
weak private(set) var rootDeepLinkHandler: Handler?
public class Router<Intent>: DeepLinkRouter {

public private(set) var rootDeepLinkHandler: AnyDeepLinkHandler<Intent>?
let scheme: String

public typealias HandlerClosure = (URL, [DeepLinkPatternParameter: String]) -> Handler.Intent?
public typealias HandlerClosure = (URL, [DeepLinkPatternParameter: String]) -> Intent?
var routesHandlers: [DeepLinkRoute: HandlerClosure] = [:]
var routesPreference: [DeepLinkRoute] = []

public init(scheme: String, rootDeepLinkHandler: Handler) {
public init(scheme: String, rootDeepLinkHandler: AnyDeepLinkHandler<Intent>) {
self.scheme = scheme
self.rootDeepLinkHandler = rootDeepLinkHandler
}
Expand All @@ -24,26 +25,14 @@ public class DeepLinkRouter<Handler: DeepLinkHandler> {
routes.forEach({ routesHandlers[$0] = handler })
}

public func canOpen(url: URL) -> Bool {
return openURL(url) != nil
}

@discardableResult
public func open(url: URL) -> Bool {
guard let (_, intent) = openURL(url) else { return false }
let deeplink = DeepLink(url: url, intent: intent)
rootDeepLinkHandler?.open(deeplink: deeplink, animated: true) as Void?
return true
}

func openURL(_ url: URL) -> (DeepLinkPatternMatcher.Result, Handler.Intent)? {
public func openURL(_ url: URL) -> Intent? {
guard url.scheme == scheme else { return nil }

for route in routesPreference {
let matcher = DeepLinkPatternMatcher(route: route, url: url)
let result = matcher.match()
if result.matched, let handler = routesHandlers[route], let intent = handler(url, result.params) {
return (result, intent)
return intent
}
}
return nil
Expand Down
Loading