Created
September 30, 2015 22:49
-
-
Save edwardaux/93e3108ae0dc43c1c3e7 to your computer and use it in GitHub Desktop.
Patches for Argo #237
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From bf726b714c977045974a92d91d561a72c3045924 Mon Sep 17 00:00:00 2001 | |
From: Tony DiPasquale <[email protected]> | |
Date: Fri, 13 Mar 2015 13:08:22 -0400 | |
Subject: [PATCH] Update the documentation for Swift 2 | |
This also breaks up the main README.md into a Documentations directory | |
with separate documents for different topics. This will be expanded upon | |
with new PRs going forward. | |
--- | |
ArgoTests/JSON/JSONFileReader.swift | 3 +- | |
Documentation/.gitkeep | 0 | |
Documentation/Basic-Usage.md | 137 ++++++++++++++++++ | |
Documentation/Functional-Concepts.md | 26 ++++ | |
Documentation/Ideology.md | 37 +++++ | |
Documentation/README.md | 24 ++++ | |
README.md | 261 +---------------------------------- | |
7 files changed, 231 insertions(+), 257 deletions(-) | |
create mode 100644 Documentation/.gitkeep | |
create mode 100644 Documentation/Basic-Usage.md | |
create mode 100644 Documentation/Functional-Concepts.md | |
create mode 100644 Documentation/Ideology.md | |
create mode 100644 Documentation/README.md | |
diff --git a/ArgoTests/JSON/JSONFileReader.swift b/ArgoTests/JSON/JSONFileReader.swift | |
index 1b3c8e6..0f50ee7 100644 | |
--- a/ArgoTests/JSON/JSONFileReader.swift | |
+++ b/ArgoTests/JSON/JSONFileReader.swift | |
@@ -7,8 +7,7 @@ func JSONFromFile(file: String) -> AnyObject? { | |
} | |
private func JSONObjectWithData(data: NSData) -> AnyObject? { | |
- do { return try NSJSONSerialization.JSONObjectWithData(data, options: []) } | |
- catch { return .None } | |
+ return try? NSJSONSerialization.JSONObjectWithData(data, options: []) | |
} | |
private class JSONFileReader { } | |
diff --git a/Documentation/.gitkeep b/Documentation/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/Documentation/Basic-Usage.md b/Documentation/Basic-Usage.md | |
new file mode 100644 | |
index 0000000..e9e86bd | |
--- /dev/null | |
+++ b/Documentation/Basic-Usage.md | |
@@ -0,0 +1,137 @@ | |
+## Usage | |
+ | |
+The first thing you need to do when you receive JSON data is convert it from | |
+`NSData` to an `AnyObject` using `Foundation`'s `NSJSONSerialization` API. | |
+Once you have the `AnyObject`, you can call the global `decode` function to get | |
+back the decoded model. | |
+ | |
+```swift | |
+let json: AnyObject? = try? NSJSONSerialization.JSONObjectWithData(responseData, options: []) | |
+ | |
+if let j: AnyObject = json { | |
+ let user: User? = decode(j) // ignore error info or | |
+ let decodedUser: Decoded<User> = decode(j) // preserve error info | |
+} | |
+``` | |
+ | |
+Argo 1.0 introduces a new type: `Decoded<T>`. This is the type returned from | |
+the `decode` function that you implement as part of the `Decodable` protocol. | |
+This new type allows you to preserve information about why a decoding failed. | |
+You can choose to either ignore the `Decoded` type and just get back the | |
+optional value or keep the `Decoded` type and use it to debug decoding errors. | |
+When you decode an `AnyObject` into a model using the global `decode` function, | |
+you can specify whether you want an `Optional` model or a `Decoded` model by | |
+specifying the return type as seen in the code block above. | |
+ | |
+Next, you need to make sure that models that you wish to decode from JSON | |
+conform to the `Decodable` protocol: | |
+ | |
+```swift | |
+public protocol Decodable { | |
+ typealias DecodedType = Self | |
+ class func decode(JSON) -> Decoded<DecodedType> | |
+} | |
+``` | |
+ | |
+You will need to implement the `decode` function to perform any kinds of | |
+transformations you need to transform your model from a JSON value. The power | |
+of Argo can be seen when decoding actual model objects. To illustrate this, we | |
+will decode the simple `User` object. | |
+ | |
+Create your `User` model: | |
+ | |
+```swift | |
+struct User { | |
+ let id: Int | |
+ let name: String | |
+} | |
+``` | |
+ | |
+We will be using [`Curry`] to help with decoding our `User` model. Currying | |
+allows us to partially apply the `init` function over the course of the | |
+decoding process. If you'd like to learn more about currying, we recommend the | |
+following articles: | |
+ | |
+[`Curry`]: https://github.com/thoughtbot/Curry | |
+ | |
+- [Apple's documentation of curried functions](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_615) | |
+- [Introduction to Function Currying in Swift](http://robots.thoughtbot.com/introduction-to-function-currying-in-swift) | |
+ | |
+Now, we make `User` conform to `Decodable` and implement the required `decode` | |
+function. We will implement this function by using `map` (`<^>`) and `apply` | |
+(`<*>`) to conditionally pass the required parameters to the curried init | |
+function. The common pattern will look like: | |
+ | |
+```swift | |
+return curry(Model.init) <^> paramOne <*> paramTwo <*> paramThree | |
+``` | |
+ | |
+and so on. If any of those parameters are an error, the entire creation process | |
+will fail, and the function will return the first error. If all of the | |
+parameters are successful, the value will be unwrapped and passed to the | |
+`init` function. | |
+ | |
+In order to help with the decoding process, Argo introduces two new operators | |
+for parsing a value out of the JSON: | |
+ | |
+- `<|` will attempt to parse a single value from the JSON | |
+- `<||` will attempt to parse an array of values from the JSON | |
+ | |
+The usage of these operators is the same regardless: | |
+ | |
+- `json <| "key"` is analogous to `json["key"]` | |
+- `json <| ["key", "nested"]` is analogous to `json["key"]["nested"]` | |
+ | |
+Both operators will attempt to parse the value from the JSON and will also | |
+attempt to cast the value to the expected type. If it can't find a value, the | |
+function will return a `Decoded.MissingKey(message: String)` error. If the | |
+value it finds is the wrong type, the function will return a | |
+`Decoded.TypeMismatch(message: String)` error. | |
+ | |
+There are also Optional versions of these operators: | |
+ | |
+- `<|?` will attempt to parse an optional value from the JSON | |
+- `<||?` will attempt to parse an optional array of values from the JSON | |
+ | |
+Usage is the same as the non-optionals. The difference is that if these fail | |
+parsing, the parsing continues. This is useful for including parameters that | |
+truly are optional values. For example, if your system doesn't require someone | |
+to supply an email address, you could have an optional property on `User`: `let | |
+email: String?` and parse it with `json <|? "email"`. | |
+ | |
+So to implement our `decode` function, we can use the JSON parsing operator in | |
+conjunction with `map` and `apply`: | |
+ | |
+```swift | |
+extension User: Decodable { | |
+ static func decode(j: JSON) -> Decoded<User> { | |
+ return curry(User.init) | |
+ <^> j <| "id" | |
+ <*> j <| "name" | |
+ } | |
+} | |
+``` | |
+ | |
+For comparison, this same function without Argo would look like so: | |
+ | |
+```swift | |
+extension User { | |
+ static func decode(j: NSDictionary) -> User? { | |
+ if let id = j["id"] as Int, | |
+ let name = j["name"] as String | |
+ { | |
+ return User(id: id, name: name) | |
+ } | |
+ | |
+ return .None | |
+ } | |
+} | |
+``` | |
+ | |
+You could see how this would get much worse with a more complex model. | |
+ | |
+You can decode custom types the same way, as long as the type also conforms to | |
+`Decodable`. | |
+ | |
+For more examples on how to use Argo, please check out the tests. | |
+ | |
diff --git a/Documentation/Functional-Concepts.md b/Documentation/Functional-Concepts.md | |
new file mode 100644 | |
index 0000000..ba3e09c | |
--- /dev/null | |
+++ b/Documentation/Functional-Concepts.md | |
@@ -0,0 +1,26 @@ | |
+## Functional Concepts | |
+ | |
+Argo really wants to be used with patterns borrowed from functional programming | |
+such as `map` and `apply`. We feel that these patterns greatly reduce the pain | |
+felt in trying to use JSON (an inherently loosely typed format) with Swift (a | |
+strictly typed language). It also gives us a way to succinctly maintain Argo's | |
+core concept, and short circuit the decoding process if any part of it fails. | |
+ | |
+Additionally, we feel that the use of operators for these functions greatly | |
+improves the readability of the code we're suggesting. Using named functions | |
+would lead to nested functions and a confusing number of parenthesis. | |
+ | |
+If you aren't familiar with how these functions work (or just aren't | |
+comfortable with using operators), that's totally OK. It's possible to use the | |
+library without using them, although it might be a little more painful. | |
+ | |
+If you're looking to learn more about these functions, we would recommend | |
+reading the following articles: | |
+ | |
+- [Functional Swift for Dealing with Optional Values](http://robots.thoughtbot.com/functional-swift-for-dealing-with-optional-values) | |
+- [Railway Oriented Programming](http://fsharpforfunandprofit.com/posts/recipe-part2/) | |
+ | |
+And check out this talk: | |
+ | |
+- [How I Learned To Stop Worrying And Love The Functor](https://github.com/gfontenot/talks/tree/master/Functors) | |
+ | |
diff --git a/Documentation/Ideology.md b/Documentation/Ideology.md | |
new file mode 100644 | |
index 0000000..80c6fb6 | |
--- /dev/null | |
+++ b/Documentation/Ideology.md | |
@@ -0,0 +1,37 @@ | |
+## Ideology | |
+ | |
+Argo's core concept is that in order to maintain type safety, you should only | |
+be able to successfully decode an object if all parameters are satisfied | |
+properly. So if you have a model that looks like this: | |
+ | |
+```swift | |
+struct User { | |
+ let id: Int | |
+ let name: String | |
+} | |
+``` | |
+ | |
+but the JSON you receive from the server looks like this: | |
+ | |
+```json | |
+{ | |
+ "user": { | |
+ "id": "this isn't a number", | |
+ "name": "Gob Bluth" | |
+ } | |
+} | |
+``` | |
+ | |
+then ideally, JSON parsing would fail, and you'd get an error state instead of | |
+a `User` object. In Argo, if JSON parsing succeeds you'll receive the `User` | |
+object and you can be sure that it is full and valid. If it fails, you will | |
+instead be given the reason why the `User` couldn't be constructed. | |
+ | |
+If you're interested in learning more about the concepts and ideology that | |
+went into building Argo, we recommend reading the series of articles that were | |
+written alongside its development: | |
+ | |
+- [Efficient JSON in Swift with Functional Concepts and Generics](http://robots.thoughtbot.com/efficient-json-in-swift-with-functional-concepts-and-generics) | |
+- [Real World JSON Parsing with Swift](http://robots.thoughtbot.com/real-world-json-parsing-with-swift) | |
+- [Parsing Embedded JSON and Arrays in Swift](http://robots.thoughtbot.com/parsing-embedded-json-and-arrays-in-swift) | |
+ | |
diff --git a/Documentation/README.md b/Documentation/README.md | |
new file mode 100644 | |
index 0000000..d2725b7 | |
--- /dev/null | |
+++ b/Documentation/README.md | |
@@ -0,0 +1,24 @@ | |
+# Documentation # | |
+ | |
+Argo allows you to easily decode loosely typed structures into strongly typed | |
+models. When paired with functional programming concepts, Argo becomes a | |
+beautiful way to decode JSON from network responses into your application | |
+models. The following guides will teach you how to use Argo and how powerful it | |
+can be. | |
+ | |
+## High Level Concepts ## | |
+ | |
+- [Overarching ideology](Ideology.md) | |
+- [Functional concepts](Functional-Concepts.md) | |
+ | |
+## Basic Usage ## | |
+ | |
+- [Decoding your first model](Basic-Usage.md) | |
+- Relationships // TODO | |
+ | |
+## Advanced Usage ## | |
+ | |
+- Understanding the Decode operators // TODO | |
+- Interacting with the `JSON` enum // TODO | |
+- Writing your own custom parser // TODO | |
+- More complex parsers // TODO | |
diff --git a/README.md b/README.md | |
index 69577eb..338339e 100644 | |
--- a/README.md | |
+++ b/README.md | |
@@ -84,280 +84,30 @@ extension User: Decodable { | |
// Wherever you receive JSON data: | |
-let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: nil) | |
+let json: AnyObject? = try? NSJSONSerialization.JSONObjectWithData(data, options: []) | |
if let j: AnyObject = json { | |
let user: User? = decode(j) | |
} | |
``` | |
-## Ideology | |
+For more information, see the [Documentation](Documentation/) | |
-Argo's core concept is that in order to maintain type safety, you should only | |
-be able to successfully decode an object if all parameters are satisfied | |
-properly. So if you have a model that looks like this: | |
- | |
-```swift | |
-struct User { | |
- let id: Int | |
- let name: String | |
-} | |
-``` | |
- | |
-but the JSON you receive from the server looks like this: | |
- | |
-```json | |
-{ | |
- "user": { | |
- "id": "this isn't a number", | |
- "name": "Gob Bluth" | |
- } | |
-} | |
-``` | |
- | |
-then ideally, JSON parsing would fail, and you'd get an error state instead of | |
-a `User` object. In Argo, if JSON parsing succeeds you'll receive the `User` | |
-object and you can be sure that it is full and valid. If it fails, you will | |
-instead be given the reason why the `User` couldn't be constructed. | |
- | |
-If you're interested in learning more about the concepts and ideology that | |
-went into building Argo, we recommend reading the series of articles that were | |
-written alongside its development: | |
- | |
-- [Efficient JSON in Swift with Functional Concepts and Generics](http://robots.thoughtbot.com/efficient-json-in-swift-with-functional-concepts-and-generics) | |
-- [Real World JSON Parsing with Swift](http://robots.thoughtbot.com/real-world-json-parsing-with-swift) | |
-- [Parsing Embedded JSON and Arrays in Swift](http://robots.thoughtbot.com/parsing-embedded-json-and-arrays-in-swift) | |
- | |
-## Functional Concepts | |
- | |
-Argo really wants to be used with patterns borrowed from functional | |
-programming such as `map` and `apply`. We feel that these patterns greatly | |
-reduce the pain felt in trying to use JSON (an inherently loosely typed | |
-format) with Swift (a strictly typed language). It also gives us a way to | |
-succinctly maintain the core concept described above, and short circuit the | |
-decoding process if any part of it fails. | |
- | |
-Additionally, we feel that the use of operators for these functions greatly | |
-improves the readability of the code we're suggesting. Using named functions | |
-would lead to nested functions and a confusing number of parenthesis. | |
- | |
-If you aren't familiar with how these functions work (or just aren't | |
-comfortable with using operators), that's totally OK. It's possible to use the | |
-library without using them, although it might be a little more painful. | |
- | |
-If you're looking to learn more about these functions, we would recommend | |
-reading the following articles: | |
- | |
-- [Functional Swift for Dealing with Optional Values](http://robots.thoughtbot.com/functional-swift-for-dealing-with-optional-values) | |
-- [Railway Oriented Programming](http://fsharpforfunandprofit.com/posts/recipe-part2/) | |
- | |
-And check out this talk: | |
- | |
-- [How I Learned To Stop Worrying And Love The Functor](https://github.com/gfontenot/talks/tree/master/Functors) | |
- | |
-## Usage | |
- | |
-The first thing you need to do when you receive JSON data is convert it from | |
-`NSData` to an `AnyObject` using the built-in `NSJSONSerialization` API. Once | |
-you have the `AnyObject`, you can call the global `decode` function to get back | |
-the decoded model. | |
- | |
-```swift | |
-var error: NSError? | |
-let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(responseData, options: NSJSONReadingOptions(0), error: &error) | |
- | |
-if let j: AnyObject = json { | |
- let user: User? = decode(j) // ignore error info or | |
- let decodedUser: Decoded<User> = decode(j) // preserve error info | |
-} else { | |
- // handle error | |
-} | |
-``` | |
- | |
-Note that you probably want to use an error pointer to track errors from | |
-`NSJSONSerialization`. | |
- | |
-The `JSON` enum exists to help with some of the type inference, and also wraps | |
-up some of the casting that you'll need to do to transform the JSON into native | |
-types. | |
- | |
-Argo 1.0 introduces a new type: `Decoded<T>`. This is now the type returned | |
-from the `decode` function that you implement as part of the `Decodable` | |
-protocol. This new type allows you to preserve information about why a decoding | |
-failed. You can choose to either ignore the `Decoded` type and just get back | |
-the optional value or keep the `Decoded` type and use it to debug decoding | |
-errors. When you decode an `AnyObject` into a model using the global `decode` | |
-function, you can specify whether you want an `Optional` model or a `Decoded` | |
-model by specifying the return type as seen in the code block above. | |
- | |
-Next, you need to make sure that models that you wish to decode from JSON | |
-conform to the `Decodable` protocol: | |
- | |
-```swift | |
-public protocol Decodable { | |
- typealias DecodedType = Self | |
- class func decode(JSON) -> Decoded<DecodedType> | |
-} | |
-``` | |
- | |
-You will need to implement the `decode` function to perform any kinds of | |
-transformations you need to transform your model from a JSON value. A simple | |
-implementation for an enum value might look like: | |
- | |
-```swift | |
-enum RoleType: String { | |
- case Admin = "Admin" | |
- case User = "User" | |
-} | |
- | |
-extension RoleType: Decodable { | |
- static func decode(j: JSON) -> Decoded<RoleType> { | |
- switch j { | |
- case let .String(s): return .fromOptional(RoleType(rawValue: s)) | |
- default: return .TypeMismatch("\(j) is not a String") // Provide an Error message for a string type mismatch | |
- } | |
- } | |
-} | |
-``` | |
- | |
-The real power of Argo can be seen when decoding actual model objects. To | |
-illustrate this, we will decode the simple `User` object that we used earlier. | |
- | |
-Create your model normally: | |
- | |
-```swift | |
-struct User { | |
- let id: Int | |
- let name: String | |
-} | |
-``` | |
- | |
-You will also need a curried function used to construct your model object. If | |
-you'd like to do this manually, it would look like so: | |
- | |
-```swift | |
-extension User { | |
- static func create(id: Int)(name: String) -> User { | |
- return User(id: id, name: name) | |
- } | |
-} | |
-``` | |
- | |
-Alternatively, you can use a `curry` function to curry the object's normal | |
-initializer: | |
- | |
-```swift | |
-curry(User.init) | |
-``` | |
- | |
-We recommend using a shared dependency such as [Curry.framework] to introduce | |
-this function to avoid collisions. | |
- | |
-[Curry.framework]: https://github.com/thoughtbot/Curry | |
- | |
-Using this curried syntax will allow us to partially apply the function over | |
-the course of the decoding process. If you'd like to learn more about | |
-currying, we recommend the following articles: | |
- | |
-- [Apple's documentation of curried functions](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_615) | |
-- [Introduction to Function Currying in Swift](http://robots.thoughtbot.com/introduction-to-function-currying-in-swift) | |
- | |
-The last thing to do will be to conform to `Decodable` and implement the | |
-required `decode` function. We will implement this function by using `map` | |
-(`<^>`) and `apply` (`<*>`) to conditionally pass the required parameters to | |
-the curried creation function. The common pattern will look like: | |
- | |
-```swift | |
-return curry(Model.init) <^> paramOne <*> paramTwo <*> paramThree | |
-``` | |
- | |
-and so on. If any of those parameters are an error, the entire creation process | |
-will fail, and the function will return the first error. If all of the | |
-parameters are successful, the value will be unwrapped and passed to the | |
-constructor function. | |
- | |
-In order to help with the decoding process, Argo introduces two new operators | |
-for parsing a value out of the JSON: | |
- | |
-- `<|` will attempt to parse a single value from the JSON | |
-- `<||` will attempt to parse an array of values from the JSON | |
- | |
-The usage of these operators is the same regardless: | |
- | |
-- `json <| "key"` is analogous to `json["key"]` | |
-- `json <| ["key", "nested"]` is analogous to `json["key"]["nested"]` | |
- | |
-Both operators will attempt to parse the value from the JSON and will also | |
-attempt to cast the value to the expected type. If it can't find a value, the | |
-function will return a `Decoded.MissingKey(message: String)` error. If the | |
-value it finds is the wrong type, the function will return a | |
-`Decoded.TypeMismatch(message: String)` error. | |
- | |
-There are also Optional versions of these operators: | |
- | |
-- `<|?` will attempt to parse an optional value from the JSON | |
-- `<||?` will attempt to parse an optional array of values from the JSON | |
- | |
-Usage is the same as the non-optionals. The difference is that if these fail | |
-parsing, the parsing continues. This is useful for including parameters that | |
-truly are optional values. For example, if your system doesn't require someone | |
-to supply an email address, you could have an optional property: `let email: | |
-String?` and parse it with `json <|? "email"`. | |
- | |
-So to implement our `decode` function, we can use the JSON parsing operator in | |
-conjunction with `map` and `apply`: | |
- | |
-```swift | |
-extension User: Decodable { | |
- static func decode(j: JSON) -> Decoded<User> { | |
- return curry(User.init) | |
- <^> j <| "id" | |
- <*> j <| "name" | |
- } | |
-} | |
-``` | |
- | |
-For comparison, this same function without Argo would look like so: | |
- | |
-```swift | |
-extension User { | |
- static func decode(j: NSDictionary) -> User? { | |
- if let id = j["id"] as! Int, | |
- let name = j["name"] as! String | |
- { | |
- return User(id: id, name: name) | |
- } | |
- | |
- return .None | |
- } | |
-} | |
-``` | |
- | |
-You could see how this would get much worse with a more complex model. | |
- | |
-You can decode custom types the same way, as long as the type also conforms to | |
-`Decodable`. | |
- | |
-For more examples on how to use Argo, please check out the tests. | |
- | |
-Contributing | |
------------- | |
+## Contributing | |
See the [CONTRIBUTING] document. Thank you, [contributors]! | |
[CONTRIBUTING]: CONTRIBUTING.md | |
[contributors]: https://github.com/thoughtbot/Argo/graphs/contributors | |
-License | |
-------- | |
+## License | |
Argo is Copyright (c) 2015 thoughtbot, inc. It is free software, and may be | |
redistributed under the terms specified in the [LICENSE] file. | |
[LICENSE]: /LICENSE | |
-About | |
------ | |
+## About | |
 | |
@@ -370,3 +120,4 @@ our product [case studies] and [hire us][hire] to help build your iOS app. | |
[community]: https://thoughtbot.com/community?utm_source=github | |
[case studies]: https://thoughtbot.com/ios?utm_source=github | |
[hire]: https://thoughtbot.com/hire-us?utm_source=github | |
+ | |
-- | |
2.2.1 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 038f72a4b007e4b86e4e3667a568dc7bf0b23338 Mon Sep 17 00:00:00 2001 | |
From: Tony DiPasquale <[email protected]> | |
Date: Mon, 21 Sep 2015 16:08:06 -0700 | |
Subject: [PATCH] Add a Custom error case for DecodeError | |
--- | |
Argo/Types/DecodeError.swift | 2 ++ | |
Argo/Types/Decoded.swift | 5 +++++ | |
ArgoTests/Tests/DecodedTests.swift | 15 +++++++++++++++ | |
3 files changed, 22 insertions(+) | |
diff --git a/Argo/Types/DecodeError.swift b/Argo/Types/DecodeError.swift | |
index 9a86f88..26cddbf 100644 | |
--- a/Argo/Types/DecodeError.swift | |
+++ b/Argo/Types/DecodeError.swift | |
@@ -1,6 +1,7 @@ | |
public enum DecodeError: ErrorType { | |
case TypeMismatch(expected: String, actual: String) | |
case MissingKey(String) | |
+ case Custom(String) | |
} | |
extension DecodeError: CustomStringConvertible { | |
@@ -8,6 +9,7 @@ extension DecodeError: CustomStringConvertible { | |
switch self { | |
case let .TypeMismatch(expected, actual): return "TypeMismatch(Expected \(expected), got \(actual))" | |
case let .MissingKey(s): return "MissingKey(\(s))" | |
+ case let .Custom(s): return "Custom(\(s))" | |
} | |
} | |
} | |
diff --git a/Argo/Types/Decoded.swift b/Argo/Types/Decoded.swift | |
index 154d4f2..e55b056 100644 | |
--- a/Argo/Types/Decoded.swift | |
+++ b/Argo/Types/Decoded.swift | |
@@ -16,6 +16,7 @@ public extension Decoded { | |
case let .Success(value): return .Success(.Some(value)) | |
case .Failure(.MissingKey): return .Success(.None) | |
case let .Failure(.TypeMismatch(x)): return .Failure(.TypeMismatch(x)) | |
+ case let .Failure(.Custom(x)): return .Failure(.Custom(x)) | |
} | |
} | |
@@ -39,6 +40,10 @@ public extension Decoded { | |
static func missingKey<T>(name: String) -> Decoded<T> { | |
return .Failure(.MissingKey(name)) | |
} | |
+ | |
+ static func customError<T>(message: String) -> Decoded<T> { | |
+ return .Failure(.Custom(message)) | |
+ } | |
} | |
extension Decoded: CustomStringConvertible { | |
diff --git a/ArgoTests/Tests/DecodedTests.swift b/ArgoTests/Tests/DecodedTests.swift | |
index 8864567..526668d 100644 | |
--- a/ArgoTests/Tests/DecodedTests.swift | |
+++ b/ArgoTests/Tests/DecodedTests.swift | |
@@ -28,6 +28,15 @@ class DecodedTests: XCTestCase { | |
default: XCTFail("Unexpected Case Occurred") | |
} | |
} | |
+ | |
+ func testDecodedCustomError() { | |
+ let customError: Decoded<Dummy> = decode([:]) | |
+ | |
+ switch customError { | |
+ case let .Failure(e): XCTAssert(e.description == "Custom(My Custom Error)") | |
+ default: XCTFail("Unexpected Case Occurred") | |
+ } | |
+ } | |
func testDecodedDematerializeSuccess() { | |
let user: Decoded<User> = decode(JSONFromFile("user_with_email")!) | |
@@ -70,3 +79,9 @@ class DecodedTests: XCTestCase { | |
} | |
} | |
} | |
+ | |
+private struct Dummy: Decodable { | |
+ static func decode(json: JSON) -> Decoded<Dummy> { | |
+ return .Failure(.Custom("My Custom Error")) | |
+ } | |
+} | |
-- | |
2.2.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment