diff --git a/Argo.xcodeproj/project.pbxproj b/Argo.xcodeproj/project.pbxproj index e517d3e..ec22e15 100644 --- a/Argo.xcodeproj/project.pbxproj +++ b/Argo.xcodeproj/project.pbxproj @@ -11,7 +11,7 @@ 4D5F6DDA1B3832C200D79B25 /* user_with_nested_name.json in Resources */ = {isa = PBXBuildFile; fileRef = 4D5F6DD81B3832C200D79B25 /* user_with_nested_name.json */; }; 809754CB1BADF34200C409E6 /* Argo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 809754C11BADF34100C409E6 /* Argo.framework */; }; 809754D81BADF36D00C409E6 /* Decoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69E1ABC5F1300E3B0AB /* Decoded.swift */; }; - 809754D91BADF36D00C409E6 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69F1ABC5F1300E3B0AB /* JSON.swift */; }; + 809754D91BADF36D00C409E6 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69F1ABC5F1300E3B0AB /* Value.swift */; }; 809754DA1BADF36D00C409E6 /* Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A01ABC5F1300E3B0AB /* Decodable.swift */; }; 809754DB1BADF36D00C409E6 /* StandardTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A11ABC5F1300E3B0AB /* StandardTypes.swift */; }; 809754DC1BADF36D00C409E6 /* DecodeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84318A71B9A2D7A00165216 /* DecodeError.swift */; }; @@ -59,7 +59,7 @@ 8097550A1BADF3F200C409E6 /* types.plist in Resources */ = {isa = PBXBuildFile; fileRef = EABDF68E1A9CD4EA00B6CC83 /* types.plist */; }; BF92789D1B9365900038A7E1 /* RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF92789C1B9365900038A7E1 /* RawRepresentable.swift */; }; D0592EBE1B77DD8E00EFEF39 /* Decoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69E1ABC5F1300E3B0AB /* Decoded.swift */; }; - D0592EBF1B77DD8E00EFEF39 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69F1ABC5F1300E3B0AB /* JSON.swift */; }; + D0592EBF1B77DD8E00EFEF39 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69F1ABC5F1300E3B0AB /* Value.swift */; }; D0592EC01B77DD8E00EFEF39 /* Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A01ABC5F1300E3B0AB /* Decodable.swift */; }; D0592EC11B77DD8E00EFEF39 /* StandardTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A11ABC5F1300E3B0AB /* StandardTypes.swift */; }; D0592EC51B77DD9A00EFEF39 /* decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69A1ABC5F1300E3B0AB /* decode.swift */; }; @@ -160,6 +160,10 @@ F862E0AE1A519D5C0093B028 /* types_fail_embedded.json in Resources */ = {isa = PBXBuildFile; fileRef = EA4EAF7219DD96330036AE0D /* types_fail_embedded.json */; }; F874B7EA1A66BF52004CCE5E /* root_array.json in Resources */ = {isa = PBXBuildFile; fileRef = F874B7E91A66BF52004CCE5E /* root_array.json */; }; F874B7EB1A66C221004CCE5E /* root_array.json in Resources */ = {isa = PBXBuildFile; fileRef = F874B7E91A66BF52004CCE5E /* root_array.json */; }; + F874DE8F1F7FFDE600D885C3 /* Deprecations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F874DE8E1F7FFDE600D885C3 /* Deprecations.swift */; }; + F874DE901F7FFDE600D885C3 /* Deprecations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F874DE8E1F7FFDE600D885C3 /* Deprecations.swift */; }; + F874DE911F7FFDE600D885C3 /* Deprecations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F874DE8E1F7FFDE600D885C3 /* Deprecations.swift */; }; + F874DE921F7FFDE600D885C3 /* Deprecations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F874DE8E1F7FFDE600D885C3 /* Deprecations.swift */; }; F87897EF1A927864009316A5 /* Argo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAD9FACF19D0EAB50031E006 /* Argo.framework */; }; F87EB6A41ABC5F1300E3B0AB /* decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69A1ABC5F1300E3B0AB /* decode.swift */; }; F87EB6A51ABC5F1300E3B0AB /* decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69A1ABC5F1300E3B0AB /* decode.swift */; }; @@ -169,8 +173,8 @@ F87EB6A91ABC5F1300E3B0AB /* sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69C1ABC5F1300E3B0AB /* sequence.swift */; }; F87EB6AA1ABC5F1300E3B0AB /* Decoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69E1ABC5F1300E3B0AB /* Decoded.swift */; }; F87EB6AB1ABC5F1300E3B0AB /* Decoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69E1ABC5F1300E3B0AB /* Decoded.swift */; }; - F87EB6AC1ABC5F1300E3B0AB /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69F1ABC5F1300E3B0AB /* JSON.swift */; }; - F87EB6AD1ABC5F1300E3B0AB /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69F1ABC5F1300E3B0AB /* JSON.swift */; }; + F87EB6AC1ABC5F1300E3B0AB /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69F1ABC5F1300E3B0AB /* Value.swift */; }; + F87EB6AD1ABC5F1300E3B0AB /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69F1ABC5F1300E3B0AB /* Value.swift */; }; F87EB6AE1ABC5F1300E3B0AB /* Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A01ABC5F1300E3B0AB /* Decodable.swift */; }; F87EB6AF1ABC5F1300E3B0AB /* Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A01ABC5F1300E3B0AB /* Decodable.swift */; }; F87EB6B01ABC5F1300E3B0AB /* StandardTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A11ABC5F1300E3B0AB /* StandardTypes.swift */; }; @@ -329,11 +333,12 @@ F85F93431D42C8D6001C8EA7 /* Curry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Curry.framework; path = Carthage/Checkouts/Curry/build/Debug/Curry.framework; sourceTree = ""; }; F85F93451D42C8DD001C8EA7 /* Curry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Curry.framework; path = "Carthage/Checkouts/Curry/build/Debug-appletvos/Curry.framework"; sourceTree = ""; }; F874B7E91A66BF52004CCE5E /* root_array.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = root_array.json; sourceTree = ""; }; + F874DE8E1F7FFDE600D885C3 /* Deprecations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deprecations.swift; sourceTree = ""; }; F87EB69A1ABC5F1300E3B0AB /* decode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = decode.swift; sourceTree = ""; }; F87EB69B1ABC5F1300E3B0AB /* flatReduce.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = flatReduce.swift; sourceTree = ""; }; F87EB69C1ABC5F1300E3B0AB /* sequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = sequence.swift; sourceTree = ""; }; F87EB69E1ABC5F1300E3B0AB /* Decoded.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decoded.swift; sourceTree = ""; }; - F87EB69F1ABC5F1300E3B0AB /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = ""; }; + F87EB69F1ABC5F1300E3B0AB /* Value.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Value.swift; sourceTree = ""; }; F87EB6A01ABC5F1300E3B0AB /* Decodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decodable.swift; sourceTree = ""; }; F87EB6A11ABC5F1300E3B0AB /* StandardTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StandardTypes.swift; sourceTree = ""; }; F89335541A4CE83000B88685 /* Argo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Argo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -469,6 +474,7 @@ F87EB69D1ABC5F1300E3B0AB /* Types */, F87EB6981ABC5F1300E3B0AB /* Functions */, F8CBE6651A6451F800316FBC /* Extensions */, + F874DE8E1F7FFDE600D885C3 /* Deprecations.swift */, ); name = Argo; path = Sources/Argo; @@ -569,7 +575,7 @@ isa = PBXGroup; children = ( EA04D5A81BBF43C7001DE23B /* Decoded */, - F87EB69F1ABC5F1300E3B0AB /* JSON.swift */, + F87EB69F1ABC5F1300E3B0AB /* Value.swift */, F87EB6A01ABC5F1300E3B0AB /* Decodable.swift */, F87EB6A11ABC5F1300E3B0AB /* StandardTypes.swift */, F84318A71B9A2D7A00165216 /* DecodeError.swift */, @@ -964,6 +970,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F874DE921F7FFDE600D885C3 /* Deprecations.swift in Sources */, EA9159F81BDE74E400D85292 /* Monad.swift in Sources */, 809754DF1BADF36D00C409E6 /* (null) in Sources */, EA9159F71BDE74C700D85292 /* catDecoded.swift in Sources */, @@ -979,7 +986,7 @@ EA9159FA1BDE74F300D85292 /* Applicative.swift in Sources */, 809754E51BADF36D00C409E6 /* Dictionary.swift in Sources */, 809754E61BADF36D00C409E6 /* RawRepresentable.swift in Sources */, - 809754D91BADF36D00C409E6 /* JSON.swift in Sources */, + 809754D91BADF36D00C409E6 /* Value.swift in Sources */, F8C2561C1C3C855C00B70968 /* NSNumber.swift in Sources */, EA9159FB1BDE74F800D85292 /* Alternative.swift in Sources */, ); @@ -1017,6 +1024,7 @@ files = ( EA04D59B1BBF1FA4001DE23B /* Applicative.swift in Sources */, D0592EC11B77DD8E00EFEF39 /* StandardTypes.swift in Sources */, + F874DE911F7FFDE600D885C3 /* Deprecations.swift in Sources */, EA04D59F1BBF1FB9001DE23B /* Alternative.swift in Sources */, D0592EC01B77DD8E00EFEF39 /* Decodable.swift in Sources */, D0592EC51B77DD9A00EFEF39 /* decode.swift in Sources */, @@ -1025,7 +1033,7 @@ EA04D5A31BBF2021001DE23B /* FailureCoalescing.swift in Sources */, D0592EBE1B77DD8E00EFEF39 /* Decoded.swift in Sources */, F84318AA1B9A2D7A00165216 /* DecodeError.swift in Sources */, - D0592EBF1B77DD8E00EFEF39 /* JSON.swift in Sources */, + D0592EBF1B77DD8E00EFEF39 /* Value.swift in Sources */, F8EF43311BBC729F001886BA /* catDecoded.swift in Sources */, EA1200CE1BAB621C006DDBD8 /* RawRepresentable.swift in Sources */, EA04D5931BBF1F40001DE23B /* Monad.swift in Sources */, @@ -1041,12 +1049,13 @@ files = ( F87EB6AA1ABC5F1300E3B0AB /* Decoded.swift in Sources */, EA04D5991BBF1FA4001DE23B /* Applicative.swift in Sources */, + F874DE8F1F7FFDE600D885C3 /* Deprecations.swift in Sources */, BF92789D1B9365900038A7E1 /* RawRepresentable.swift in Sources */, EA04D59D1BBF1FB9001DE23B /* Alternative.swift in Sources */, F87EB6AE1ABC5F1300E3B0AB /* Decodable.swift in Sources */, F87EB6A41ABC5F1300E3B0AB /* decode.swift in Sources */, F82D15F31C3C82730079FFB5 /* NSNumber.swift in Sources */, - F87EB6AC1ABC5F1300E3B0AB /* JSON.swift in Sources */, + F87EB6AC1ABC5F1300E3B0AB /* Value.swift in Sources */, EA04D5A11BBF2021001DE23B /* FailureCoalescing.swift in Sources */, F87EB6A61ABC5F1300E3B0AB /* flatReduce.swift in Sources */, F87EB6A81ABC5F1300E3B0AB /* sequence.swift in Sources */, @@ -1091,10 +1100,11 @@ files = ( F87EB6AB1ABC5F1300E3B0AB /* Decoded.swift in Sources */, EA04D59A1BBF1FA4001DE23B /* Applicative.swift in Sources */, + F874DE901F7FFDE600D885C3 /* Deprecations.swift in Sources */, F87EB6AF1ABC5F1300E3B0AB /* Decodable.swift in Sources */, EA04D59E1BBF1FB9001DE23B /* Alternative.swift in Sources */, F87EB6A51ABC5F1300E3B0AB /* decode.swift in Sources */, - F87EB6AD1ABC5F1300E3B0AB /* JSON.swift in Sources */, + F87EB6AD1ABC5F1300E3B0AB /* Value.swift in Sources */, F8C2561A1C3C855B00B70968 /* NSNumber.swift in Sources */, F87EB6A71ABC5F1300E3B0AB /* flatReduce.swift in Sources */, EA04D5A21BBF2021001DE23B /* FailureCoalescing.swift in Sources */, diff --git a/Documentation/Curry-Limitations.md b/Documentation/Curry-Limitations.md index 2e999dc..a16e25f 100644 --- a/Documentation/Curry-Limitations.md +++ b/Documentation/Curry-Limitations.md @@ -25,14 +25,14 @@ struct User: Decodable { let mediumAvatar: String let largeAvatar: String - static func decode(j: JSON) -> Decoded { + static func decode(v: Value) -> Decoded { return curry(User.init) - <^> j <| "id" - <*> j <| "name" - <*> j <| "bio" - <*> j <| "small_avatar" - <*> j <| "medium_avatar" - <*> j <| "large_avatar" + <^> v <| "id" + <*> v <| "name" + <*> v <| "bio" + <*> v <| "small_avatar" + <*> v <| "medium_avatar" + <*> v <| "large_avatar" } } ``` @@ -59,7 +59,7 @@ struct Avatar { Now `User.init` has 4 arguments and `Avatar.init` has 3 arguments, so we are within the assumed limitations of `curry`. But, it is also less clear how we -should write `User.decode`. How can we extract the 3 avatar fields from `JSON` +should write `User.decode`. How can we extract the 3 avatar fields from `Value` to build `Avatar` first, and then use that to build `User`? The key insight is to see that `j <| "key"` returns a `Decoded` value, representing one step of decoding. So, we can decode a `Avatar` first using `j`, and then plug that @@ -67,21 +67,21 @@ directly into `curry(User.init)`: ```swift extension Avatar: Decodable { - static func decode(j: JSON) -> Decoded { + static func decode(v: Value) -> Decoded { return curry(Avatar.init) - <^> j <| "small_avatar" - <*> j <| "medium_avatar" - <*> j <| "large_avatar" + <^> v <| "small_avatar" + <*> v <| "medium_avatar" + <*> v <| "large_avatar" } } extension User: Decodable { - static func decode(j: JSON) -> Decoded { + static func decode(v: Value) -> Decoded { return curry(User.init) - <^> j <| "id" - <*> j <| "name" - <*> j <| "bio" - <*> Avatar.decode(j) + <^> v <| "id" + <*> v <| "name" + <*> v <| "bio" + <*> Avatar.decode(v) } } ``` diff --git a/Documentation/Decode-Enums.md b/Documentation/Decode-Enums.md index dc28d9b..a91602c 100644 --- a/Documentation/Decode-Enums.md +++ b/Documentation/Decode-Enums.md @@ -44,7 +44,7 @@ We can write `Decodable` for `FootRace` like so: ```swift extension FootRace: Decodable { - static func decode(j: JSON) -> Decoded { + static func decode(j: Value) -> Decoded { switch j { // First, make sure JSON is a number. diff --git a/Sources/Argo/Deprecations.swift b/Sources/Argo/Deprecations.swift new file mode 100644 index 0000000..2dc10ed --- /dev/null +++ b/Sources/Argo/Deprecations.swift @@ -0,0 +1,2 @@ +@available(*, deprecated, renamed: "Value") +public typealias JSON = Value diff --git a/Sources/Argo/Extensions/RawRepresentable.swift b/Sources/Argo/Extensions/RawRepresentable.swift index 4960c93..3635ad8 100644 --- a/Sources/Argo/Extensions/RawRepresentable.swift +++ b/Sources/Argo/Extensions/RawRepresentable.swift @@ -3,13 +3,13 @@ `String` as the raw value. */ public extension Decodable where Self.DecodedType == Self, Self: RawRepresentable, Self.RawValue == String { - static func decode(_ json: JSON) -> Decoded { - switch json { + static func decode(_ value: Value) -> Decoded { + switch value { case let .string(s): return self.init(rawValue: s) - .map(pure) ?? .typeMismatch(expected: "rawValue for \(self)", actual: json) + .map(pure) ?? .typeMismatch(expected: "rawValue for \(self)", actual: value) default: - return .typeMismatch(expected: "String", actual: json) + return .typeMismatch(expected: "String", actual: value) } } } @@ -19,13 +19,13 @@ public extension Decodable where Self.DecodedType == Self, Self: RawRepresentabl `Int` as the raw value. */ public extension Decodable where Self.DecodedType == Self, Self: RawRepresentable, Self.RawValue == Int { - static func decode(_ json: JSON) -> Decoded { - switch json { + static func decode(_ value: Value) -> Decoded { + switch value { case let .number(n): return self.init(rawValue: n.intValue) - .map(pure) ?? .typeMismatch(expected: "rawValue for \(self)", actual: json) + .map(pure) ?? .typeMismatch(expected: "rawValue for \(self)", actual: value) default: - return .typeMismatch(expected: "Int", actual: json) + return .typeMismatch(expected: "Int", actual: value) } } } diff --git a/Sources/Argo/Functions/decode.swift b/Sources/Argo/Functions/decode.swift index 1822f90..7e2b0ed 100644 --- a/Sources/Argo/Functions/decode.swift +++ b/Sources/Argo/Functions/decode.swift @@ -22,7 +22,7 @@ - returns: A `Decoded` value where `T` is `Decodable` */ public func decode(_ object: Any) -> Decoded where T == T.DecodedType { - return T.decode(JSON(object)) + return T.decode(Value(object)) } /** @@ -56,7 +56,7 @@ public func decode(_ object: Any) -> T? where T == T.DecodedType { Attempt to transform `Any` into a `Decodable` value using a specified root key. - This function attempts to extract the embedded `JSON` object from the + This function attempts to extract the embedded `Value` object from the dictionary at the specified key and transform it into a `Decodable` value. This works based on the type you ask for. @@ -79,14 +79,14 @@ public func decode(_ object: Any) -> T? where T == T.DecodedType { - returns: A `Decoded` value where `T` is `Decodable` */ public func decode(_ dict: [String: Any], rootKey: String) -> Decoded where T == T.DecodedType { - return JSON(dict as Any)[rootKey] + return Value(dict as Any)[rootKey] } /** Attempt to transform `Any` into a `Decodable` value using a specified root key and return an `Optional`. - This function attempts to extract the embedded `JSON` object from the + This function attempts to extract the embedded `Value` object from the dictionary at the specified key and transform it into a `Decodable` value, returning an `Optional`. This works based on the type you ask for. diff --git a/Sources/Argo/Types/Decodable.swift b/Sources/Argo/Types/Decodable.swift index 0569ca4..225ad21 100644 --- a/Sources/Argo/Types/Decodable.swift +++ b/Sources/Argo/Types/Decodable.swift @@ -20,15 +20,15 @@ public protocol Decodable { associatedtype DecodedType = Self /** - Decode an object from JSON. + Decode an object from Value. This is the main entry point for Argo. This function declares how the - conforming type should be decoded from JSON. Since this is a failable + conforming type should be decoded from Value. Since this is a failable operation, we need to return a `Decoded` type from this function. - - parameter json: The `JSON` representation of this object + - parameter value: The `Value` representation of this object - returns: A decoded instance of the `DecodedType` */ - static func decode(_ json: JSON) -> Decoded + static func decode(_ value: Value) -> Decoded } diff --git a/Sources/Argo/Types/DecodeError.swift b/Sources/Argo/Types/DecodeError.swift index 53ebd13..7138628 100644 --- a/Sources/Argo/Types/DecodeError.swift +++ b/Sources/Argo/Types/DecodeError.swift @@ -3,13 +3,13 @@ public enum DecodeError: Error { /// The type existing at the key didn't match the type being requested. case typeMismatch(expected: String, actual: String) - /// The key did not exist in the JSON. + /// The key did not exist in the Value. case missingKey(String) /// A custom error case for adding explicit failure info. case custom(String) - /// There were multiple errors in the JSON. + /// There were multiple errors in the Value. case multiple([DecodeError]) } diff --git a/Sources/Argo/Types/JSON.swift b/Sources/Argo/Types/JSON.swift deleted file mode 100644 index e7087ba..0000000 --- a/Sources/Argo/Types/JSON.swift +++ /dev/null @@ -1,145 +0,0 @@ -import Foundation - -/// A type safe representation of JSON. -public enum JSON { - case object([String: JSON]) - case array([JSON]) - case string(String) - case number(NSNumber) - case bool(Bool) - case null -} - -public extension JSON { - /** - Transform an `Any` instance into `JSON`. - - This is used to move from a loosely typed object (like those returned from - `NSJSONSerialization`) to the strongly typed `JSON` tree structure. - - - parameter json: A loosely typed object - */ - init(_ json: Any) { - switch json { - - case let v as [Any]: - self = .array(v.map(JSON.init)) - - case let v as [String: Any]: - self = .object(v.map(JSON.init)) - - case let v as String: - self = .string(v) - - case let v as NSNumber: - if v.isBool { - self = .bool(v.boolValue) - } else { - self = .number(v) - } - - default: - self = .null - } - } -} - -extension JSON { - /** - Attempt to extract a value at the specified key path and transform it into - the requested type. - - This method is used to decode a mandatory value from the `JSON`. If the - decoding fails for any reason, this will result in a `.Failure` being - returned. - - - parameter keyPath: The key path for the object to decode, represented by - a variadic list of strings. - - - returns: A `Decoded` value representing the success or failure of the - decode operation - */ - public subscript(keyPath: String...) -> Decoded where T == T.DecodedType { - return flatReduce(keyPath, initial: self, combine: decodedJSON) - .flatMap(T.decode) - } - - /** - Attempt to extract an optional value at the specified key path and - transform it into the requested type. - - This method is used to decode an optional value from the `JSON`. If any of - the keys in the key path aren't present in the `JSON`, this will still return - `.success`. However, if the key path exists but the object assigned to the - final key is unable to be decoded into the requested type, this will return - `.failure`. - - - parameter keyPath: The key path for the object to decode, represented by - a variadic list of strings. - - returns: A `Decoded` optional value representing the success or failure - of the decode operation - */ - public subscript(optional keyPath: String...) -> Decoded where T == T.DecodedType { - switch flatReduce(keyPath, initial: self, combine: decodedJSON) { - case .failure: - return .success(.none) - - case let .success(x): - return T.decode(x) - .flatMap { .success(.some($0)) } - } - } -} - -extension JSON: Decodable { - /** - Decode `JSON` into `Decoded`. - - This simply wraps the provided `JSON` in `.Success`. This is useful because - it means we can use `JSON` values with the `<|` family of operators to pull - out sub-keys. - - - parameter json: The `JSON` value to decode - - - returns: The provided `JSON` wrapped in `.Success` - */ - public static func decode(_ json: JSON) -> Decoded { - return pure(json) - } -} - -extension JSON: CustomStringConvertible { - public var description: String { - switch self { - case let .string(v): return "String(\(v))" - case let .number(v): return "Number(\(v))" - case let .bool(v): return "Bool(\(v))" - case let .array(a): return "Array(\(a.description))" - case let .object(o): return "Object(\(o.description))" - case .null: return "Null" - } - } -} - -extension JSON: Equatable { } - -public func == (lhs: JSON, rhs: JSON) -> Bool { - switch (lhs, rhs) { - case let (.string(l), .string(r)): return l == r - case let (.number(l), .number(r)): return l == r - case let (.bool(l), .bool(r)): return l == r - case let (.array(l), .array(r)): return l == r - case let (.object(l), .object(r)): return l == r - case (.null, .null): return true - default: return false - } -} - -/// MARK: Deprecations - -extension JSON { - @available(*, deprecated: 3.0, renamed: "init") - static func parse(_ json: Any) -> JSON { - return JSON(json) - } -} diff --git a/Sources/Argo/Types/StandardTypes.swift b/Sources/Argo/Types/StandardTypes.swift index db276f8..b70491e 100644 --- a/Sources/Argo/Types/StandardTypes.swift +++ b/Sources/Argo/Types/StandardTypes.swift @@ -3,257 +3,257 @@ import Runes extension String: Decodable { /** - Decode `JSON` into `Decoded`. + Decode `Value` into `Decoded`. Succeeds if the value is a string, otherwise it returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded `String` value */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case let .string(s): return pure(s) - default: return .typeMismatch(expected: "String", actual: json) + default: return .typeMismatch(expected: "String", actual: value) } } } extension Int: Decodable { /** - Decode `JSON` into `Decoded`. + Decode `Value` into `Decoded`. Succeeds if the value is a number that can be converted to an `Int`, otherwise it returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded `Int` value */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case let .number(n): return pure(n.intValue) - default: return .typeMismatch(expected: "Int", actual: json) + default: return .typeMismatch(expected: "Int", actual: value) } } } extension UInt: Decodable { /** - Decode `JSON` into `Decoded`. + Decode `Value` into `Decoded`. Succeeds if the value is a number that can be converted to a `UInt`, otherwise it returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded `UInt` value */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case let .number(n): return pure(n.uintValue) - default: return .typeMismatch(expected: "UInt", actual: json) + default: return .typeMismatch(expected: "UInt", actual: value) } } } extension Int64: Decodable { /** - Decode `JSON` into `Decoded`. + Decode `Value` into `Decoded`. Succeeds if the value is a number that can be converted to an `Int64` or a string that represents a large number, otherwise it returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded `Int64` value */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case let .number(n): return pure(n.int64Value) case let .string(s): guard let i = Int64(s) else { fallthrough } return pure(i) - default: return .typeMismatch(expected: "Int64", actual: json) + default: return .typeMismatch(expected: "Int64", actual: value) } } } extension UInt64: Decodable { /** - Decode `JSON` into `Decoded`. + Decode `Value` into `Decoded`. Succeeds if the value is a number that can be converted to an `UInt64` or a string that represents a large number, otherwise it returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded `UInt` value */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case let .number(n): return pure(n.uint64Value) case let .string(s): guard let i = UInt64(s) else { fallthrough } return pure(i) - default: return .typeMismatch(expected: "UInt64", actual: json) + default: return .typeMismatch(expected: "UInt64", actual: value) } } } extension Double: Decodable { /** - Decode `JSON` into `Decoded`. + Decode `Value` into `Decoded`. Succeeds if the value is a number that can be converted to a `Double`, otherwise it returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded `Double` value */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case let .number(n): return pure(n.doubleValue) - default: return .typeMismatch(expected: "Double", actual: json) + default: return .typeMismatch(expected: "Double", actual: value) } } } extension Float: Decodable { /** - Decode `JSON` into `Decoded`. + Decode `Value` into `Decoded`. Succeeds if the value is a number that can be converted to a `Float`, otherwise it returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded `Float` value */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case let .number(n): return pure(n.floatValue) - default: return .typeMismatch(expected: "Float", actual: json) + default: return .typeMismatch(expected: "Float", actual: value) } } } extension Bool: Decodable { /** - Decode `JSON` into `Decoded`. + Decode `Value` into `Decoded`. Succeeds if the value is a boolean or if the value is a number that is able to be converted to a boolean, otherwise it returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded `Bool` value */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case let .bool(n): return pure(n) case let .number(n): return pure(n.boolValue) - default: return .typeMismatch(expected: "Bool", actual: json) + default: return .typeMismatch(expected: "Bool", actual: value) } } } public extension Optional where Wrapped: Decodable, Wrapped == Wrapped.DecodedType { /** - Decode `JSON` into an `Optional` value where `Wrapped` is `Decodable`. + Decode `Value` into an `Optional` value where `Wrapped` is `Decodable`. Returns a decoded optional value from the result of performing `decode` on the internal wrapped type. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded optional `Wrapped` value */ - static func decode(_ json: JSON) -> Decoded { - return Wrapped.decode(json) >>- { .success(.some($0)) } + static func decode(_ value: Value) -> Decoded { + return Wrapped.decode(value) >>- { .success(.some($0)) } } } extension Array: Decodable where Element: Decodable, Element == Element.DecodedType { /** - Decode `JSON` into an array of values where the elements of the array are + Decode `Value` into an array of values where the elements of the array are `Decodable`. - If the `JSON` is an array of `JSON` objects, this returns a decoded array - of values by mapping the element's `decode` function over the `JSON` and + If the `Value` is an array of `Value` objects, this returns a decoded array + of values by mapping the element's `decode` function over the `Value` and then applying `sequence` to the result. This makes this `decode` function an all-or-nothing operation (See the documentation for `sequence` for more info). - If the `JSON` is not an array, this returns a type mismatch. + If the `Value` is not an array, this returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded array of values */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case let .array(a): return sequence(a.map(Iterator.Element.decode)) - default: return .typeMismatch(expected: "Array", actual: json) + default: return .typeMismatch(expected: "Array", actual: value) } } } extension Dictionary: Decodable where Value: Decodable, Value == Value.DecodedType, Key == String { /** - Decode `JSON` into a dictionary of keys and values where the keys are + Decode `Value` into a dictionary of keys and values where the keys are `String`s and the values are `Decodable`. - If the `JSON` is a dictionary of `String`/`JSON` pairs, this returns a decoded dictionary - of key/value pairs by mapping the value's `decode` function over the `JSON` and + If the `Value` is a dictionary of `String`/`Value` pairs, this returns a decoded dictionary + of key/value pairs by mapping the value's `decode` function over the `Value` and then applying `sequence` to the result. This makes this `decode` function an all-or-nothing operation (See the documentation for `sequence` for more info). - If the `JSON` is not a dictionary, this returns a type mismatch. + If the `Value` is not a dictionary, this returns a type mismatch. - - parameter json: The `JSON` value to decode + - parameter value: The `Value` to decode - returns: A decoded dictionary of key/value pairs */ - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Argo.Value) -> Decoded { + switch value { case let .object(o): return sequence(Value.decode <^> o) - default: return .typeMismatch(expected: "Object", actual: json) + default: return .typeMismatch(expected: "Object", actual: value) } } } /** - Pull an embedded `JSON` value from a specified key. + Pull an embedded `Value` from a specified key. - If the `JSON` value is an object, it will attempt to return the embedded - `JSON` value at the specified key, failing if the key doesn't exist. + If the `Value` is an object, it will attempt to return the embedded + `Value` at the specified key, failing if the key doesn't exist. - If the `JSON` value is not an object, this will return a type mismatch. + If the `Value` is not an object, this will return a type mismatch. - This is similar to adding a subscript to `JSON`, except that it returns a + This is similar to adding a subscript to `Value`, except that it returns a `Decoded` type. - - parameter json: The `JSON` value that contains the key - - parameter key: The key containing the embedded `JSON` object + - parameter value: The `Value` that contains the key + - parameter key: The key containing the embedded `Value` object - - returns: A decoded `JSON` value representing the success or failure of + - returns: A decoded `Value` representing the success or failure of extracting the value from the object */ -public func decodedJSON(_ json: JSON, forKey key: String) -> Decoded { - switch json { +public func decodedValue(_ value: Value, forKey key: String) -> Decoded { + switch value { case let .object(o): return guardNull(key, o[key] ?? .null) - default: return .typeMismatch(expected: "Object", actual: json) + default: return .typeMismatch(expected: "Object", actual: value) } } -private func guardNull(_ key: String, _ json: JSON) -> Decoded { - switch json { +private func guardNull(_ key: String, _ value: Value) -> Decoded { + switch value { case .null: return .missingKey(key) - default: return pure(json) + default: return pure(value) } } diff --git a/Sources/Argo/Types/Value.swift b/Sources/Argo/Types/Value.swift new file mode 100644 index 0000000..3ae539c --- /dev/null +++ b/Sources/Argo/Types/Value.swift @@ -0,0 +1,145 @@ +import Foundation + +/// A type safe representation of a weakly typed object. +public enum Value { + case object([String: Value]) + case array([Value]) + case string(String) + case number(NSNumber) + case bool(Bool) + case null +} + +public extension Value { + /** + Transform an `Any` instance into `Value`. + + This is used to move from a loosely typed object (like those returned from + `NSJSONSerialization`) to the strongly typed `Value` tree structure. + + - parameter value: A loosely typed object + */ + init(_ value: Any) { + switch value { + + case let v as [Any]: + self = .array(v.map(Value.init)) + + case let v as [String: Any]: + self = .object(v.map(Value.init)) + + case let v as String: + self = .string(v) + + case let v as NSNumber: + if v.isBool { + self = .bool(v.boolValue) + } else { + self = .number(v) + } + + default: + self = .null + } + } +} + +extension Value { + /** + Attempt to extract a value at the specified key path and transform it into + the requested type. + + This method is used to decode a mandatory value from the `JSON`. If the + decoding fails for any reason, this will result in a `.Failure` being + returned. + + - parameter keyPath: The key path for the object to decode, represented by + a variadic list of strings. + + - returns: A `Decoded` value representing the success or failure of the + decode operation + */ + public subscript(keyPath: String...) -> Decoded where T == T.DecodedType { + return flatReduce(keyPath, initial: self, combine: decodedValue) + .flatMap(T.decode) + } + + /** + Attempt to extract an optional value at the specified key path and + transform it into the requested type. + + This method is used to decode an optional value from the `JSON`. If any of + the keys in the key path aren't present in the `JSON`, this will still return + `.success`. However, if the key path exists but the object assigned to the + final key is unable to be decoded into the requested type, this will return + `.failure`. + + - parameter keyPath: The key path for the object to decode, represented by + a variadic list of strings. + - returns: A `Decoded` optional value representing the success or failure + of the decode operation + */ + public subscript(optional keyPath: String...) -> Decoded where T == T.DecodedType { + switch flatReduce(keyPath, initial: self, combine: decodedValue) { + case .failure: + return .success(.none) + + case let .success(x): + return T.decode(x) + .flatMap { .success(.some($0)) } + } + } +} + +extension Value: Decodable { + /** + Decode `Value` into `Decoded`. + + This simply wraps the provided `Value` in `.Success`. This is useful because + it means we can use `Value`s with the `<|` family of operators to pull + out sub-keys. + + - parameter value: The `Value` to decode + + - returns: The provided `Value` wrapped in `.Success` + */ + public static func decode(_ value: Value) -> Decoded { + return pure(value) + } +} + +extension Value: CustomStringConvertible { + public var description: String { + switch self { + case let .string(v): return "String(\(v))" + case let .number(v): return "Number(\(v))" + case let .bool(v): return "Bool(\(v))" + case let .array(a): return "Array(\(a.description))" + case let .object(o): return "Object(\(o.description))" + case .null: return "Null" + } + } +} + +extension Value: Equatable {} + +public func == (lhs: Value, rhs: Value) -> Bool { + switch (lhs, rhs) { + case let (.string(l), .string(r)): return l == r + case let (.number(l), .number(r)): return l == r + case let (.bool(l), .bool(r)): return l == r + case let (.array(l), .array(r)): return l == r + case let (.object(l), .object(r)): return l == r + case (.null, .null): return true + default: return false + } +} + +/// MARK: Deprecations + +extension Value { + @available(*, deprecated: 3.0, renamed: "init") + static func parse(_ json: Any) -> Value { + return Value(json) + } +} diff --git a/Tests/ArgoTests/Models/Booleans.swift b/Tests/ArgoTests/Models/Booleans.swift index 75648ee..d02ed78 100644 --- a/Tests/ArgoTests/Models/Booleans.swift +++ b/Tests/ArgoTests/Models/Booleans.swift @@ -6,9 +6,9 @@ struct Booleans: Argo.Decodable { let bool: Bool let number: Bool - static func decode(_ json: JSON) -> Decoded { + static func decode(_ value: Value) -> Decoded { return curry(Booleans.init) - <^> json["realBool"] - <*> json["numberBool"] + <^> value["realBool"] + <*> value["numberBool"] } } diff --git a/Tests/ArgoTests/Models/Comment.swift b/Tests/ArgoTests/Models/Comment.swift index 454d2af..a9c6f89 100644 --- a/Tests/ArgoTests/Models/Comment.swift +++ b/Tests/ArgoTests/Models/Comment.swift @@ -9,10 +9,10 @@ struct Comment { } extension Comment: Argo.Decodable { - static func decode(_ json: JSON) -> Decoded { + static func decode(_ value: Value) -> Decoded { return curry(self.init) - <^> json["id"] - <*> json["text"] - <*> json["author", "name"] + <^> value["id"] + <*> value["text"] + <*> value["author", "name"] } } diff --git a/Tests/ArgoTests/Models/Post.swift b/Tests/ArgoTests/Models/Post.swift index a3277d5..b40f3d2 100644 --- a/Tests/ArgoTests/Models/Post.swift +++ b/Tests/ArgoTests/Models/Post.swift @@ -10,12 +10,12 @@ struct Post { } extension Post: Argo.Decodable { - static func decode(_ json: JSON) -> Decoded { + static func decode(_ value: Value) -> Decoded { return curry(self.init) - <^> json["id"] - <*> json["text"] - <*> json["author"] - <*> json["comments"] + <^> value["id"] + <*> value["text"] + <*> value["author"] + <*> value["comments"] } } @@ -28,13 +28,13 @@ struct LocationPost { } extension LocationPost: Argo.Decodable { - static func decode(_ json: JSON) -> Decoded { + static func decode(_ value: Value) -> Decoded { return curry(self.init) - <^> json["id"] - <*> json["text"] - <*> json["author"] - <*> json["comments"] - <*> json[optional: "location"] + <^> value["id"] + <*> value["text"] + <*> value["author"] + <*> value["comments"] + <*> value[optional: "location"] } } @@ -45,10 +45,10 @@ struct Location { } extension Location: Argo.Decodable { - static func decode(_ json: JSON) -> Decoded { + static func decode(_ value: Value) -> Decoded { return curry(self.init) - <^> json["lat"] - <*> json["lng"] - <*> json["title"] + <^> value["lat"] + <*> value["lng"] + <*> value["title"] } } diff --git a/Tests/ArgoTests/Models/TestModel.swift b/Tests/ArgoTests/Models/TestModel.swift index 2bfee0b..4bbc376 100644 --- a/Tests/ArgoTests/Models/TestModel.swift +++ b/Tests/ArgoTests/Models/TestModel.swift @@ -15,18 +15,18 @@ struct TestModel { } extension TestModel: Argo.Decodable { - static func decode(_ json: JSON) -> Decoded { + static func decode(_ value: Value) -> Decoded { let curriedInit = curry(self.init) return curriedInit - <^> json["numerics"] - <*> json["user_opt", "name"] - <*> json["bool"] - <*> json["string_array"] - <*> json[optional: "string_array_opt"] - <*> json["embedded", "string_array"] - <*> json[optional: "embedded", "string_array_opt"] - <*> json[optional: "user_opt"] - <*> json["dict"] + <^> value["numerics"] + <*> value["user_opt", "name"] + <*> value["bool"] + <*> value["string_array"] + <*> value[optional: "string_array_opt"] + <*> value["embedded", "string_array"] + <*> value[optional: "embedded", "string_array_opt"] + <*> value[optional: "user_opt"] + <*> value["dict"] } } @@ -43,18 +43,18 @@ struct TestModelNumerics { } extension TestModelNumerics: Argo.Decodable { - static func decode(_ json: JSON) -> Decoded { + static func decode(_ value: Value) -> Decoded { let f = curry(self.init) - <^> json["int"] - <*> json["int64"] - <*> json["int64_string"] - <*> json["double"] - <*> json["float"] - <*> json[optional: "int_opt"] + <^> value["int"] + <*> value["int64"] + <*> value["int64_string"] + <*> value["double"] + <*> value["float"] + <*> value[optional: "int_opt"] return f - <*> json["uint"] - <*> json["uint64"] - <*> json["uint64_string"] + <*> value["uint"] + <*> value["uint64"] + <*> value["uint64_string"] } } diff --git a/Tests/ArgoTests/Models/URL.swift b/Tests/ArgoTests/Models/URL.swift index 806b832..7173490 100644 --- a/Tests/ArgoTests/Models/URL.swift +++ b/Tests/ArgoTests/Models/URL.swift @@ -2,11 +2,11 @@ import Argo import Foundation extension URL: Argo.Decodable { - public static func decode(_ json: JSON) -> Decoded { - switch json { + public static func decode(_ value: Value) -> Decoded { + switch value { case .string(let urlString): - return URL(string: urlString).map(pure) ?? .typeMismatch(expected: "URL", actual: json) - default: return .typeMismatch(expected: "URL", actual: json) + return URL(string: urlString).map(pure) ?? .typeMismatch(expected: "URL", actual: value) + default: return .typeMismatch(expected: "URL", actual: value) } } } diff --git a/Tests/ArgoTests/Models/User.swift b/Tests/ArgoTests/Models/User.swift index 6b5af79..b4ca2c1 100644 --- a/Tests/ArgoTests/Models/User.swift +++ b/Tests/ArgoTests/Models/User.swift @@ -9,10 +9,10 @@ struct User { } extension User: Argo.Decodable { - static func decode(_ json: JSON) -> Decoded { + static func decode(_ value: Value) -> Decoded { return curry(self.init) - <^> json["id"] - <*> (json["userinfo", "name"] <|> json["name"]) - <*> json[optional: "email"] + <^> value["id"] + <*> (value["userinfo", "name"] <|> value["name"]) + <*> value[optional: "email"] } } diff --git a/Tests/ArgoTests/Tests/DecodedTests.swift b/Tests/ArgoTests/Tests/DecodedTests.swift index 56be115..dc7c10f 100644 --- a/Tests/ArgoTests/Tests/DecodedTests.swift +++ b/Tests/ArgoTests/Tests/DecodedTests.swift @@ -80,7 +80,7 @@ class DecodedTests: XCTestCase { let expected: [DecodeError] = [ .missingKey("name"), - .typeMismatch(expected: "String", actual: String(describing: JSON.number(1))) + .typeMismatch(expected: "String", actual: String(describing: Value.number(1))) ] switch user { @@ -195,7 +195,7 @@ class DecodedTests: XCTestCase { } private struct Dummy: Argo.Decodable { - static func decode(_ json: JSON) -> Decoded { + static func decode(_ value: Value) -> Decoded { return .customError("My Custom Error") } } diff --git a/Tests/ArgoTests/Tests/EquatableTests.swift b/Tests/ArgoTests/Tests/EquatableTests.swift index 9581a81..2deb56d 100644 --- a/Tests/ArgoTests/Tests/EquatableTests.swift +++ b/Tests/ArgoTests/Tests/EquatableTests.swift @@ -3,15 +3,15 @@ import Argo class EquatableTests: XCTestCase { func testEqualJSONObjects() { - let j = json(fromFile: "types").map(JSON.init) - let anotherParsed = json(fromFile: "types").map(JSON.init) + let j = json(fromFile: "types").map(Value.init) + let anotherParsed = json(fromFile: "types").map(Value.init) XCTAssertEqual(j, anotherParsed) } func testNotEqualJSONObjects() { - let j = json(fromFile: "types").map(JSON.init) - let anotherJSON = json(fromFile: "types_fail_embedded").map(JSON.init) + let j = json(fromFile: "types").map(Value.init) + let anotherJSON = json(fromFile: "types_fail_embedded").map(Value.init) XCTAssertNotEqual(j, anotherJSON) } diff --git a/Tests/ArgoTests/Tests/ExampleTests.swift b/Tests/ArgoTests/Tests/ExampleTests.swift index d589b37..d21bc6d 100644 --- a/Tests/ArgoTests/Tests/ExampleTests.swift +++ b/Tests/ArgoTests/Tests/ExampleTests.swift @@ -27,8 +27,8 @@ class ExampleTests: XCTestCase { } func testDecodingJSONWithRootArray() { - let expected = JSON([["title": "Foo", "age": 21], ["title": "Bar", "age": 32]]) - let j = json(fromFile: "root_array").map(JSON.init) + let expected = Value([["title": "Foo", "age": 21], ["title": "Bar", "age": 32]]) + let j = json(fromFile: "root_array").map(Value.init) XCTAssertEqual(expected, j) } diff --git a/Tests/ArgoTests/Tests/PerformanceTests.swift b/Tests/ArgoTests/Tests/PerformanceTests.swift index 38505fd..dd28105 100644 --- a/Tests/ArgoTests/Tests/PerformanceTests.swift +++ b/Tests/ArgoTests/Tests/PerformanceTests.swift @@ -6,13 +6,13 @@ class PerformanceTests: XCTestCase { let obj: Any = json(fromFile: "big_data")! measure { - _ = JSON(obj) + _ = Value(obj) } } func testDecodePerformance() { let obj: Any = json(fromFile: "big_data")! - let j = JSON(obj) + let j = Value(obj) measure { _ = [TestModel].decode(j) @@ -21,7 +21,7 @@ class PerformanceTests: XCTestCase { func testBigDataDecodesCorrectly() { let obj: Any = json(fromFile: "big_data")! - let j = JSON(obj) + let j = Value(obj) let models = [TestModel].decode(j) XCTAssertEqual(models.value?.count, 10_000, "Decoded big_data should have 10_000 results.") } diff --git a/Tests/ArgoTests/Tests/RawRepresentableTests.swift b/Tests/ArgoTests/Tests/RawRepresentableTests.swift index 11392a7..4d7ba1d 100644 --- a/Tests/ArgoTests/Tests/RawRepresentableTests.swift +++ b/Tests/ArgoTests/Tests/RawRepresentableTests.swift @@ -16,9 +16,9 @@ extension TestRawInt: Argo.Decodable { } class RawRepresentable: XCTestCase { func testStringEnum() { - let json = JSON.object([ - "string": JSON.string("CoolString"), - "another": JSON.string("NotCoolStringBro") + let json = Value.object([ + "string": Value.string("CoolString"), + "another": Value.string("NotCoolStringBro") ]) let string: TestRawString? = json["string"].value @@ -28,9 +28,9 @@ class RawRepresentable: XCTestCase { } func testIntEnum() { - let json = JSON.object([ - "zero": JSON.number(0), - "one": JSON.number(1) + let json = Value.object([ + "zero": Value.number(0), + "one": Value.number(1) ]) let zero: TestRawInt? = json["zero"].value diff --git a/Tests/ArgoTests/Tests/TypeTests.swift b/Tests/ArgoTests/Tests/TypeTests.swift index b51a16c..6bb249f 100644 --- a/Tests/ArgoTests/Tests/TypeTests.swift +++ b/Tests/ArgoTests/Tests/TypeTests.swift @@ -38,8 +38,8 @@ class TypeTests: XCTestCase { } func testBooleanIdentification() { - let j = json(fromFile: "booleans").map(JSON.init)! - let boolean: JSON? = j["realBool"].value + let v = json(fromFile: "booleans").map(Value.init)! + let boolean: Value? = v["realBool"].value XCTAssertEqual(boolean, .bool(true)) }