Skip to content

Instantly share code, notes, and snippets.

@akisute
Created January 1, 2015 13:07
Show Gist options
  • Save akisute/e2d523b821ca0fad46e2 to your computer and use it in GitHub Desktop.
Save akisute/e2d523b821ca0fad46e2 to your computer and use it in GitHub Desktop.
import Foundation
public class JSON {
private let _value:AnyObject
public init(_ obj:AnyObject) { self._value = obj }
public init(_ json:JSON){ self._value = json._value }
}
extension JSON {
public typealias NSNull = Foundation.NSNull
public typealias NSError = Foundation.NSError
public class var null:NSNull { return NSNull() }
public convenience init(data:NSData) {
var err:NSError?
var obj:AnyObject? = NSJSONSerialization.JSONObjectWithData(
data, options:nil, error:&err
)
self.init(err != nil ? err! : obj!)
}
public convenience init(string:String) {
let enc:NSStringEncoding = NSUTF8StringEncoding
self.init(data: string.dataUsingEncoding(enc)!)
}
public class func parse(string:String)->JSON {
return JSON(string:string)
}
public convenience init(nsurl:NSURL) {
var enc:NSStringEncoding = NSUTF8StringEncoding
var err:NSError?
let str:String? =
NSString(
contentsOfURL:nsurl, usedEncoding:&enc, error:&err
)
if err != nil { self.init(err!) }
else { self.init(string:str!) }
}
public class func fromNSURL(nsurl:NSURL) -> JSON {
return JSON(nsurl:nsurl)
}
public convenience init(url:String) {
if let nsurl = NSURL(string:url) as NSURL? {
self.init(nsurl:nsurl)
} else {
self.init(NSError(
domain:"JSONErrorDomain",
code:400,
userInfo:[NSLocalizedDescriptionKey: "malformed URL"]
)
)
}
}
public class func fromURL(url:String) -> JSON {
return JSON(url:url)
}
public class func stringify(obj:AnyObject, pretty:Bool=false) -> String! {
if !NSJSONSerialization.isValidJSONObject(obj) {
JSON(NSError(
domain:"JSONErrorDomain",
code:422,
userInfo:[NSLocalizedDescriptionKey: "not an JSON object"]
))
return nil
}
return JSON(obj).toString(pretty:pretty)
}
}
extension JSON {
public subscript(idx:Int) -> JSON {
switch _value {
case let err as NSError:
return self
case let ary as NSArray:
if 0 <= idx && idx < ary.count {
return JSON(ary[idx])
}
return JSON(NSError(
domain:"JSONErrorDomain", code:404, userInfo:[
NSLocalizedDescriptionKey:
"[\(idx)] is out of range"
]))
default:
return JSON(NSError(
domain:"JSONErrorDomain", code:500, userInfo:[
NSLocalizedDescriptionKey: "not an array"
]))
}
}
public subscript(key:String)->JSON {
switch _value {
case let err as NSError:
return self
case let dic as NSDictionary:
if let val:AnyObject = dic[key] { return JSON(val) }
return JSON(NSError(
domain:"JSONErrorDomain", code:404, userInfo:[
NSLocalizedDescriptionKey:
"[\"\(key)\"] not found"
]))
default:
return JSON(NSError(
domain:"JSONErrorDomain", code:500, userInfo:[
NSLocalizedDescriptionKey: "not an object"
]))
}
}
public var data:AnyObject? {
return self.isError ? nil : self._value
}
public var type:String {
switch _value {
case is NSError: return "NSError"
case is NSNull: return "NSNull"
case let o as NSNumber:
switch String.fromCString(o.objCType)! {
case "c", "C": return "Bool"
case "q", "l", "i", "s": return "Int"
case "Q", "L", "I", "S": return "UInt"
default: return "Double"
}
case is NSString: return "String"
case is NSArray: return "Array"
case is NSDictionary: return "Dictionary"
default: return "NSError"
}
}
public var isError: Bool { return _value is NSError }
public var isNull: Bool { return _value is NSNull }
public var isBool: Bool { return type == "Bool" }
public var isInt: Bool { return type == "Int" }
public var isUInt: Bool { return type == "UInt" }
public var isDouble: Bool { return type == "Double" }
public var isNumber: Bool {
if let o = _value as? NSNumber {
let t = String.fromCString(o.objCType)!
return t != "c" && t != "C"
}
return false
}
public var isString: Bool { return _value is NSString }
public var isArray: Bool { return _value is NSArray }
public var isDictionary: Bool { return _value is NSDictionary }
public var isLeaf: Bool {
return !(isArray || isDictionary || isError)
}
public var asError:NSError? {
return _value as? NSError
}
public var asNull:NSNull? {
return _value is NSNull ? JSON.null : nil
}
public var asBool:Bool? {
switch _value {
case let o as NSNumber:
switch String.fromCString(o.objCType)! {
case "c", "C": return Bool(o.boolValue)
default:
return nil
}
default: return nil
}
}
public var asInt:Int? {
switch _value {
case let o as NSNumber:
switch String.fromCString(o.objCType)! {
case "c", "C":
return nil
default:
return Int(o.longLongValue)
}
default: return nil
}
}
public var asDouble:Double? {
switch _value {
case let o as NSNumber:
switch String.fromCString(o.objCType)! {
case "c", "C":
return nil
default:
return Double(o.doubleValue)
}
default: return nil
}
}
public var asNumber:Double? { return asDouble }
public var asString:String? {
switch _value {
case let o as NSString:
return o as String
default: return nil
}
}
public var asArray:[JSON]? {
switch _value {
case let o as NSArray:
var result = [JSON]()
for v:AnyObject in o { result.append(JSON(v)) }
return result
default:
return nil
}
}
public var asDictionary:[String:JSON]? {
switch _value {
case let o as NSDictionary:
var result = [String:JSON]()
for (k:AnyObject, v:AnyObject) in o {
result[k as String] = JSON(v)
}
return result
default: return nil
}
}
public var asDate:NSDate? {
if let dateString = _value as? NSString {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZ"
return dateFormatter.dateFromString(dateString)
}
return nil
}
public var length:Int {
switch _value {
case let o as NSArray: return o.count
case let o as NSDictionary: return o.count
default: return 0
}
}
}
extension JSON : SequenceType {
public func generate()->GeneratorOf<(AnyObject,JSON)> {
switch _value {
case let o as NSArray:
var i = -1
return GeneratorOf<(AnyObject, JSON)> {
if ++i == o.count { return nil }
return (i, JSON(o[i]))
}
case let o as NSDictionary:
var ks = o.allKeys.reverse()
return GeneratorOf<(AnyObject, JSON)> {
if ks.isEmpty { return nil }
let k = ks.removeLast() as String
return (k, JSON(o.valueForKey(k)!))
}
default:
return GeneratorOf<(AnyObject, JSON)>{ nil }
}
}
public func mutableCopyOfTheObject() -> AnyObject {
return _value.mutableCopy()
}
}
extension JSON : Printable {
public func toString(pretty:Bool=false)->String {
switch _value {
case is NSError: return "\(_value)"
case is NSNull: return "null"
case let o as NSNumber:
switch String.fromCString(o.objCType)! {
case "c", "C":
return o.boolValue.description
case "q", "l", "i", "s":
return o.longLongValue.description
case "Q", "L", "I", "S":
return o.unsignedLongLongValue.description
default:
switch o.doubleValue {
case 0.0/0.0: return "0.0/0.0"
case -1.0/0.0: return "-1.0/0.0"
case +1.0/0.0: return "+1.0/0.0"
default:
return o.doubleValue.description
}
}
case let o as NSString:
return o.debugDescription
default:
let opts = pretty
? NSJSONWritingOptions.PrettyPrinted : nil
if let data = NSJSONSerialization.dataWithJSONObject(
_value, options:opts, error:nil
) as NSData? {
if let nsstring = NSString(
data:data, encoding:NSUTF8StringEncoding
) as NSString? {
return nsstring
}
}
return "YOU ARE NOT SUPPOSED TO SEE THIS!"
}
}
public var description:String { return toString() }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment