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

Remove UserInfo from unnecessary methods #41

Merged
merged 4 commits into from
Dec 2, 2021
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ If you maintain a complex application and you want to use independent URL patter
You can use `ContextParser`.

```swift
let parser = ContextParser<Void>()
let parser = ContextParser()
let context = parser.parse(URL(string: "pokedex:/pokemons/25")!,
with: "pokedex://pokemons/:id")
```
Expand Down
43 changes: 35 additions & 8 deletions Sources/Crossroad/Context.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

struct Arguments {
public struct Arguments {
enum Error: Swift.Error {
case keyNotFound(String)
case couldNotParse(Parsable.Type)
Expand Down Expand Up @@ -72,22 +72,49 @@ public struct QueryParameters {
private var storage: [URLQueryItem]
}

public struct Context<UserInfo> {
public protocol ContextProtocol {
var url: URL { get }
/// This struct is for internal usage.
var internalArgumentsContainer: Arguments { get }
var queryParameters: QueryParameters { get }
}

extension ContextProtocol {
func attach<UserInfo>(_ userInfo: UserInfo) -> Context<UserInfo> {
Context<UserInfo>(url: url, internalArgumentsContainer: internalArgumentsContainer, queryParameters: queryParameters, userInfo: userInfo)
}
}

struct AbstractContext: ContextProtocol {
let url: URL
let internalArgumentsContainer: Arguments
let queryParameters: QueryParameters

init(url: URL, arguments: Arguments, queryParameters: QueryParameters) {
self.url = url
self.internalArgumentsContainer = arguments
self.queryParameters = queryParameters
}
}

public struct Context<UserInfo>: ContextProtocol {
public let url: URL
private let arguments: Arguments
public let internalArgumentsContainer: Arguments
public let queryParameters: QueryParameters
public let userInfo: UserInfo

internal init(url: URL, arguments: Arguments, queryParameters: QueryParameters, userInfo: UserInfo) {
internal init(url: URL, internalArgumentsContainer: Arguments, queryParameters: QueryParameters, userInfo: UserInfo) {
self.url = url
self.arguments = arguments
self.internalArgumentsContainer = internalArgumentsContainer
self.queryParameters = queryParameters
self.userInfo = userInfo
}
}

extension ContextProtocol {
@available(*, deprecated, message: "subscript for an argument is depricated.", renamed: "argument(named:)")
public subscript<T: Parsable>(argument keyword: String) -> T? {
return try? arguments.get(named: keyword)
return try? internalArgumentsContainer.get(named: keyword)
}

@available(*, deprecated, message: "Use queryParameters[key] instead")
Expand All @@ -96,7 +123,7 @@ public struct Context<UserInfo> {
}

public func argument<T: Parsable>(named key: String, as type: T.Type = T.self) throws -> T {
return try arguments.get(named: key)
return try internalArgumentsContainer.get(named: key)
}

@available(*, deprecated, renamed: "queryParameter(named:)")
Expand Down Expand Up @@ -132,6 +159,6 @@ public struct Context<UserInfo> {

extension Context where UserInfo == Void {
init(url: URL, arguments: Arguments, queryParameters: QueryParameters) {
self.init(url: url, arguments: arguments, queryParameters: queryParameters, userInfo: ())
self.init(url: url, internalArgumentsContainer: arguments, queryParameters: queryParameters, userInfo: ())
}
}
25 changes: 7 additions & 18 deletions Sources/Crossroad/ContextParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Foundation
@available(*, deprecated, renamed: "ContextParser")
public typealias URLParser = ContextParser

public class ContextParser<UserInfo> {
public class ContextParser {
private let keywordPrefix = ":"

public enum Error: Swift.Error {
Expand All @@ -16,17 +16,17 @@ public class ContextParser<UserInfo> {

public init() { }

public func parse(_ url: URL, with patternString: String, userInfo: UserInfo) throws -> Context<UserInfo> {
public func parse(_ url: URL, with patternString: String) throws -> ContextProtocol {
let pattern = try Pattern(patternString: patternString)
return try parse(url, with: pattern, userInfo: userInfo)
return try parse(url, with: pattern)
}

@available(*, deprecated, renamed: "parse(_:with:userInfo:)")
public func parse(_ url: URL, in patternString: String, userInfo: UserInfo) throws -> Context<UserInfo> {
try parse(url, with: patternString, userInfo: userInfo)
public func parse(_ url: URL, in patternString: String) throws -> ContextProtocol {
try parse(url, with: patternString)
}

func parse(_ url: URL, with pattern: Pattern, userInfo: UserInfo) throws -> Context<UserInfo> {
func parse(_ url: URL, with pattern: Pattern) throws -> ContextProtocol {
let expectedComponents: [String]
let actualURLComponents: [String]
let shouldBeCaseSensitives: [Bool]
Expand Down Expand Up @@ -69,7 +69,7 @@ public class ContextParser<UserInfo> {

let argumentContainer = Arguments(arguments)
let parameters = parseParameters(from: url)
return Context<UserInfo>(url: url, arguments: argumentContainer, queryParameters: parameters, userInfo: userInfo)
return AbstractContext(url: url, arguments: argumentContainer, queryParameters: parameters)
}

private func compare(_ lhs: String, _ rhs: String, isCaseSensitive: Bool) -> Bool {
Expand All @@ -90,14 +90,3 @@ public class ContextParser<UserInfo> {
return QueryParameters(parameters)
}
}

extension ContextParser where UserInfo == Void {
public func parse(_ url: URL, with patternString: String) throws -> Context<UserInfo> {
return try parse(url, with: patternString, userInfo: ())
}

@available(*, deprecated, renamed: "parse(_:with:)")
public func parse(_ url: URL, in patternString: String) throws -> Context<UserInfo> {
try parse(url, with: patternString, userInfo: ())
}
}
8 changes: 0 additions & 8 deletions Sources/Crossroad/OpenURLOption.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ public extension Router where UserInfo == OpenURLOption {
func openIfPossible(_ url: URL, options: ApplicationOpenURLOptions) -> Bool {
return openIfPossible(url, userInfo: OpenURLOption(options: options))
}

func responds(to url: URL, options: ApplicationOpenURLOptions) -> Bool {
return responds(to: url, userInfo: OpenURLOption(options: options))
}
}

@available(iOS 13.0, *)
Expand All @@ -44,10 +40,6 @@ extension Router where UserInfo == OpenURLOption {
public func openIfPossible(_ url: URL, options: UIScene.OpenURLOptions) -> Bool {
return openIfPossible(url, userInfo: OpenURLOption(options: options))
}

public func responds(to url: URL, options: UIScene.OpenURLOptions) -> Bool {
return responds(to: url, userInfo: OpenURLOption(options: options))
}
}

extension Context where UserInfo == OpenURLOption {
Expand Down
20 changes: 8 additions & 12 deletions Sources/Crossroad/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public final class Router<UserInfo> {

let linkSources: Set<LinkSource>
private(set) var routes: [Route]
private let parser = ContextParser<UserInfo>()
private let parser = ContextParser()

public convenience init(accepting linkSource: LinkSource) {
self.init(linkSources: [linkSource])
Expand Down Expand Up @@ -52,18 +52,18 @@ public final class Router<UserInfo> {

@discardableResult
public func openIfPossible(_ url: URL, userInfo: UserInfo) -> Bool {
searchMatchingRoutes(to: url, userInfo: userInfo)
searchMatchingRoutes(to: url)
.first { result in
do {
return try result.route.executeHandler(context: result.context)
return try result.route.executeHandler(context: result.context.attach(userInfo))
} catch {
return false
}
} != nil
}

public func responds(to url: URL, userInfo: UserInfo) -> Bool {
!searchMatchingRoutes(to: url, userInfo: userInfo).isEmpty
public func responds(to url: URL) -> Bool {
!searchMatchingRoutes(to: url).isEmpty
}

private func expandAcceptablePattern(of route: Route) -> Set<Pattern> {
Expand All @@ -79,12 +79,12 @@ public final class Router<UserInfo> {

private struct MatchResult {
let route: Route
let context: Context<UserInfo>
let context: ContextProtocol
}
private func searchMatchingRoutes(to url: URL, userInfo: UserInfo) -> [MatchResult] {
private func searchMatchingRoutes(to url: URL) -> [MatchResult] {
routes.reduce(into: []) { matchings, route in
for pattern in expandAcceptablePattern(of: route) {
if let context = try? parser.parse(url, with: pattern, userInfo: userInfo) {
if let context = try? parser.parse(url, with: pattern) {
let result = MatchResult(route: route, context: context)
matchings.append(result)
}
Expand All @@ -98,10 +98,6 @@ public extension Router where UserInfo == Void {
func openIfPossible(_ url: URL) -> Bool {
return openIfPossible(url, userInfo: ())
}

func responds(to url: URL) -> Bool {
return responds(to: url, userInfo: ())
}
}

public extension Router {
Expand Down
2 changes: 1 addition & 1 deletion Tests/CrossroadTests/ContextTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ final class ContextTests: XCTestCase {

var context: Context<Void> {
return Context<Void>(url: url,
arguments: Arguments(["pokedexID": "25", "name": "Pikachu"]),
internalArgumentsContainer: Arguments(["pokedexID": "25", "name": "Pikachu"]),
queryParameters: QueryParameters([
URLQueryItem(name: "name", value: "Pikachu"),
URLQueryItem(name: "type", value: "electric"),
Expand Down
2 changes: 1 addition & 1 deletion Tests/CrossroadTests/OpenURLOptionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class OpenURLOptionTests: XCTestCase {

func testContextWithOpenURLOption() {
let context = Context<OpenURLOption>(url: URL(string: "https://example.com")!,
arguments: .init([:]),
internalArgumentsContainer: .init([:]),
queryParameters: .init([]),
userInfo: options)
XCTAssertEqual(context.options.sourceApplication, "org.giginet.myapp")
Expand Down
4 changes: 2 additions & 2 deletions Tests/CrossroadTests/ParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import XCTest

final class ParserTests: XCTestCase {
func testURLParser() throws {
let parser = ContextParser<Void>()
let parser = ContextParser()
let patternString = "pokedex://pokemons/:pokedexID"
let context = try parser.parse(URL(string: "pokedex://pokemons/25")!, with: patternString)
XCTAssertEqual(try context.argument(named: "pokedexID"), 25)
}

func testPatternCase() throws {
let parser = ContextParser<Void>()
let parser = ContextParser()

let testCases: [(String, String, Bool, UInt)] = [
("http://my-awesome-pokedex.com/pokemons", "HTTP://MY-AWESOME-POKEDEX.COM/pokemons", true, #line),
Expand Down