Add SwiftLint
This commit is contained in:
parent
7e8d9c64e7
commit
637b91471d
|
@ -0,0 +1,12 @@
|
||||||
|
disabled_rules:
|
||||||
|
- force_try
|
||||||
|
- identifier_name
|
||||||
|
- trailing_whitespace
|
||||||
|
|
||||||
|
line_length: 300
|
||||||
|
|
||||||
|
nesting:
|
||||||
|
type_level: 3
|
||||||
|
|
||||||
|
trailing_comma:
|
||||||
|
mandatory_comma: true
|
10
README.md
10
README.md
|
@ -8,22 +8,22 @@ Type-safe URL routing for Swift.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
// Define routes
|
// Define routes
|
||||||
struct UserIndex : Route {
|
struct UserIndex: Route {
|
||||||
let path = "/users"
|
let path = "/users"
|
||||||
|
|
||||||
func map(to url: URL, parameters: [String : String], queries: [String : String]) -> UIViewController {
|
func map(to url: URL, parameters: [String: String], queries: [String: String]) -> UIViewController {
|
||||||
return UserIndexViewController()
|
return UserIndexViewController()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UserDetail : Route {
|
struct UserDetail: Route {
|
||||||
let path = "/users/{id}"
|
let path = "/users/{id}"
|
||||||
|
|
||||||
struct Parameters : Decodable {
|
struct Parameters: Decodable {
|
||||||
let id: Int
|
let id: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func map(to url: URL, parameters: Parameters, queries: [String : String]) -> UIViewController {
|
func map(to url: URL, parameters: Parameters, queries: [String: String]) -> UIViewController {
|
||||||
return UserDetailViewController(id: parameters.id)
|
return UserDetailViewController(id: parameters.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,6 +219,7 @@
|
||||||
430EC1DD20598F7600F84EA2 /* Frameworks */,
|
430EC1DD20598F7600F84EA2 /* Frameworks */,
|
||||||
430EC1DE20598F7600F84EA2 /* Headers */,
|
430EC1DE20598F7600F84EA2 /* Headers */,
|
||||||
430EC1DF20598F7600F84EA2 /* Resources */,
|
430EC1DF20598F7600F84EA2 /* Resources */,
|
||||||
|
437785B820EBDD810067EC31 /* ShellScript */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
@ -255,6 +256,7 @@
|
||||||
430EC2062059919F00F84EA2 /* Frameworks */,
|
430EC2062059919F00F84EA2 /* Frameworks */,
|
||||||
430EC2072059919F00F84EA2 /* Headers */,
|
430EC2072059919F00F84EA2 /* Headers */,
|
||||||
430EC2082059919F00F84EA2 /* Resources */,
|
430EC2082059919F00F84EA2 /* Resources */,
|
||||||
|
437785B920EBDD8D0067EC31 /* ShellScript */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
@ -290,7 +292,7 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastSwiftUpdateCheck = 0920;
|
LastSwiftUpdateCheck = 0920;
|
||||||
LastUpgradeCheck = 0920;
|
LastUpgradeCheck = 0940;
|
||||||
ORGANIZATIONNAME = woxtu;
|
ORGANIZATIONNAME = woxtu;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
430EC1E020598F7600F84EA2 = {
|
430EC1E020598F7600F84EA2 = {
|
||||||
|
@ -362,6 +364,35 @@
|
||||||
};
|
};
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
437785B820EBDD810067EC31 /* ShellScript */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||||
|
};
|
||||||
|
437785B920EBDD8D0067EC31 /* ShellScript */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
430EC1DC20598F7600F84EA2 /* Sources */ = {
|
430EC1DC20598F7600F84EA2 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
|
@ -599,6 +630,7 @@
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
CLANG_WARN_COMMA = YES;
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
@ -606,6 +638,7 @@
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
@ -659,6 +692,7 @@
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
CLANG_WARN_COMMA = YES;
|
CLANG_WARN_COMMA = YES;
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
@ -666,6 +700,7 @@
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0920"
|
LastUpgradeVersion = "0940"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -26,7 +26,6 @@
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
language = ""
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
|
@ -56,7 +55,6 @@
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
language = ""
|
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0920"
|
LastUpgradeVersion = "0940"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -26,7 +26,6 @@
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
language = ""
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
|
@ -56,7 +55,6 @@
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
language = ""
|
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
|
|
@ -10,9 +10,9 @@ import Foundation
|
||||||
|
|
||||||
struct AnyRoute<T> {
|
struct AnyRoute<T> {
|
||||||
let pattern: Pattern
|
let pattern: Pattern
|
||||||
let map: (URL, [String : String], [String : String]) -> T?
|
let map: (URL, [String: String], [String: String]) -> T?
|
||||||
|
|
||||||
init<R>(_ route: R) where R : Route, R.Response == T {
|
init<R>(_ route: R) where R: Route, R.Response == T {
|
||||||
self.pattern = Pattern(string: route.path)
|
self.pattern = Pattern(string: route.path)
|
||||||
|
|
||||||
self.map = { url, parameters, queries in
|
self.map = { url, parameters, queries in
|
||||||
|
|
|
@ -10,6 +10,6 @@ import Foundation
|
||||||
|
|
||||||
extension NSRegularExpression {
|
extension NSRegularExpression {
|
||||||
func stringByReplacingMatches(in string: String, options: NSRegularExpression.MatchingOptions = [], withTemplate templ: String) -> String {
|
func stringByReplacingMatches(in string: String, options: NSRegularExpression.MatchingOptions = [], withTemplate templ: String) -> String {
|
||||||
return self.stringByReplacingMatches(in: string, options: options, range: NSMakeRange(0, string.count), withTemplate: templ)
|
return self.stringByReplacingMatches(in: string, options: options, range: NSRange(location: 0, length: string.count), withTemplate: templ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ open class Navigator {
|
||||||
return UIApplication.shared.keyWindow?.rootViewController
|
return UIApplication.shared.keyWindow?.rootViewController
|
||||||
}
|
}
|
||||||
|
|
||||||
open static func append<R>(route: R) where R : Route, R.Response == UIViewController {
|
open static func append<R>(route: R) where R: Route, R.Response == UIViewController {
|
||||||
self.router.append(route: route)
|
self.router.append(route: route)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@ struct Pattern {
|
||||||
.map(Component.init)
|
.map(Component.init)
|
||||||
}
|
}
|
||||||
|
|
||||||
func match(url: URL) -> [String : String]? {
|
func match(url: URL) -> [String: String]? {
|
||||||
let pathComponents = [url.host].flatMap { $0 } + url.pathComponents.dropFirst() // drop "/"
|
let pathComponents = [url.host].compactMap { $0 } + url.pathComponents.dropFirst() // drop "/"
|
||||||
|
|
||||||
if self.scheme == url.scheme && self.pathComponents == pathComponents.map(Component.init) {
|
if self.scheme == url.scheme && self.pathComponents == pathComponents.map(Component.init) {
|
||||||
return zip(self.pathComponents, pathComponents).reduce(into: [:]) { result, component in
|
return zip(self.pathComponents, pathComponents).reduce(into: [:]) { result, component in
|
||||||
|
@ -54,8 +54,8 @@ struct Pattern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Pattern.Component : Equatable {
|
extension Pattern.Component: Equatable {
|
||||||
static func ==(lhs: Pattern.Component, rhs: Pattern.Component) -> Bool {
|
static func == (lhs: Pattern.Component, rhs: Pattern.Component) -> Bool {
|
||||||
switch (lhs, rhs) {
|
switch (lhs, rhs) {
|
||||||
case let (.constant(lhs), .constant(rhs)): return lhs == rhs
|
case let (.constant(lhs), .constant(rhs)): return lhs == rhs
|
||||||
case let (.variable(lhs), .variable(rhs)): return lhs == rhs
|
case let (.variable(lhs), .variable(rhs)): return lhs == rhs
|
||||||
|
|
|
@ -9,20 +9,20 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class PayloadDecoder {
|
class PayloadDecoder {
|
||||||
func decode<T>(_ type: T.Type = T.self, from data: [String : String]) throws -> T where T : Decodable {
|
func decode<T>(_ type: T.Type = T.self, from data: [String: String]) throws -> T where T: Decodable {
|
||||||
return try T(from: InnerDecoder(data: data))
|
return try T(from: InnerDecoder(data: data))
|
||||||
}
|
}
|
||||||
|
|
||||||
class InnerDecoder : Decoder {
|
class InnerDecoder: Decoder {
|
||||||
let data: [String : String]
|
let data: [String: String]
|
||||||
var codingPath = [CodingKey]()
|
var codingPath = [CodingKey]()
|
||||||
let userInfo = [CodingUserInfoKey : Any]()
|
let userInfo = [CodingUserInfoKey: Any]()
|
||||||
|
|
||||||
init(data: [String : String]) {
|
init(data: [String: String]) {
|
||||||
self.data = data
|
self.data = data
|
||||||
}
|
}
|
||||||
|
|
||||||
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
|
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key: CodingKey {
|
||||||
return KeyedDecodingContainer(InnerKeyedDecodingContainer(referencing: self))
|
return KeyedDecodingContainer(InnerKeyedDecodingContainer(referencing: self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class PayloadDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InnerKeyedDecodingContainer<Key> : KeyedDecodingContainerProtocol where Key : CodingKey {
|
class InnerKeyedDecodingContainer<Key>: KeyedDecodingContainerProtocol where Key: CodingKey {
|
||||||
let decoder: InnerDecoder
|
let decoder: InnerDecoder
|
||||||
|
|
||||||
var codingPath: [CodingKey] {
|
var codingPath: [CodingKey] {
|
||||||
|
@ -43,7 +43,7 @@ class PayloadDecoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
var allKeys: [Key] {
|
var allKeys: [Key] {
|
||||||
return self.decoder.data.keys.flatMap(Key.init)
|
return self.decoder.data.keys.compactMap(Key.init)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(referencing decoder: InnerDecoder) {
|
init(referencing decoder: InnerDecoder) {
|
||||||
|
@ -58,7 +58,7 @@ class PayloadDecoder {
|
||||||
return self.decoder.data[key.stringValue] == nil
|
return self.decoder.data[key.stringValue] == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable & LosslessStringConvertible {
|
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Decodable & LosslessStringConvertible {
|
||||||
guard let rawValue = self.decoder.data[key.stringValue] else {
|
guard let rawValue = self.decoder.data[key.stringValue] else {
|
||||||
throw DecodingError.valueNotFound(type, .init(codingPath: self.codingPath, debugDescription: "No value associated with key '\(key)'."))
|
throw DecodingError.valueNotFound(type, .init(codingPath: self.codingPath, debugDescription: "No value associated with key '\(key)'."))
|
||||||
}
|
}
|
||||||
|
@ -70,13 +70,13 @@ class PayloadDecoder {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable {
|
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T: Decodable {
|
||||||
self.decoder.codingPath.append(key)
|
self.decoder.codingPath.append(key)
|
||||||
defer { self.decoder.codingPath.removeLast() }
|
defer { self.decoder.codingPath.removeLast() }
|
||||||
return try T(from: self.decoder)
|
return try T(from: self.decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
|
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey: CodingKey {
|
||||||
fatalError("It should not be called")
|
fatalError("It should not be called")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ class PayloadDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InnerSingleValueDecodingContainer : SingleValueDecodingContainer {
|
class InnerSingleValueDecodingContainer: SingleValueDecodingContainer {
|
||||||
let decoder: InnerDecoder
|
let decoder: InnerDecoder
|
||||||
|
|
||||||
var codingPath: [CodingKey] {
|
var codingPath: [CodingKey] {
|
||||||
|
@ -112,7 +112,7 @@ class PayloadDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode<T>(_ type: T.Type) throws -> T where T : Decodable & LosslessStringConvertible {
|
func decode<T>(_ type: T.Type) throws -> T where T: Decodable & LosslessStringConvertible {
|
||||||
guard let key = self.codingPath.last else {
|
guard let key = self.codingPath.last else {
|
||||||
fatalError("It should not be called")
|
fatalError("It should not be called")
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ class PayloadDecoder {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
|
func decode<T>(_ type: T.Type) throws -> T where T: Decodable {
|
||||||
return try T(from: self.decoder)
|
return try T(from: self.decoder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,10 @@ import Foundation
|
||||||
|
|
||||||
public protocol Route {
|
public protocol Route {
|
||||||
associatedtype Response
|
associatedtype Response
|
||||||
associatedtype Parameters : Decodable = [String : String]
|
associatedtype Parameters: Decodable = [String: String]
|
||||||
associatedtype Queries : Decodable = [String : String]
|
associatedtype Queries: Decodable = [String: String]
|
||||||
|
|
||||||
var path: String { get }
|
var path: String { get }
|
||||||
|
|
||||||
func map(to url: URL, parameters: Parameters, queries: Queries) -> Response
|
func map(to url: URL, parameters: Parameters, queries: Queries) -> Response
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ open class Router<T> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open func append<R>(route: R) where R : Route, R.Response == T {
|
open func append<R>(route: R) where R: Route, R.Response == T {
|
||||||
self.routes.append(AnyRoute(route))
|
self.routes.append(AnyRoute(route))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,13 +20,13 @@ class AnyRouteTests: XCTestCase {
|
||||||
struct TestRoute: Route {
|
struct TestRoute: Route {
|
||||||
let path = "/"
|
let path = "/"
|
||||||
|
|
||||||
func map(to url: URL, parameters: [String : String], queries: [String : String]) -> TestResponse {
|
func map(to url: URL, parameters: [String: String], queries: [String: String]) -> TestResponse {
|
||||||
return TestResponse(x1: parameters["x", default: ""], x2: queries["x", default: ""])
|
return TestResponse(x1: parameters["x", default: ""], x2: queries["x", default: ""])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let route = AnyRoute<TestResponse>(TestRoute())
|
let route = AnyRoute<TestResponse>(TestRoute())
|
||||||
let response = route.map(URL(string: "/")!, ["x" : "foo"], ["x" : "bar"])
|
let response = route.map(URL(string: "/")!, ["x": "foo"], ["x": "bar"])
|
||||||
XCTAssertEqual(response?.x1, "foo")
|
XCTAssertEqual(response?.x1, "foo")
|
||||||
XCTAssertEqual(response?.x2, "bar")
|
XCTAssertEqual(response?.x2, "bar")
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ class AnyRouteTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
let route = AnyRoute<TestResponse>(TestRoute())
|
let route = AnyRoute<TestResponse>(TestRoute())
|
||||||
let response = route.map(URL(string: "/")!, ["x" : "foo"], ["x" : "bar"])
|
let response = route.map(URL(string: "/")!, ["x": "foo"], ["x": "bar"])
|
||||||
XCTAssertEqual(response?.x1, "foo")
|
XCTAssertEqual(response?.x1, "foo")
|
||||||
XCTAssertEqual(response?.x2, "bar")
|
XCTAssertEqual(response?.x2, "bar")
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,6 @@ class PatternTests: XCTestCase {
|
||||||
|
|
||||||
func testPatternMatch() {
|
func testPatternMatch() {
|
||||||
XCTAssertNil(Pattern(string: "/x1/{x2}").match(url: URL(string: "/")!))
|
XCTAssertNil(Pattern(string: "/x1/{x2}").match(url: URL(string: "/")!))
|
||||||
XCTAssertEqual(Pattern(string: "/x1/{x2}").match(url: URL(string: "/x1/x2")!)!, ["x2" : "x2"])
|
XCTAssertEqual(Pattern(string: "/x1/{x2}").match(url: URL(string: "/x1/x2")!)!, ["x2": "x2"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,45 +11,45 @@ import XCTest
|
||||||
|
|
||||||
class PayloadDecoderTests: XCTestCase {
|
class PayloadDecoderTests: XCTestCase {
|
||||||
func testDecodeString() {
|
func testDecodeString() {
|
||||||
struct TestStruct : Decodable {
|
struct TestStruct: Decodable {
|
||||||
let x: String
|
let x: String
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload = ["x" : "x"]
|
let payload = ["x": "x"]
|
||||||
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
||||||
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, "x")
|
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, "x")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDecodeInt() {
|
func testDecodeInt() {
|
||||||
struct TestStruct : Decodable {
|
struct TestStruct: Decodable {
|
||||||
let x: Int
|
let x: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload = ["x" : "42"]
|
let payload = ["x": "42"]
|
||||||
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
||||||
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, 42)
|
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, 42)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDecodeOptional() {
|
func testDecodeOptional() {
|
||||||
struct TestStruct : Decodable {
|
struct TestStruct: Decodable {
|
||||||
let x: String?
|
let x: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload = [String : String]()
|
let payload = [String: String]()
|
||||||
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
||||||
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, nil)
|
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDecodeEnum() {
|
func testDecodeEnum() {
|
||||||
enum TestEnum : String, Decodable {
|
enum TestEnum: String, Decodable {
|
||||||
case type
|
case type
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestStruct : Decodable {
|
struct TestStruct: Decodable {
|
||||||
let x: TestEnum
|
let x: TestEnum
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload = ["x" : "type"]
|
let payload = ["x": "type"]
|
||||||
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
|
||||||
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, .type)
|
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, .type)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,14 @@ class RouterTests: XCTestCase {
|
||||||
let q: String?
|
let q: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestRoute : Route {
|
struct TestRoute: Route {
|
||||||
let path = "/{p}"
|
let path = "/{p}"
|
||||||
|
|
||||||
struct Parameters : Decodable {
|
struct Parameters: Decodable {
|
||||||
let p: String
|
let p: String
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Queries : Decodable {
|
struct Queries: Decodable {
|
||||||
let q: String?
|
let q: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue