Commit 9786fd61 by Mark Sands

Improvements to swift 3 conversion

1 parent 80680e6f
Showing with 3309 additions and 261 deletions

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

github "ReactiveX/RxSwift" "3.0.0-beta.1"
github "ReactiveX/RxSwift" "3.0.0"
github "thoughtbot/Argo" "master"
github "thoughtbot/Curry" "master"
github "mattdeckard/RxSugar" "swift-3.0"
github "RxSugar/RxSugar" "v0.1.1"
github "thoughtbot/Curry" "408134ffa8dd1c09b0050f65eae300381b934bf6"
github "thoughtbot/Runes" "e00cf681ec03a2dbf2b4cd6dd1e24d522f55474b"
github "ReactiveX/RxSwift" "3.0.0-beta.1"
github "thoughtbot/Argo" "4b57653f7760bd3eedfd1c1fbc821bde191e603d"
github "mattdeckard/RxSugar" "f01a30ac260f188d4c3d1908166481dfe99384b5"
github "thoughtbot/Curry" "863ec7b235448ca53e682cf6958df4c30880c78e"
github "thoughtbot/Runes" "v4.0.1"
github "ReactiveX/RxSwift" "3.0.0"
github "thoughtbot/Argo" "0c5242ba09c19c3c2b6bfc41ebd8616b8218722c"
github "RxSugar/RxSugar" "v0.1.1"
......@@ -34,5 +34,9 @@ Carthage/
.idea/
*.iml
# Swift Package Manager
.build/
Packages/
Argo.framework.zip
*.xcscmblueprint
Pod::Spec.new do |spec|
spec.name = 'Argo'
spec.version = '3.0.1'
spec.version = '4.1.0'
spec.summary = 'Functional JSON parsing library for Swift.'
spec.homepage = 'https://github.com/thoughtbot/Argo'
spec.license = { :type => 'MIT', :file => 'LICENSE' }
......@@ -11,9 +11,9 @@ Pod::Spec.new do |spec|
}
spec.social_media_url = 'http://twitter.com/thoughtbot'
spec.source = { :git => 'https://github.com/thoughtbot/Argo.git', :tag => "v#{spec.version}" }
spec.source_files = 'Argo/**/*.{h,swift}'
spec.source_files = 'Sources/**/*.{h,swift}'
spec.dependency 'Runes', '>= 3.0.0'
spec.dependency 'Runes', '>= 4.0.0'
spec.requires_arc = true
spec.compiler_flags = '-whole-module-optimization'
......
github "thoughtbot/Runes" "master"
github "thoughtbot/Runes" ~> 4.0.0
github "thoughtbot/Curry" "master"
github "thoughtbot/Curry" ~> 3.0.0
github "thoughtbot/Curry" "408134ffa8dd1c09b0050f65eae300381b934bf6"
github "thoughtbot/Runes" "e00cf681ec03a2dbf2b4cd6dd1e24d522f55474b"
github "thoughtbot/Curry" "v3.0.0"
github "thoughtbot/Runes" "v4.0.0"
import PackageDescription
let package = Package(
name: "Argo",
dependencies: [
.Package(url: "https://github.com/thoughtbot/Runes.git", majorVersion: 4)
]
)
<img src="https://raw.githubusercontent.com/thoughtbot/Argo/master/Resources/Logo.png" width="250" />
<img src="https://raw.githubusercontent.com/thoughtbot/Argo/master/web/Logo.png" width="250" />
# Argo [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
......@@ -23,7 +23,7 @@ Here is the current Swift compatibility breakdown:
| Swift Version | Argo Version |
| ------------- | ------------ |
| 3.X | master |
| 3.X | 4.X |
| 2.2, 2.3 | 3.X |
| 2.0, 2.1 | 2.X |
| 1.2 - 2.0 | 1.X |
......
#import <Foundation/Foundation.h>
//! Project version number for Argo.
FOUNDATION_EXPORT double ArgoVersionNumber;
//! Project version string for Argo.
FOUNDATION_EXPORT const unsigned char ArgoVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Argo/PublicHeader.h>
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.0.0-beta.1</string>
<string>4.1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
import Runes
// pure merge for Dictionaries
func + <T, U>(lhs: [T: U], rhs: [T: U]) -> [T: U] {
var merged = lhs
for (key, val) in rhs {
merged[key] = val
}
return merged
}
extension Dictionary {
func map<T>(_ f: (Value) -> T) -> [Key: T] {
var accum = Dictionary<Key, T>(minimumCapacity: self.count)
for (key, value) in self {
accum[key] = f(value)
}
return accum
}
}
func <^> <T, U, V>(f: (T) -> U, x: [V: T]) -> [V: U] {
return x.map(f)
}
import Foundation
extension NSNumber {
var isBool: Bool {
return CFBooleanGetTypeID() == CFGetTypeID(self)
}
}
/**
Default implementation of `Decodable` for `RawRepresentable` types using
`String` as the raw value.
*/
public extension Decodable where Self.DecodedType == Self, Self: RawRepresentable, Self.RawValue == String {
static func decode(_ json: JSON) -> Decoded<Self> {
switch json {
case let .string(s):
return self.init(rawValue: s)
.map(pure) ?? .typeMismatch(expected: "rawValue for \(self)", actual: json)
default:
return .typeMismatch(expected: "String", actual: json)
}
}
}
/**
Default implementation of `Decodable` for `RawRepresentable` types using
`Int` as the raw value.
*/
public extension Decodable where Self.DecodedType == Self, Self: RawRepresentable, Self.RawValue == Int {
static func decode(_ json: JSON) -> Decoded<Self> {
switch json {
case let .number(n):
return self.init(rawValue: n.intValue)
.map(pure) ?? .typeMismatch(expected: "rawValue for \(self)", actual: json)
default:
return .typeMismatch(expected: "Int", actual: json)
}
}
}
/**
Create a new array of unwrapped `.Success` values, filtering out `.Failure`s.
This will iterate through the array of `Decoded<T>` elements and safely
unwrap the values.
If the element is `.Success(T)`, it will unwrap the value and add it into the
array.
If the element is `.Failure`, it will not be added to the new array.
- parameter xs: An array of `Decoded<T>` values
- returns: An array of unwrapped values of type `T`
*/
public func catDecoded<T>(_ xs: [Decoded<T>]) -> [T] {
var accum: [T] = []
accum.reserveCapacity(xs.count)
for x in xs {
switch x {
case let .success(value): accum.append(value)
case .failure: continue
}
}
return accum
}
/**
Create a new dictionary of unwrapped `.Success` values, filtering out
`.Failure`s.
This will iterate through the dictionary of `Decoded<T>` elements and safely
unwrap the values.
If the element is `.Success(T)`, it will unwrap the value and assign it to
the existing key in the new dictionary.
If the element is `.Failure`, it will not be added to the new dictionary.
- parameter xs: A dictionary of `Decoded<T>` values assigned to `String` keys
- returns: A dictionary of unwrapped values of type `T` assigned to `String` keys
*/
public func catDecoded<T>(_ xs: [String: Decoded<T>]) -> [String: T] {
var accum = Dictionary<String, T>(minimumCapacity: xs.count)
for (key, x) in xs {
switch x {
case let .success(value): accum[key] = value
case .failure: continue
}
}
return accum
}
/**
Attempt to transform `Any` into a `Decodable` value.
This function takes `Any` (usually the output from
`NSJSONSerialization`) and attempts to transform it into a `Decodable` value.
This works based on the type you ask for.
For example, the following code attempts to decode to `Decoded<String>`,
because that's what we have explicitly stated is the return type:
```
do {
let object = try NSJSONSerialization.JSONObjectWithData(data, options: nil)
let str: Decoded<String> = decode(object)
} catch {
// handle error
}
```
- parameter object: The `Any` instance to attempt to decode
- returns: A `Decoded<T>` value where `T` is `Decodable`
*/
public func decode<T: Decodable>(_ object: Any) -> Decoded<T> where T == T.DecodedType {
return T.decode(JSON(object))
}
/**
Attempt to transform `Any` into an `Array` of `Decodable` values.
This function takes `Any` (usually the output from
`NSJSONSerialization`) and attempts to transform it into an `Array` of
`Decodable` values. This works based on the type you ask for.
For example, the following code attempts to decode to
`Decoded<[String]>`, because that's what we have explicitly stated is
the return type:
```
do {
let object = try NSJSONSerialization.JSONObjectWithData(data, options: nil)
let str: Decoded<[String]> = decode(object)
} catch {
// handle error
}
```
- parameter object: The `Any` instance to attempt to decode
- returns: A `Decoded<[T]>` value where `T` is `Decodable`
*/
public func decode<T: Decodable>(_ object: Any) -> Decoded<[T]> where T == T.DecodedType {
return Array<T>.decode(JSON(object))
}
/**
Attempt to transform `Any` into a `Decodable` value and return an `Optional`.
This function takes `Any` (usually the output from
`NSJSONSerialization`) and attempts to transform it into a `Decodable` value,
returning an `Optional`. This works based on the type you ask for.
For example, the following code attempts to decode to `Optional<String>`,
because that's what we have explicitly stated is the return type:
```
do {
let object = try NSJSONSerialization.JSONObjectWithData(data, options: nil)
let str: String? = decode(object)
} catch {
// handle error
}
```
- parameter object: The `Any` instance to attempt to decode
- returns: An `Optional<T>` value where `T` is `Decodable`
*/
public func decode<T: Decodable>(_ object: Any) -> T? where T == T.DecodedType {
return decode(object).value
}
/**
Attempt to transform `Any` into an `Array` of `Decodable` values and
return an `Optional`.
This function takes `Any` (usually the output from
`NSJSONSerialization`) and attempts to transform it into an `Array` of
`Decodable` values, returning an `Optional`. This works based on the type you
ask for.
For example, the following code attempts to decode to
`Optional<[String]>`, because that's what we have explicitly stated is
the return type:
```
do {
let object = try NSJSONSerialization.JSONObjectWithData(data, options: nil)
let str: [String]? = decode(object)
} catch {
// handle error
}
```
- parameter object: The `Any` instance to attempt to decode
- returns: An `Optional<[T]>` value where `T` is `Decodable`
*/
public func decode<T: Decodable>(_ object: Any) -> [T]? where T == T.DecodedType {
return decode(object).value
}
/**
Attempt to transform `Any` into a `Decodable` value using a specified
root key.
This function attempts to extract the embedded `JSON` object from the
dictionary at the specified key and transform it into a `Decodable` value.
This works based on the type you ask for.
For example, the following code attempts to decode to `Decoded<String>`,
because that's what we have explicitly stated is the return type:
```
do {
let dict = try NSJSONSerialization.JSONObjectWithData(data, options: nil) as? [String: Any] ?? [:]
let str: Decoded<String> = decode(dict, rootKey: "value")
} catch {
// handle error
}
```
- parameter dict: The dictionary containing the `Any` instance to
attempt to decode
- parameter rootKey: The root key that contains the object to decode
- returns: A `Decoded<T>` value where `T` is `Decodable`
*/
public func decode<T: Decodable>(_ dict: [String: Any], rootKey: String) -> Decoded<T> where T == T.DecodedType {
return JSON(dict as Any) <| rootKey
}
/**
Attempt to transform `Any` into an `Array` of `Decodable` value using a
specified root key.
This function attempts to extract the embedded `JSON` object from the
dictionary at the specified key and transform it into an `Array` of
`Decodable` values. This works based on the type you ask for.
For example, the following code attempts to decode to `Decoded<[String]>`,
because that's what we have explicitly stated is the return type:
```
do {
let dict = try NSJSONSerialization.JSONObjectWithData(data, options: nil) as? [String: Any] ?? [:]
let str: Decoded<[String]> = decode(dict, rootKey: "value")
} catch {
// handle error
}
```
- parameter dict: The dictionary containing the `Any` instance to
attempt to decode
- parameter rootKey: The root key that contains the object to decode
- returns: A `Decoded<[T]>` value where `T` is `Decodable`
*/
public func decode<T: Decodable>(_ dict: [String: Any], rootKey: String) -> Decoded<[T]> where T == T.DecodedType {
return JSON(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
dictionary at the specified key and transform it into a `Decodable` value,
returning an `Optional`. This works based on the type you ask for.
For example, the following code attempts to decode to `Optional<String>`,
because that's what we have explicitly stated is the return type:
```
do {
let dict = try NSJSONSerialization.JSONObjectWithData(data, options: nil) as? [String: Any] ?? [:]
let str: String? = decode(dict, rootKey: "value")
} catch {
// handle error
}
```
- parameter dict: The dictionary containing the `Any` instance to
attempt to decode
- parameter rootKey: The root key that contains the object to decode
- returns: A `Decoded<T>` value where `T` is `Decodable`
*/
public func decode<T: Decodable>(_ dict: [String: Any], rootKey: String) -> T? where T == T.DecodedType {
return decode(dict, rootKey: rootKey).value
}
/**
Attempt to transform `Any` into an `Array` of `Decodable` value using a
specified root key and return an `Optional`
This function attempts to extract the embedded `JSON` object from the
dictionary at the specified key and transform it into an `Array` of
`Decodable` values, returning an `Optional`. This works based on the type you
ask for.
For example, the following code attempts to decode to `Optional<[String]>`,
because that's what we have explicitly stated is the return type:
```
do {
let dict = try NSJSONSerialization.JSONObjectWithData(data, options: nil) as? [String: Any] ?? [:]
let str: [String]? = decode(dict, rootKey: "value")
} catch {
// handle error
}
```
- parameter dict: The dictionary containing the `Any` instance to
attempt to decode
- parameter rootKey: The root key that contains the object to decode
- returns: A `Decoded<[T]>` value where `T` is `Decodable`
*/
public func decode<T: Decodable>(_ dict: [String: Any], rootKey: String) -> [T]? where T == T.DecodedType {
return decode(dict, rootKey: rootKey).value
}
import Runes
/**
Reduce a sequence with a combinator that returns a `Decoded` type, flattening
the result.
This function is a helper function to make it easier to deal with combinators
that return `Decoded` types without ending up with multiple levels of nested
`Decoded` values.
For example, it can be used to traverse a JSON structure with an array of
keys. See the implementations of `<|` and `<||` that take an array of keys for
a real-world example of this use case.
- parameter sequence: Any `SequenceType` of values
- parameter initial: The initial value for the accumulator
- parameter combine: The combinator, which returns a `Decoded` type
- returns: The result of iterating the combinator over every element of the
sequence and flattening the result
*/
public func flatReduce<S: Sequence, U>(_ sequence: S, initial: U, combine: (U, S.Iterator.Element) -> Decoded<U>) -> Decoded<U> {
return sequence.reduce(pure(initial)) { accum, x in
accum >>- { combine($0, x) }
}
}
/**
Convert an `Array` of `Decoded<T>` values to a `Decoded` `Array` of unwrapped
`T` values.
This performs an all-or-nothing transformation on the array. If every element
is `.Success`, then this function will return `.Success` along with the array
of unwrapped `T` values.
However, if _any_ of the elements are `.Failure`, this function will also
return `.Failure`, and no array will be returned.
- parameter xs: An `Array` of `Decoded<T>` values
- returns: A `Decoded` `Array` of unwrapped `T` values
*/
public func sequence<T>(_ xs: [Decoded<T>]) -> Decoded<[T]> {
var accum: [T] = []
accum.reserveCapacity(xs.count)
for x in xs {
switch x {
case let .success(value): accum.append(value)
case let .failure(error): return .failure(error)
}
}
return pure(accum)
}
/**
Convert a `Dictionary` with `Decoded<T>` values to a `Decoded` `Dictionary`
with unwrapped `T` values.
This performs an all-or-nothing transformation on the dictionary. If every
key is associated with a `.Success` value, then this function will return
`.Success` along with the dictionary of unwrapped `T` values associated with
their original keys.
However, if _any_ of the keys are associated with a `.Failure` value, this
function will also return `.Failure`, and no dictionary will be returned.
- parameter xs: A `Dictionary` of arbitrary keys and `Decoded<T>` values
- returns: A `Decoded` `Dictionary` of unwrapped `T` values assigned to their
original keys
*/
public func sequence<Key, Value>(_ xs: [Key: Decoded<Value>]) -> Decoded<[Key: Value]> {
var accum = Dictionary<Key, Value>(minimumCapacity: xs.count)
for (key, x) in xs {
switch x {
case let .success(value): accum[key] = value
case let .failure(error): return .failure(error)
}
}
return pure(accum)
}
import Runes
precedencegroup ArgoDecodePrecedence {
associativity: left
higherThan: RunesApplicativeSequencePrecedence
lowerThan: NilCoalescingPrecedence
}
infix operator <| : ArgoDecodePrecedence
infix operator <|? : ArgoDecodePrecedence
infix operator <|| : ArgoDecodePrecedence
infix operator <||? : ArgoDecodePrecedence
import Runes
/**
Attempt to decode a value at the specified key into the requested type.
This operator 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 json: The `JSON` object containing the key
- parameter key: The key for the object to decode
- returns: A `Decoded` value representing the success or failure of the
decode operation
*/
public func <| <A: Decodable>(json: JSON, key: String) -> Decoded<A> where A == A.DecodedType {
return json <| [key]
}
/**
Attempt to decode an optional value at the specified key into the requested
type.
This operator is used to decode an optional value from the `JSON`. If the key
isn't present in the `JSON`, this will still return `.Success`. However, if
the key exists but the object assigned to that key is unable to be decoded
into the requested type, this will return `.Failure`.
- parameter json: The `JSON` object containing the key
- parameter key: The key for the object to decode
- returns: A `Decoded` optional value representing the success or failure of
the decode operation
*/
public func <|? <A: Decodable>(json: JSON, key: String) -> Decoded<A?> where A == A.DecodedType {
return json <|? [key]
}
/**
Attempt to decode a value at the specified key path into the requested type.
This operator 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 json: The `JSON` object containing the key
- parameter keys: The key path for the object to decode, represented by an
array of strings
- returns: A `Decoded` value representing the success or failure of the
decode operation
*/
public func <| <A: Decodable>(json: JSON, keys: [String]) -> Decoded<A> where A == A.DecodedType {
return flatReduce(keys, initial: json, combine: decodedJSON) >>- A.decode
}
/**
Attempt to decode an optional value at the specified key path into the
requested type.
This operator 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 json: The `JSON` object containing the key
- parameter keys: The key path for the object to decode, represented by an
array of strings
- returns: A `Decoded` optional value representing the success or failure of
the decode operation
*/
public func <|? <A: Decodable>(json: JSON, keys: [String]) -> Decoded<A?> where A == A.DecodedType {
switch flatReduce(keys, initial: json, combine: decodedJSON) {
case .failure: return .success(.none)
case .success(let x): return A.decode(x) >>- { .success(.some($0)) }
}
}
/**
Attempt to decode an array of values at the specified key into the requested
type.
This operator is used to decode a mandatory array of values from the `JSON`.
If the decoding of any of the objects fail for any reason, this will result
in a `.Failure` being returned.
- parameter json: The `JSON` object containing the key
- parameter key: The key for the array of objects to decode
- returns: A `Decoded` array of values representing the success or failure of
the decode operation
*/
public func <|| <A: Decodable>(json: JSON, key: String) -> Decoded<[A]> where A == A.DecodedType {
return json <|| [key]
}
/**
Attempt to decode an optional array of values at the specified key into the
requested type.