From 22fd5aceb8748495d8349718ff30f787c3648250 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 19 Jul 2016 11:37:50 -0700 Subject: [PATCH] Update Mapper for Swift 3.0 --- .swift-version | 1 + CHANGELOG.md | 8 +- Makefile | 3 +- Mapper.xcodeproj/project.pbxproj | 8 +- README.md | 8 +- Sources/Convertible.swift | 11 +- Sources/DefaultConvertible.swift | 4 +- Sources/Mappable.swift | 25 ++-- Sources/Mapper.swift | 116 ++++++++---------- Sources/MapperError.swift | 12 +- Sources/NSDictionary+Safety.swift | 8 +- Sources/NSURL+Convertible.swift | 21 ++-- Sources/Transform+Dictionary.swift | 11 +- Tests/MapperTests/ConvertibleValueTests.swift | 30 +++-- .../CustomTransformationTests.swift | 4 +- Tests/MapperTests/ErrorTests.swift | 14 +-- Tests/MapperTests/NormalValueTests.swift | 4 +- .../RawRepresentibleValueTests.swift | 22 ++-- Tests/MapperTests/TransformTests.swift | 8 +- 19 files changed, 147 insertions(+), 171 deletions(-) create mode 100644 .swift-version diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..9f55b2c --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +3.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f3a76e..048a70b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,13 @@ ## Breaking -- Swift 2.3 support +- Swift 3.0 support [Keith Smiley](https://github.com/keith) - [#73](https://github.com/lyft/mapper/pull/73) + [#76](https://github.com/lyft/mapper/pull/76) + +- Update transformation function to take `Any` + [Keith Smiley](https://github.com/keith) + [#76](https://github.com/lyft/mapper/pull/76) ## Enhancements diff --git a/Makefile b/Makefile index 933461a..420c0ab 100644 --- a/Makefile +++ b/Makefile @@ -75,5 +75,4 @@ test-coverage: ! grep -C 10 "^\s*0" coverage.txt test-swiftpm-osx: - SWIFT_EXEC="/Applications/Xcode.app/Contents/Developer/Toolchains/Swift_2.3.xctoolchain/usr/bin/swiftc" \ - swift test + swift test diff --git a/Mapper.xcodeproj/project.pbxproj b/Mapper.xcodeproj/project.pbxproj index 6b36d94..74fda7e 100644 --- a/Mapper.xcodeproj/project.pbxproj +++ b/Mapper.xcodeproj/project.pbxproj @@ -376,7 +376,7 @@ PRODUCT_NAME = Mapper; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -400,7 +400,7 @@ PRODUCT_NAME = Mapper; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; @@ -415,7 +415,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.Lyft.MapperTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -429,7 +429,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.Lyft.MapperTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/README.md b/README.md index 85dfcc1..db57616 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ import Mapper // Conform to the Mappable protocol struct User: Mappable { let id: String - let photoURL: NSURL? + let photoURL: URL? // Implement this initializer init(map: Mapper) throws { @@ -95,7 +95,7 @@ extension CLLocationCoordinate2D: Convertible { let latitude = location["lat"] as? Double, let longitude = location["lng"] as? Double else { - throw MapperError.ConvertibleError(value: value, type: [String: Double].self) + throw MapperError.convertibleError(value: value, type: [String: Double].self) } return CLLocationCoordinate2D(latitude: latitude, longitude: longitude) @@ -128,7 +128,7 @@ let place = Place.from(JSON) ```swift private func extractFirstName(object: AnyObject?) throws -> String { guard let fullName = object as? String else { - throw MapperError.ConvertibleError(value: object, type: String.self) + throw MapperError.convertibleError(value: object, type: String.self) } let parts = fullName.characters.split { $0 == " " }.map(String.init) @@ -136,7 +136,7 @@ private func extractFirstName(object: AnyObject?) throws -> String { return firstName } - throw MapperError.CustomError(field: nil, message: "Couldn't split the string!") + throw MapperError.customError(field: nil, message: "Couldn't split the string!") } struct User: Mappable { diff --git a/Sources/Convertible.swift b/Sources/Convertible.swift index 166414d..41ccb6b 100644 --- a/Sources/Convertible.swift +++ b/Sources/Convertible.swift @@ -1,16 +1,16 @@ /** The Convertible protocol defines how to convert values to custom objects this differs from the Mappable protocol because the creation function is passed - an AnyObject, allowing your definition to accept any data, and convert it as seen fit + an Any, allowing your definition to accept any data, and convert it as seen fit - NSURL's Convertible implementation is provided by default, assuming the passed value + URL's Convertible implementation is provided by default, assuming the passed value is a String Example: // Convertible implementation for custom logic to create `CLLocationCoordinate2D`s from dictionaries extension CLLocationCoordinate2D: Convertible { - public static func fromMap(value: AnyObject?) throws -> CLLocationCoordinate2D { + public static func fromMap(value: Any) throws -> CLLocationCoordinate2D { guard let location = value as? NSDictionary, let latitude = (location["lat"] ?? location["latitude"]) as? Double, let longitude = (location["lng"] ?? location["longitude"]) as? Double else @@ -35,10 +35,9 @@ public protocol Convertible { - parameter value: Any value (probably from the data source's value for the given field) to create the expected object with - - throws: Any error from your custom implementation, MapperError.ConvertibleError is recommended + - throws: Any error from your custom implementation, MapperError.convertibleError is recommended - returns: The successfully created value from the given input */ - @warn_unused_result - static func fromMap(value: AnyObject?) throws -> ConvertedType + static func fromMap(_ value: Any) throws -> ConvertedType } diff --git a/Sources/DefaultConvertible.swift b/Sources/DefaultConvertible.swift index bd38ce9..6fa6235 100644 --- a/Sources/DefaultConvertible.swift +++ b/Sources/DefaultConvertible.swift @@ -11,12 +11,12 @@ public protocol DefaultConvertible: Convertible {} extension DefaultConvertible { - public static func fromMap(value: AnyObject?) throws -> ConvertedType { + public static func fromMap(_ value: Any) throws -> ConvertedType { if let object = value as? ConvertedType { return object } - throw MapperError.ConvertibleError(value: value, type: ConvertedType.self) + throw MapperError.convertibleError(value: value, type: ConvertedType.self) } } diff --git a/Sources/Mappable.swift b/Sources/Mappable.swift index ec5e9d5..44f2479 100644 --- a/Sources/Mappable.swift +++ b/Sources/Mappable.swift @@ -7,14 +7,14 @@ import Foundation public struct Thing: Mappable { let string: String - let URL: NSURL? + let URL: URL? public init(map: Mapper) throws { // Attemps to convert the value for the "some_string" key to a String, if it fails // it throws an error try string = map.from("some_string") - // Attemps to convert the value for the "base_url" key to an NSURL, if it fails + // Attemps to convert the value for the "base_url" key to an URL, if it fails // it assigns URL to nil URL = map.optionalFrom("base_url") } @@ -24,9 +24,10 @@ public protocol Mappable { /** Define how your custom object is created from a Mapper object */ - @warn_unused_result init(map: Mapper) throws +} +public extension Mappable { /** Convenience method for creating Mappable objects from NSDictionaries @@ -34,8 +35,9 @@ public protocol Mappable { - returns: The object if it could be created, nil if creating the object threw an error */ - @warn_unused_result - static func from(JSON: NSDictionary) -> Self? + public static func from(_ JSON: NSDictionary) -> Self? { + return try? self.init(map: Mapper(JSON: JSON)) + } /** Convenience method for creating Mappable objects from a NSArray @@ -44,18 +46,7 @@ public protocol Mappable { - returns: An array of the created objects, or nil if creating threw */ - @warn_unused_result - static func from(JSON: NSArray) -> [Self]? -} - -public extension Mappable { - @warn_unused_result - public static func from(JSON: NSDictionary) -> Self? { - return try? self.init(map: Mapper(JSON: JSON)) - } - - @warn_unused_result - public static func from(JSON: NSArray) -> [Self]? { + public static func from(_ JSON: NSArray) -> [Self]? { if let array = JSON as? [NSDictionary] { return try? array.map { try self.init(map: Mapper(JSON: $0)) } } diff --git a/Sources/Mapper.swift b/Sources/Mapper.swift index f647a5e..c0c1f06 100644 --- a/Sources/Mapper.swift +++ b/Sources/Mapper.swift @@ -12,7 +12,6 @@ public struct Mapper { - parameter JSON: The dictionary to use for the data */ - @warn_unused_result public init(JSON: NSDictionary) { self.JSON = JSON } @@ -27,22 +26,21 @@ public struct Mapper { - parameter field: The field to retrieve from the source data, can be an empty string to return the entire data set - - throws: MapperError.MissingFieldError if the field doesn't exist - - throws: MapperError.TypeMismatchError if the value exists but doesn't match the type of the RawValue - - throws: MapperError.InvalidRawValueError if the value exists with the correct type, but the type's + - throws: MapperError.missingFieldError if the field doesn't exist + - throws: MapperError.typeMismatchError if the value exists but doesn't match the type of the RawValue + - throws: MapperError.invalidRawValueError if the value exists with the correct type, but the type's initializer fails with the passed rawValue - returns: The value for the given field, if it can be converted to the expected type T */ - @warn_unused_result - public func from(field: String) throws -> T { + public func from(_ field: String) throws -> T { let object = try self.JSONFromField(field) guard let rawValue = object as? T.RawValue else { - throw MapperError.TypeMismatchError(field: field, value: object, type: T.RawValue.self) + throw MapperError.typeMismatchError(field: field, value: object, type: T.RawValue.self) } guard let value = T(rawValue: rawValue) else { - throw MapperError.InvalidRawValueError(field: field, value: rawValue, type: T.self) + throw MapperError.invalidRawValueError(field: field, value: rawValue, type: T.self) } return value @@ -58,8 +56,7 @@ public struct Mapper { - returns: The value for the given field, if it can be converted to the expected type T otherwise nil */ - @warn_unused_result - public func optionalFrom(field: String) -> T? { + public func optionalFrom(_ field: String) -> T? { return try? self.from(field) } @@ -71,8 +68,7 @@ public struct Mapper { - returns: The first non-nil value to be produced from the array of fields, or nil if none exist */ - @warn_unused_result - public func optionalFrom(fields: [String]) -> T? { + public func optionalFrom(_ fields: [String]) -> T? { for field in fields { if let value: T = try? self.from(field) { return value @@ -94,18 +90,17 @@ public struct Mapper { - parameter field: The field to use from the source data - parameter defaultValue: The value to use if the rawValue initializer fails - - throws: MapperError.TypeMismatchError when the value for the key is not an array of AnyObject + - throws: MapperError.typeMismatchError when the value for the key is not an array of Any - throws: Any other error produced by a Convertible implementation - returns: An array of the RawRepresentable value, with all nils removed */ - @warn_unused_result - public func from(field: String, defaultValue: T? = nil) throws -> [T] + public func from(_ field: String, defaultValue: T? = nil) throws -> + [T] where T.RawValue: Convertible, T.RawValue == T.RawValue.ConvertedType { let value = try self.JSONFromField(field) - guard let array = value as? [AnyObject] else { - throw MapperError.TypeMismatchError(field: field, value: value, type: [AnyObject].self) + guard let array = value as? [Any] else { + throw MapperError.typeMismatchError(field: field, value: value, type: [Any].self) } let rawValues = try array.map { try T.RawValue.fromMap($0) } @@ -122,19 +117,18 @@ public struct Mapper { - parameter field: The field to retrieve from the source data, can be an empty string to return the entire data set - - throws: MapperError.MissingFieldError if the field doesn't exist - - throws: MapperError.TypeMismatchError if the field exists but isn't an NSDictionary + - throws: MapperError.missingFieldError if the field doesn't exist + - throws: MapperError.typeMismatchError if the field exists but isn't an NSDictionary - returns: The value for the given field, if it can be converted to the expected type T */ - @warn_unused_result - public func from(field: String) throws -> T { + public func from(_ field: String) throws -> T { let value = try self.JSONFromField(field) if let JSON = value as? NSDictionary { return try T(map: Mapper(JSON: JSON)) } - throw MapperError.TypeMismatchError(field: field, value: value, type: NSDictionary.self) + throw MapperError.typeMismatchError(field: field, value: value, type: NSDictionary.self) } /** @@ -147,20 +141,19 @@ public struct Mapper { - parameter field: The field to retrieve from the source data, can be an empty string to return the entire data set - - throws: MapperError.MissingFieldError if the field doesn't exist - - throws: MapperError.TypeMismatchError if the field exists but isn't an array of NSDictionarys + - throws: MapperError.missingFieldError if the field doesn't exist + - throws: MapperError.typeMismatchError if the field exists but isn't an array of NSDictionarys - throws: Any errors produced by the subsequent Mappable initializers - returns: The value for the given field, if it can be converted to the expected type [T] */ - @warn_unused_result - public func from(field: String) throws -> [T] { + public func from(_ field: String) throws -> [T] { let value = try self.JSONFromField(field) if let JSON = value as? [NSDictionary] { return try JSON.map { try T(map: Mapper(JSON: $0)) } } - throw MapperError.TypeMismatchError(field: field, value: value, type: [NSDictionary].self) + throw MapperError.typeMismatchError(field: field, value: value, type: [NSDictionary].self) } /** @@ -173,8 +166,7 @@ public struct Mapper { - returns: The value for the given field, if it can be converted to the expected type T otherwise nil */ - @warn_unused_result - public func optionalFrom(field: String) -> T? { + public func optionalFrom(_ field: String) -> T? { return try? self.from(field) } @@ -190,8 +182,7 @@ public struct Mapper { - returns: The value for the given field, if it can be converted to the expected type [T] */ - @warn_unused_result - public func optionalFrom(field: String) -> [T]? { + public func optionalFrom(_ field: String) -> [T]? { return try? self.from(field) } @@ -203,8 +194,7 @@ public struct Mapper { - returns: The first non-nil value to be produced from the array of fields, or nil if none exist */ - @warn_unused_result - public func optionalFrom(fields: [String]) -> T? { + public func optionalFrom(_ fields: [String]) -> T? { for field in fields { if let value: T = try? self.from(field) { return value @@ -228,8 +218,7 @@ public struct Mapper { - returns: The value for the given field, if it can be converted to the expected type T */ - @warn_unused_result - public func from(field: String) throws -> T { + public func from(_ field: String) throws -> T where T == T.ConvertedType { return try self.from(field, transformation: T.fromMap) } @@ -247,8 +236,7 @@ public struct Mapper { - returns: The value for the given field, if it can be converted to the expected type Optional */ - @warn_unused_result - public func from(field: String) throws -> T? { + public func from(_ field: String) throws -> T? where T == T.ConvertedType { return try self.from(field, transformation: T.fromMap) } @@ -260,20 +248,19 @@ public struct Mapper { - parameter field: The field to retrieve from the source data, can be an empty string to return the entire data set - - throws: MapperError.MissingFieldError if the field doesn't exist - - throws: MapperError.TypeMismatchError if the field exists but isn't an array of AnyObject + - throws: MapperError.missingFieldError if the field doesn't exist + - throws: MapperError.typeMismatchError if the field exists but isn't an array of Any - throws: Any error produced by the subsequent Convertible implementations - returns: The value for the given field, if it can be converted to the expected type [T] */ - @warn_unused_result - public func from(field: String) throws -> [T] { + public func from(_ field: String) throws -> [T] where T == T.ConvertedType { let value = try self.JSONFromField(field) - if let JSON = value as? [AnyObject] { + if let JSON = value as? [Any] { return try JSON.map(T.fromMap) } - throw MapperError.TypeMismatchError(field: field, value: value, type: [AnyObject].self) + throw MapperError.typeMismatchError(field: field, value: value, type: [Any].self) } /** @@ -286,8 +273,7 @@ public struct Mapper { - returns: The value for the given field, if it can be converted to the expected type T otherwise nil */ - @warn_unused_result - public func optionalFrom(field: String) -> T? { + public func optionalFrom(_ field: String) -> T? where T == T.ConvertedType { return try? self.from(field, transformation: T.fromMap) } @@ -301,8 +287,7 @@ public struct Mapper { - returns: The value for the given field, if it can be converted to the expected type [T] */ - @warn_unused_result - public func optionalFrom(field: String) -> [T]? { + public func optionalFrom(_ field: String) -> [T]? where T == T.ConvertedType { return try? self.from(field) } @@ -314,18 +299,17 @@ public struct Mapper { - parameter field: The field to retrieve from the source data, can be an empty string to return the entire data set - - throws: MapperError.TypeMismatchError if the value for the given field isn't a NSDictionary + - throws: MapperError.typeMismatchError if the value for the given field isn't a [AnyHashable: Any] - throws: Any error produced by the Convertible implementation of either expected type - returns: A dictionary where the keys and values are created using their convertible implementations */ - @warn_unused_result - public func from(field: String) throws -> [U: T] + public func from(_ field: String) throws -> [U: T] + where U == U.ConvertedType, T == T.ConvertedType { let object = try self.JSONFromField(field) - guard let data = object as? NSDictionary else { - throw MapperError.TypeMismatchError(field: field, value: object, type: NSDictionary.self) + guard let data = object as? [AnyHashable: Any] else { + throw MapperError.typeMismatchError(field: field, value: object, type: [AnyHashable: Any].self) } var result = [U: T]() @@ -347,9 +331,8 @@ public struct Mapper { - returns: A dictionary where the keys and values are created using their convertible implementations or nil if anything throws */ - @warn_unused_result - public func optionalFrom(field: String) -> [U: T]? + public func optionalFrom(_ field: String) -> [U: T]? + where U == U.ConvertedType, T == T.ConvertedType { return try? self.from(field) } @@ -362,8 +345,7 @@ public struct Mapper { - returns: The first non-nil value to be produced from the array of fields, or nil if none exist */ - @warn_unused_result - public func optionalFrom(fields: [String]) -> T? { + public func optionalFrom(_ fields: [String]) -> T? where T == T.ConvertedType { for field in fields { if let value: T = try? self.from(field) { return value @@ -382,14 +364,13 @@ public struct Mapper { the entire data set - parameter transformation: The transformation function used to create the expected value - - throws: MapperError.MissingFieldError if the field doesn't exist + - throws: MapperError.missingFieldError if the field doesn't exist - throws: Any exception thrown by the transformation function, if you're implementing the transformation function you should use `MapperError`, see the documentation there for more info - returns: The value of type T for the given field */ - @warn_unused_result - public func from(field: String, @noescape transformation: AnyObject? throws -> T) throws -> T { + public func from(_ field: String, transformation: (Any) throws -> T) throws -> T { return try transformation(try self.JSONFromField(field)) } @@ -403,8 +384,7 @@ public struct Mapper { - returns: The value of type T for the given field, if the transformation function doesn't throw otherwise nil */ - @warn_unused_result - public func optionalFrom(field: String, @noescape transformation: AnyObject? throws -> T?) -> T? { + public func optionalFrom(_ field: String, transformation: (Any) throws -> T?) -> T? { return (try? transformation(try? self.JSONFromField(field))).flatMap { $0 } } @@ -417,15 +397,15 @@ public struct Mapper { - parameter field: The field to extract from the data source, can be an empty string to return the entire data source - - throws: MapperError.MissingFieldError if the field doesn't exist + - throws: MapperError.missingFieldError if the field doesn't exist - returns: The object for the given field */ - private func JSONFromField(field: String) throws -> AnyObject { - if let value = field.isEmpty ? self.JSON : self.JSON.safeValueForKeyPath(field) { + private func JSONFromField(_ field: String) throws -> Any { + if let value = field.isEmpty ? self.JSON : self.JSON.safeValue(forKeyPath: field) { return value } - throw MapperError.MissingFieldError(field: field) + throw MapperError.missingFieldError(field: field) } } diff --git a/Sources/MapperError.swift b/Sources/MapperError.swift index a5ed539..75841b3 100644 --- a/Sources/MapperError.swift +++ b/Sources/MapperError.swift @@ -10,10 +10,10 @@ - MissingFieldError: An error thrown when the desired key isn't in the JSON - TypeMismatchError: Thrown when the desired key exists in the JSON, but does not match the expected type */ -public enum MapperError: ErrorType { - case ConvertibleError(value: AnyObject?, type: Any.Type) - case CustomError(field: String?, message: String) - case InvalidRawValueError(field: String, value: Any, type: Any.Type) - case MissingFieldError(field: String) - case TypeMismatchError(field: String, value: AnyObject, type: Any.Type) +public enum MapperError: Error { + case convertibleError(value: Any?, type: Any.Type) + case customError(field: String?, message: String) + case invalidRawValueError(field: String, value: Any, type: Any.Type) + case missingFieldError(field: String) + case typeMismatchError(field: String, value: Any, type: Any.Type) } diff --git a/Sources/NSDictionary+Safety.swift b/Sources/NSDictionary+Safety.swift index 3a4851a..5033525 100644 --- a/Sources/NSDictionary+Safety.swift +++ b/Sources/NSDictionary+Safety.swift @@ -1,12 +1,12 @@ import Foundation extension NSDictionary { - func safeValueForKeyPath(keyPath: String) -> AnyObject? { - var object: AnyObject? = self - var keys = keyPath.characters.split(".").map(String.init) + func safeValue(forKeyPath keyPath: String) -> Any? { + var object: Any? = self + var keys = keyPath.characters.split(separator: ".").map(String.init) while keys.count > 0, let currentObject = object { - let key = keys.removeAtIndex(0) + let key = keys.remove(at: 0) object = (currentObject as? NSDictionary)?[key] } diff --git a/Sources/NSURL+Convertible.swift b/Sources/NSURL+Convertible.swift index e4190de..7992182 100644 --- a/Sources/NSURL+Convertible.swift +++ b/Sources/NSURL+Convertible.swift @@ -1,29 +1,28 @@ import Foundation /** - NSURL Convertible implementation + URL Convertible implementation */ -extension NSURL: Convertible { +extension URL: Convertible { /** - Create a NSURL from Mapper + Create a URL from Mapper - parameter value: The object (or nil) passed from Mapper - - throws: MapperError.ConvertibleError if the passed value is not a String - - throws: MapperError.CustomError if the passed value a String but the NSURL initializer returns nil + - throws: MapperError.convertibleError if the passed value is not a String + - throws: MapperError.customError if the passed value a String but the URL initializer returns nil - - returns: The created NSURL + - returns: The created URL */ - @warn_unused_result - public static func fromMap(value: AnyObject?) throws -> NSURL { + public static func fromMap(_ value: Any) throws -> URL { guard let string = value as? String else { - throw MapperError.ConvertibleError(value: value, type: String.self) + throw MapperError.convertibleError(value: value, type: String.self) } - if let URL = NSURL(string: string) { + if let URL = URL(string: string) { return URL } - throw MapperError.CustomError(field: nil, message: "'\(string)' is not a valid NSURL") + throw MapperError.customError(field: nil, message: "'\(string)' is not a valid URL") } } diff --git a/Sources/Transform+Dictionary.swift b/Sources/Transform+Dictionary.swift index 0aab53f..b05131b 100644 --- a/Sources/Transform+Dictionary.swift +++ b/Sources/Transform+Dictionary.swift @@ -38,20 +38,19 @@ public extension Transform { - parameter key: A function to extract the key U from an instance of the Mappable object T - parameter object: The object to attempt to produce the objects and dictionary from, this is - AnyObject? to allow uses with transformations (see Mapper) + Any? to allow uses with transformations (see Mapper) - - throws: MapperError.ConvertibleError if the given object is not an array of NSDictionarys + - throws: MapperError.convertibleError if the given object is not an array of NSDictionarys - returns: A dictionary of [U: T] where the keys U are produced from the passed `key` function and the values T are the objects */ - @warn_unused_result - public static func toDictionary(key getKey: T -> U) -> - (object: AnyObject?) throws -> [U: T] + public static func toDictionary(key getKey: @escaping (T) -> U) -> + (_ object: Any) throws -> [U: T] where T: Mappable, U: Hashable { return { object in guard let objects = object as? [NSDictionary] else { - throw MapperError.ConvertibleError(value: object, type: [NSDictionary].self) + throw MapperError.convertibleError(value: object, type: [NSDictionary].self) } var dictionary: [U: T] = [:] diff --git a/Tests/MapperTests/ConvertibleValueTests.swift b/Tests/MapperTests/ConvertibleValueTests.swift index 539c0cd..cdbdd78 100644 --- a/Tests/MapperTests/ConvertibleValueTests.swift +++ b/Tests/MapperTests/ConvertibleValueTests.swift @@ -2,7 +2,7 @@ import Mapper import XCTest private struct Foo: Convertible { - static func fromMap(value: AnyObject?) throws -> Foo { + static func fromMap(_ value: Any) throws -> Foo { return Foo() } } @@ -10,7 +10,7 @@ private struct Foo: Convertible { final class ConvertibleValueTests: XCTestCase { func testCreatingURL() { struct Test: Mappable { - let URL: NSURL + let URL: URL init(map: Mapper) throws { try self.URL = map.from("url") } @@ -22,7 +22,7 @@ final class ConvertibleValueTests: XCTestCase { func testOptionalURL() { struct Test: Mappable { - let URL: NSURL? + let URL: URL? init(map: Mapper) { self.URL = map.optionalFrom("url") } @@ -34,7 +34,7 @@ final class ConvertibleValueTests: XCTestCase { func testInvalidURL() { struct Test: Mappable { - let URL: NSURL? + let URL: URL? init(map: Mapper) { self.URL = map.optionalFrom("url") } @@ -46,7 +46,7 @@ final class ConvertibleValueTests: XCTestCase { func testArrayOfConvertibles() { struct Test: Mappable { - let URLs: [NSURL] + let URLs: [URL] init(map: Mapper) throws { try self.URLs = map.from("urls") } @@ -58,7 +58,7 @@ final class ConvertibleValueTests: XCTestCase { func testOptionalArrayOfConvertibles() { struct Test: Mappable { - let URLs: [NSURL]? + let URLs: [URL]? init(map: Mapper) { self.URLs = map.optionalFrom("urls") } @@ -70,7 +70,7 @@ final class ConvertibleValueTests: XCTestCase { func testExistingOptionalArrayOfConvertibles() { struct Test: Mappable { - let URLs: [NSURL]? + let URLs: [URL]? init(map: Mapper) { self.URLs = map.optionalFrom("urls") } @@ -82,7 +82,7 @@ final class ConvertibleValueTests: XCTestCase { func testInvalidArrayOfConvertibles() { struct Test: Mappable { - let URLs: [NSURL] + let URLs: [URL] init(map: Mapper) throws { try self.URLs = map.from("urls") } @@ -94,7 +94,7 @@ final class ConvertibleValueTests: XCTestCase { func testInvalidArrayOfOptionalConvertibles() { struct Test: Mappable { - let URLs: [NSURL]? + let URLs: [URL]? init(map: Mapper) { self.URLs = map.optionalFrom("urls") } @@ -106,7 +106,7 @@ final class ConvertibleValueTests: XCTestCase { func testConvertibleArrayOfKeys() { struct Test: Mappable { - let URL: NSURL? + let URL: URL? init(map: Mapper) { self.URL = map.optionalFrom(["a", "b"]) } @@ -118,7 +118,7 @@ final class ConvertibleValueTests: XCTestCase { func testConvertibleArrayOfKeysReturnsNil() { struct Test: Mappable { - let URL: NSURL? + let URL: URL? init(map: Mapper) { self.URL = map.optionalFrom(["a", "b"]) } @@ -163,8 +163,12 @@ final class ConvertibleValueTests: XCTestCase { } } - let test = Test.from(["foo": ["key": "value"]]) - XCTAssertTrue(test?.dictionary.count > 0) + do { + let test = try Test(map: Mapper(JSON: ["foo": ["key": "value"]])) + XCTAssertTrue(test.dictionary.count > 0) + } catch { + XCTFail("Failed to create test") + } } func testOptionalDictionaryConvertibleNil() { diff --git a/Tests/MapperTests/CustomTransformationTests.swift b/Tests/MapperTests/CustomTransformationTests.swift index fde32f4..284fd7f 100644 --- a/Tests/MapperTests/CustomTransformationTests.swift +++ b/Tests/MapperTests/CustomTransformationTests.swift @@ -25,7 +25,7 @@ final class CustomTransformationTests: XCTestCase { let value: Int init(map: Mapper) throws { try value = map.from("foo", transformation: { object in - throw MapperError.CustomError(field: nil, message: "") + throw MapperError.customError(field: nil, message: "") }) } } @@ -63,7 +63,7 @@ final class CustomTransformationTests: XCTestCase { let string: String? init(map: Mapper) throws { string = map.optionalFrom("foo", transformation: { _ in - throw MapperError.CustomError(field: nil, message: "") + throw MapperError.customError(field: nil, message: "") }) } } diff --git a/Tests/MapperTests/ErrorTests.swift b/Tests/MapperTests/ErrorTests.swift index b415f0e..8d6d441 100644 --- a/Tests/MapperTests/ErrorTests.swift +++ b/Tests/MapperTests/ErrorTests.swift @@ -11,7 +11,7 @@ final class ErrorTests: XCTestCase { let map = Mapper(JSON: ["field": 1]) let _: Test = try map.from("field") XCTFail() - } catch MapperError.TypeMismatchError(let field, let value, let type) { + } catch MapperError.typeMismatchError(let field, let value, let type) { XCTAssert(field == "field") XCTAssert(value as? Int == 1) XCTAssert(type == NSDictionary.self) @@ -29,7 +29,7 @@ final class ErrorTests: XCTestCase { let map = Mapper(JSON: ["suit": "hearts"]) let _: Suit = try map.from("suit") XCTFail() - } catch MapperError.InvalidRawValueError(let field, let value, let type) { + } catch MapperError.invalidRawValueError(let field, let value, let type) { XCTAssert(field == "suit") XCTAssert(value as? String == "hearts") XCTAssert(type == Suit.self) @@ -41,9 +41,9 @@ final class ErrorTests: XCTestCase { func testConvertibleError() { do { let map = Mapper(JSON: ["url": 1]) - let _: NSURL = try map.from("url") + let _: URL = try map.from("url") XCTFail() - } catch MapperError.ConvertibleError(let value, let type) { + } catch MapperError.convertibleError(let value, let type) { XCTAssert(value as? Int == 1) XCTAssert(type == String.self) } catch { @@ -56,7 +56,7 @@ final class ErrorTests: XCTestCase { let map = Mapper(JSON: [:]) let _: String = try map.from("string") XCTFail() - } catch MapperError.MissingFieldError(let field) { + } catch MapperError.missingFieldError(let field) { XCTAssert(field == "string") } catch { XCTFail() @@ -67,11 +67,11 @@ final class ErrorTests: XCTestCase { do { let map = Mapper(JSON: ["string": "hi"]) _ = try map.from("string", transformation: { _ in - throw MapperError.CustomError(field: "string", message: "hi") + throw MapperError.customError(field: "string", message: "hi") }) XCTFail() - } catch MapperError.CustomError(let field, let message) { + } catch MapperError.customError(let field, let message) { XCTAssert(field == "string") XCTAssert(message == "hi") } catch { diff --git a/Tests/MapperTests/NormalValueTests.swift b/Tests/MapperTests/NormalValueTests.swift index 9880639..d09ab65 100644 --- a/Tests/MapperTests/NormalValueTests.swift +++ b/Tests/MapperTests/NormalValueTests.swift @@ -16,7 +16,7 @@ final class NormalValueTests: XCTestCase { func testMappingTimeInterval() { struct Test: Mappable { - let string: NSTimeInterval + let string: TimeInterval init(map: Mapper) throws { try self.string = map.from("time") } @@ -71,7 +71,7 @@ final class NormalValueTests: XCTestCase { } let JSON = ["a": "b", "c": "d"] - let test = try? Test(map: Mapper(JSON: JSON)) + let test = try? Test(map: Mapper(JSON: JSON as NSDictionary)) let parsedJSON = test?.JSON as? [String: String] ?? [:] XCTAssertTrue(parsedJSON == JSON) } diff --git a/Tests/MapperTests/RawRepresentibleValueTests.swift b/Tests/MapperTests/RawRepresentibleValueTests.swift index 25d4b5a..1144105 100644 --- a/Tests/MapperTests/RawRepresentibleValueTests.swift +++ b/Tests/MapperTests/RawRepresentibleValueTests.swift @@ -27,11 +27,11 @@ final class RawRepresentibleValueTests: XCTestCase { } enum Value: Int { - case First = 1 + case first = 1 } let test = try? Test(map: Mapper(JSON: ["value": 1])) - XCTAssertTrue(test?.value == .First) + XCTAssertTrue(test?.value == .first) } func testMissingRawRepresentableNumber() { @@ -43,7 +43,7 @@ final class RawRepresentibleValueTests: XCTestCase { } enum Value: Int { - case First = 1 + case first = 1 } let test = try? Test(map: Mapper(JSON: [:])) @@ -59,7 +59,7 @@ final class RawRepresentibleValueTests: XCTestCase { } enum Value: Int { - case First = 1 + case first = 1 } let test = Test(map: Mapper(JSON: [:])) @@ -75,11 +75,11 @@ final class RawRepresentibleValueTests: XCTestCase { } enum Value: Int { - case First = 1 + case first = 1 } let test = Test(map: Mapper(JSON: ["value": 1])) - XCTAssertTrue(test.value == .First) + XCTAssertTrue(test.value == .first) } func testRawRepresentableTypeMismatch() { @@ -91,7 +91,7 @@ final class RawRepresentibleValueTests: XCTestCase { } enum Value: Int { - case First = 1 + case first = 1 } let test = Test(map: Mapper(JSON: ["value": "not an int"])) @@ -145,7 +145,7 @@ final class RawRepresentibleValueTests: XCTestCase { do { _ = try Test(map: Mapper(JSON: [:])) XCTFail("Expected initialization to fail") - } catch MapperError.MissingFieldError(let field) { + } catch MapperError.missingFieldError(let field) { XCTAssertEqual(field, "a") } catch let error { XCTFail("Expected only missing field error, got \(error)") @@ -167,10 +167,10 @@ final class RawRepresentibleValueTests: XCTestCase { do { _ = try Test(map: Mapper(JSON: ["a": 1])) XCTFail("Expected initialization to fail") - } catch MapperError.TypeMismatchError(let field, let value, let type) { + } catch MapperError.typeMismatchError(let field, let value, let type) { XCTAssertEqual(field, "a") XCTAssertEqual(value as? Int, 1) - XCTAssert(type == [AnyObject].self) + XCTAssert(type == [Any].self) } catch let error { XCTFail("Expected only missing field error, got \(error)") } @@ -191,7 +191,7 @@ final class RawRepresentibleValueTests: XCTestCase { do { _ = try Test(map: Mapper(JSON: ["a": [1]])) XCTFail("Expected initialization to fail") - } catch MapperError.ConvertibleError(let value, let type) { + } catch MapperError.convertibleError(let value, let type) { XCTAssertEqual(value as? Int, 1) XCTAssert(type == String.self) } catch let error { diff --git a/Tests/MapperTests/TransformTests.swift b/Tests/MapperTests/TransformTests.swift index 26a7e1b..af5b3af 100644 --- a/Tests/MapperTests/TransformTests.swift +++ b/Tests/MapperTests/TransformTests.swift @@ -31,7 +31,7 @@ final class TransformTests: XCTestCase { } } - let JSON = [ + let JSON: NSDictionary = [ "examples": [ [ @@ -64,7 +64,7 @@ final class TransformTests: XCTestCase { do { _ = try Test(map: Mapper(JSON: ["examples": 1])) XCTFail() - } catch MapperError.ConvertibleError(let value, let type) { + } catch MapperError.convertibleError(let value, let type) { XCTAssert(value as? Int == 1) XCTAssert(type == [NSDictionary].self) } catch { @@ -82,7 +82,7 @@ final class TransformTests: XCTestCase { } } - let JSON = [ + let JSON: NSDictionary = [ "examples": [ [ @@ -104,7 +104,7 @@ final class TransformTests: XCTestCase { let map = Mapper(JSON: [:]) let _: String = try map.from("foo", transformation: { _ in return "hi" }) XCTFail() - } catch MapperError.MissingFieldError(let field) { + } catch MapperError.missingFieldError(let field) { XCTAssert(field == "foo") } catch { XCTFail()