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