Skip to content

Instantly share code, notes, and snippets.

@rnapier
Last active August 29, 2015 14:05

Revisions

  1. rnapier revised this gist Aug 19, 2014. 1 changed file with 99 additions and 6 deletions.
    105 changes: 99 additions & 6 deletions gistfile1.swift
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,55 @@
    //
    // Version 2 of pagesFromData from Functional Wish Fulfillment
    // http://robnapier.net/functional-wish-fulfillment
    //

    import Foundation

    func pagesFromData(data: NSData) -> Result<[Page]> {

    // 1. Parse the NSData into a JSON object
    switch asJSON(data) {
    case .Success(let boxJson):

    // 2. Make sure the JSON object is an array
    switch asJSONArray(boxJson.unbox) {
    case .Success(let boxArray):

    // 3. Get the second element
    switch secondElement(boxArray.unbox) {
    case .Success(let elementBox):

    // 4. Make sure the second element is a list of strings
    switch asStringList(elementBox.unbox) {
    case .Success(let titlesBox):

    // 5. Convert those strings into pages
    return asPages(titlesBox.unbox)

    case .Failure(let error):
    return .Failure(error)
    }
    case .Failure(let error):
    return .Failure(error)
    }
    case .Failure(let error):
    return .Failure(error)
    }
    case .Failure(let error):
    return .Failure(error)
    }
    }

    func asJSON(data: NSData) -> Result<JSON> {
    var error: NSError?
    let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &error)

    if let error = error {
    return .Failure(error)
    } else if let json: JSON = json {
    return .Success(Box(json))
    }
    else {
    switch (json, error) {
    case (_, .Some(let error)): return .Failure(error)

    case (.Some(let json), _): return .Success(Box(json))

    default:
    fatalError("Received neither JSON nor an error")
    return .Failure(NSError())
    }
    @@ -39,3 +81,54 @@ func asStringList(array: JSON) -> Result<[String]> {
    func asPages(titles: [String]) -> Result<[Page]> {
    return .Success(Box(titles.map { Page(title: $0) }))
    }

    enum Result<A> {
    case Success(Box<A>)
    case Failure(NSError)
    }
    final class Box<T> {
    let unbox: T
    init(_ value: T) { self.unbox = value }
    }

    extension Result: Printable {
    var description: String {
    switch self {
    case .Success(let box):
    return "Success: \(box.unbox)"
    case .Failure(let error):
    return "Failure: \(error.localizedDescription)"
    }
    }
    }

    struct Page {
    let title: String
    }

    extension Page: Printable {
    var description: String {
    return title
    }
    }

    typealias JSON = AnyObject
    typealias JSONArray = [JSON]

    extension NSError {
    convenience init(localizedDescription: String) {
    self.init(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: localizedDescription])
    }
    }

    func asJSONData(string: NSString) -> NSData {
    return string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    }

    let goodPagesJson = asJSONData("[\"a\",[\"Animal\",\"Association football\",\"Arthropod\",\"Australia\",\"AllMusic\",\"African American (U.S. Census)\",\"Album\",\"Angiosperms\",\"Actor\",\"American football\",\"Austria\",\"Argentina\",\"American Civil War\",\"Administrative divisions of Iran\",\"Alternative rock\"]]")

    pagesFromData(goodPagesJson).description

    let corruptJson = asJSONData("a\",[\"Animal\",\"Association football\",\"Arthropod\",\"Australia\",\"AllMusic\",\"African American (U.S. Census)\",\"Album\",\"Angiosperms\",\"Actor\",\"American football\",\"Austria\",\"Argentina\",\"American Civil War\",\"Administrative divisions of Iran\",\"Alternative rock\"]]")

    pagesFromData(corruptJson).description
  2. rnapier revised this gist Aug 17, 2014. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions gistfile1.swift
    Original file line number Diff line number Diff line change
    @@ -35,3 +35,7 @@ func asStringList(array: JSON) -> Result<[String]> {
    return .Failure(NSError(localizedDescription: "Unexpected string list: \(array)"))
    }
    }

    func asPages(titles: [String]) -> Result<[Page]> {
    return .Success(Box(titles.map { Page(title: $0) }))
    }
  3. rnapier revised this gist Aug 17, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.swift
    Original file line number Diff line number Diff line change
    @@ -17,7 +17,7 @@ func asJSONArray(json: JSON) -> Result<JSONArray> {
    if let array = json as? JSONArray {
    return .Success(Box(array))
    } else {
    return .Failure(NSError(localizedDescription: "Expected array, received: \(json)"))
    return .Failure(NSError(localizedDescription: "Expected array. Got: \(json)"))
    }
    }

  4. rnapier created this gist Aug 17, 2014.
    37 changes: 37 additions & 0 deletions gistfile1.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,37 @@
    func asJSON(data: NSData) -> Result<JSON> {
    var error: NSError?
    let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &error)

    if let error = error {
    return .Failure(error)
    } else if let json: JSON = json {
    return .Success(Box(json))
    }
    else {
    fatalError("Received neither JSON nor an error")
    return .Failure(NSError())
    }
    }

    func asJSONArray(json: JSON) -> Result<JSONArray> {
    if let array = json as? JSONArray {
    return .Success(Box(array))
    } else {
    return .Failure(NSError(localizedDescription: "Expected array, received: \(json)"))
    }
    }

    func secondElement(array: JSONArray) -> Result<JSON> {
    if array.count < 2 {
    return .Failure(NSError(localizedDescription:"Could not get second element. Array too short: \(array.count)"))
    }
    return .Success(Box(array[1]))
    }

    func asStringList(array: JSON) -> Result<[String]> {
    if let string = array as? [String] {
    return .Success(Box(string))
    } else {
    return .Failure(NSError(localizedDescription: "Unexpected string list: \(array)"))
    }
    }