Add SwiftLint

This commit is contained in:
woxtu 2018-07-07 16:01:08 +09:00
parent 7e8d9c64e7
commit 637b91471d
17 changed files with 106 additions and 55 deletions

12
.swiftlint.yml Normal file
View File

@ -0,0 +1,12 @@
disabled_rules:
- force_try
- identifier_name
- trailing_whitespace
line_length: 300
nesting:
type_level: 3
trailing_comma:
mandatory_comma: true

View File

@ -8,22 +8,22 @@ Type-safe URL routing for Swift.
```swift
// Define routes
struct UserIndex : Route {
struct UserIndex: Route {
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()
}
}
struct UserDetail : Route {
struct UserDetail: Route {
let path = "/users/{id}"
struct Parameters : Decodable {
struct Parameters: Decodable {
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)
}
}

View File

@ -219,6 +219,7 @@
430EC1DD20598F7600F84EA2 /* Frameworks */,
430EC1DE20598F7600F84EA2 /* Headers */,
430EC1DF20598F7600F84EA2 /* Resources */,
437785B820EBDD810067EC31 /* ShellScript */,
);
buildRules = (
);
@ -255,6 +256,7 @@
430EC2062059919F00F84EA2 /* Frameworks */,
430EC2072059919F00F84EA2 /* Headers */,
430EC2082059919F00F84EA2 /* Resources */,
437785B920EBDD8D0067EC31 /* ShellScript */,
);
buildRules = (
);
@ -290,7 +292,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0920;
LastUpgradeCheck = 0940;
ORGANIZATIONNAME = woxtu;
TargetAttributes = {
430EC1E020598F7600F84EA2 = {
@ -362,6 +364,35 @@
};
/* 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 */
430EC1DC20598F7600F84EA2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
@ -599,6 +630,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@ -606,6 +638,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_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_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@ -659,6 +692,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@ -666,6 +700,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_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_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;

View File

@ -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>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
@ -56,7 +55,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
@ -56,7 +55,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -10,9 +10,9 @@ import Foundation
struct AnyRoute<T> {
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.map = { url, parameters, queries in

View File

@ -10,6 +10,6 @@ import Foundation
extension NSRegularExpression {
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)
}
}

View File

@ -17,7 +17,7 @@ open class Navigator {
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)
}

View File

@ -39,8 +39,8 @@ struct Pattern {
.map(Component.init)
}
func match(url: URL) -> [String : String]? {
let pathComponents = [url.host].flatMap { $0 } + url.pathComponents.dropFirst() // drop "/"
func match(url: URL) -> [String: String]? {
let pathComponents = [url.host].compactMap { $0 } + url.pathComponents.dropFirst() // drop "/"
if self.scheme == url.scheme && self.pathComponents == pathComponents.map(Component.init) {
return zip(self.pathComponents, pathComponents).reduce(into: [:]) { result, component in
@ -54,8 +54,8 @@ struct Pattern {
}
}
extension Pattern.Component : Equatable {
static func ==(lhs: Pattern.Component, rhs: Pattern.Component) -> Bool {
extension Pattern.Component: Equatable {
static func == (lhs: Pattern.Component, rhs: Pattern.Component) -> Bool {
switch (lhs, rhs) {
case let (.constant(lhs), .constant(rhs)): return lhs == rhs
case let (.variable(lhs), .variable(rhs)): return lhs == rhs

View File

@ -9,20 +9,20 @@
import Foundation
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))
}
class InnerDecoder : Decoder {
let data: [String : String]
class InnerDecoder: Decoder {
let data: [String: String]
var codingPath = [CodingKey]()
let userInfo = [CodingUserInfoKey : Any]()
let userInfo = [CodingUserInfoKey: Any]()
init(data: [String : String]) {
init(data: [String: String]) {
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))
}
@ -35,7 +35,7 @@ class PayloadDecoder {
}
}
class InnerKeyedDecodingContainer<Key> : KeyedDecodingContainerProtocol where Key : CodingKey {
class InnerKeyedDecodingContainer<Key>: KeyedDecodingContainerProtocol where Key: CodingKey {
let decoder: InnerDecoder
var codingPath: [CodingKey] {
@ -43,7 +43,7 @@ class PayloadDecoder {
}
var allKeys: [Key] {
return self.decoder.data.keys.flatMap(Key.init)
return self.decoder.data.keys.compactMap(Key.init)
}
init(referencing decoder: InnerDecoder) {
@ -58,7 +58,7 @@ class PayloadDecoder {
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 {
throw DecodingError.valueNotFound(type, .init(codingPath: self.codingPath, debugDescription: "No value associated with key '\(key)'."))
}
@ -70,13 +70,13 @@ class PayloadDecoder {
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)
defer { self.decoder.codingPath.removeLast() }
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")
}
@ -93,7 +93,7 @@ class PayloadDecoder {
}
}
class InnerSingleValueDecodingContainer : SingleValueDecodingContainer {
class InnerSingleValueDecodingContainer: SingleValueDecodingContainer {
let decoder: InnerDecoder
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 {
fatalError("It should not be called")
}
@ -128,7 +128,7 @@ class PayloadDecoder {
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)
}
}

View File

@ -10,8 +10,8 @@ import Foundation
public protocol Route {
associatedtype Response
associatedtype Parameters : Decodable = [String : String]
associatedtype Queries : Decodable = [String : String]
associatedtype Parameters: Decodable = [String: String]
associatedtype Queries: Decodable = [String: String]
var path: String { get }

View File

@ -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))
}

View File

@ -20,13 +20,13 @@ class AnyRouteTests: XCTestCase {
struct TestRoute: Route {
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: ""])
}
}
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?.x2, "bar")
}
@ -54,7 +54,7 @@ class AnyRouteTests: XCTestCase {
}
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?.x2, "bar")
}

View File

@ -24,6 +24,6 @@ class PatternTests: XCTestCase {
func testPatternMatch() {
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"])
}
}

View File

@ -11,45 +11,45 @@ import XCTest
class PayloadDecoderTests: XCTestCase {
func testDecodeString() {
struct TestStruct : Decodable {
struct TestStruct: Decodable {
let x: String
}
let payload = ["x" : "x"]
let payload = ["x": "x"]
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, "x")
}
func testDecodeInt() {
struct TestStruct : Decodable {
struct TestStruct: Decodable {
let x: Int
}
let payload = ["x" : "42"]
let payload = ["x": "42"]
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, 42)
}
func testDecodeOptional() {
struct TestStruct : Decodable {
struct TestStruct: Decodable {
let x: String?
}
let payload = [String : String]()
let payload = [String: String]()
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, nil)
}
func testDecodeEnum() {
enum TestEnum : String, Decodable {
enum TestEnum: String, Decodable {
case type
}
struct TestStruct : Decodable {
struct TestStruct: Decodable {
let x: TestEnum
}
let payload = ["x" : "type"]
let payload = ["x": "type"]
XCTAssertNoThrow(try PayloadDecoder().decode(TestStruct.self, from: payload))
XCTAssertEqual(try PayloadDecoder().decode(TestStruct.self, from: payload).x, .type)
}

View File

@ -16,14 +16,14 @@ class RouterTests: XCTestCase {
let q: String?
}
struct TestRoute : Route {
struct TestRoute: Route {
let path = "/{p}"
struct Parameters : Decodable {
struct Parameters: Decodable {
let p: String
}
struct Queries : Decodable {
struct Queries: Decodable {
let q: String?
}