Skip to content

Commit

Permalink
Dictionary conversion and deserialization
Browse files Browse the repository at this point in the history
Additional changes:
- NSDate to String conversion.
- Serializable protocol.
  • Loading branch information
isair committed Apr 15, 2016
1 parent fb75c18 commit 82901fd
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 27 deletions.
8 changes: 8 additions & 0 deletions JSONHelper.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
5F6A2F4A1CC0116D00EF50C4 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */; };
5F6A2F4B1CC0116D00EF50C4 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */; };
5F6A2F4C1CC0116D00EF50C4 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */; };
5F6A2F4E1CC096DA00EF50C4 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */; };
5F6A2F4F1CC096DA00EF50C4 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */; };
5F6A2F501CC096DA00EF50C4 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */; };
5F8F88231CA5F32E00EF50C4 /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F8F88221CA5F32E00EF50C4 /* DictionaryTests.swift */; };
5F8F88251CA5F33500EF50C4 /* EnumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F8F88241CA5F33500EF50C4 /* EnumTests.swift */; };
5F928D991C0D469F00EF50C4 /* JSONHelper-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F928D981C0D469F00EF50C4 /* JSONHelper-tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -102,6 +105,7 @@
5F31FF7B1C53497600EF50C4 /* FloatTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatTests.swift; sourceTree = "<group>"; };
5F31FF7D1C53499000EF50C4 /* NSDecimalNumberTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDecimalNumberTests.swift; sourceTree = "<group>"; };
5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONHelper.swift; sourceTree = "<group>"; };
5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Serialization.swift; sourceTree = "<group>"; };
5F8F88221CA5F32E00EF50C4 /* DictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryTests.swift; sourceTree = "<group>"; };
5F8F88241CA5F33500EF50C4 /* EnumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumTests.swift; sourceTree = "<group>"; };
5F928D961C0D469F00EF50C4 /* JSONHelper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JSONHelper.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -234,6 +238,7 @@
5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */,
5F31FF5B1C533AD400EF50C4 /* Conversion.swift */,
5F31FF5D1C533AE000EF50C4 /* Deserialization.swift */,
5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */,
5FC1A4851B1CFBE500EF50C4 /* Extensions */,
5F133DA01C3840A200EF50C4 /* Support */,
5FAD07671A70F2FC00C4D09E /* Supporting Files */,
Expand Down Expand Up @@ -545,6 +550,7 @@
5F133DA41C3840CA00EF50C4 /* JSONAPI.swift in Sources */,
5F31FF741C5348FE00EF50C4 /* Double.swift in Sources */,
5F31FF621C533E9900EF50C4 /* Color.swift in Sources */,
5F6A2F501CC096DA00EF50C4 /* Serialization.swift in Sources */,
5F6A2F4C1CC0116D00EF50C4 /* JSONHelper.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -555,6 +561,7 @@
files = (
5FC1A4941B1D1D8B00EF50C4 /* NSURL.swift in Sources */,
5F31FF6E1C5348F000EF50C4 /* NSDecimalNumber.swift in Sources */,
5F6A2F4E1CC096DA00EF50C4 /* Serialization.swift in Sources */,
5FC1A4891B1D024500EF50C4 /* Int.swift in Sources */,
5FC1A48E1B1D057B00EF50C4 /* Bool.swift in Sources */,
5F31FF601C533E9900EF50C4 /* Color.swift in Sources */,
Expand Down Expand Up @@ -604,6 +611,7 @@
files = (
5FC1A4951B1D1D8B00EF50C4 /* NSURL.swift in Sources */,
5F31FF6F1C5348F000EF50C4 /* NSDecimalNumber.swift in Sources */,
5F6A2F4F1CC096DA00EF50C4 /* Serialization.swift in Sources */,
5FC1A48C1B1D036700EF50C4 /* Int.swift in Sources */,
5F31FF611C533E9900EF50C4 /* Color.swift in Sources */,
5F31FF651C533EA000EF50C4 /* Conversion.swift in Sources */,
Expand Down
46 changes: 34 additions & 12 deletions JSONHelper/Conversion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,45 @@ public func <-- <C: Convertible, T>(inout lhs: [C], rhs: T?) throws -> [C] {

// MARK: - Dictionary Conversion

public func <-- <C: Convertible, T, U>(inout lhs: [T : C]?, rhs: U?) throws -> [T : C]? {
if let dictionary = rhs as? [T : C] {
lhs = [T : C]()
for (key, value) in dictionary {
var convertedValue: C?
try convertedValue <-- value
if let convertedValue = convertedValue {
lhs?[key] = convertedValue
}
}
} else {
public func <-- <T, C: Convertible, U>(inout lhs: [T : C]?, rhs: [T : U]?) throws -> [T : C]? {
guard let rhs = rhs else {
lhs = nil
return lhs
}

lhs = [T : C]()
for (key, value) in rhs {
var convertedValue: C?
try convertedValue <-- value
if let convertedValue = convertedValue {
lhs?[key] = convertedValue
}
}

return lhs
}

public func <-- <T, C: Convertible, U>(inout lhs: [T : C], rhs: [T : U]?) throws -> [T : C] {
var newValue: [T : C]?
try newValue <-- rhs
lhs = newValue ?? lhs
return lhs
}

public func <-- <C: Convertible, T>(inout lhs: [T : C], rhs: T?) throws -> [T : C] {
public func <-- <T, C: Convertible, U>(inout lhs: [T : C]?, rhs: U?) throws -> [T : C]? {
guard let rhs = rhs else {
lhs = nil
return lhs
}

if let elements = rhs as? NSDictionary as? [T : AnyObject] {
return try lhs <-- elements
}

throw ConversionError.UnsupportedType
}

public func <-- <T, C: Convertible, U>(inout lhs: [T : C], rhs: U?) throws -> [T : C] {
var newValue: [T : C]?
try newValue <-- rhs
lhs = newValue ?? lhs
Expand Down
70 changes: 61 additions & 9 deletions JSONHelper/Deserialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,30 @@ public protocol Deserializable {
init(dictionary: [String : AnyObject]) throws
}

// MARK: - Helper Methods

private func dataStringToObject(dataString: String) -> AnyObject? {
guard let data: NSData = dataString.dataUsingEncoding(NSUTF8StringEncoding) else { return nil }
var jsonObject: AnyObject?
do {
jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0))
} catch {}
return jsonObject
}

// MARK: - Basic Deserialization

public func <-- <D: Deserializable, T>(inout lhs: D?, rhs: T?) throws -> D? {
let cleanedValue = JSONHelper.convertToNilIfNull(rhs)
print(cleanedValue)

if let jsonObject = cleanedValue as? NSDictionary as? [String : AnyObject] {
lhs = try D(dictionary: jsonObject)
} else if let string = cleanedValue as? String {
try lhs <-- dataStringToObject(string)
} else {
lhs = nil
}

return lhs
}

Expand All @@ -31,6 +45,8 @@ public func <-- <D: Deserializable, T>(inout lhs: D, rhs: T?) throws -> D {
return lhs
}

// MARK: - Array Deserialization

public func <-- <D: Deserializable, T>(inout lhs: [D]?, rhs: [T]?) throws -> [D]? {
guard let rhs = rhs else { return nil }

Expand Down Expand Up @@ -70,13 +86,49 @@ public func <-- <D: Deserializable, T>(inout lhs: [D], rhs: T?) throws -> [D] {
return lhs
}

// MARK: - Helper methods
// MARK: - Dictionary Deserialization

private func dataStringToObject(dataString: String) -> AnyObject? {
guard let data: NSData = dataString.dataUsingEncoding(NSUTF8StringEncoding) else { return nil }
var jsonObject: AnyObject?
do {
jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0))
} catch {}
return jsonObject
public func <-- <T, D: Deserializable, U>(inout lhs: [T : D]?, rhs: [T : U]?) throws -> [T : D]? {
guard let rhs = rhs else {
lhs = nil
return lhs
}

lhs = [T : D]()
for (key, value) in rhs {
var convertedValue: D?
try convertedValue <-- value
if let convertedValue = convertedValue {
lhs?[key] = convertedValue
}
}

return lhs
}

public func <-- <T, D: Deserializable, U>(inout lhs: [T : D], rhs: [T : U]?) throws -> [T : D] {
var newValue: [T : D]?
try newValue <-- rhs
lhs = newValue ?? lhs
return lhs
}

public func <-- <T, D: Deserializable, U>(inout lhs: [T : D]?, rhs: U?) throws -> [T : D]? {
guard let rhs = rhs else {
lhs = nil
return lhs
}

if let elements = rhs as? NSDictionary as? [T : AnyObject] {
return try lhs <-- elements
}

throw ConversionError.UnsupportedType
}

public func <-- <T, D: Deserializable, U>(inout lhs: [T : D], rhs: U?) throws -> [T : D] {
var newValue: [T : D]?
try newValue <-- rhs
lhs = newValue ?? lhs
return lhs
}
2 changes: 2 additions & 0 deletions JSONHelper/Extensions/String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ extension String: Convertible {
return stringValue
} else if let intValue = value as? Int {
return "\(intValue)"
} else if let dateValue = value as? NSDate {
return JSONHelper.dateFormatter.stringFromDate(dateValue)
}

throw ConversionError.UnsupportedType
Expand Down
14 changes: 14 additions & 0 deletions JSONHelper/Serialization.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Copyright © 2016 Baris Sencan. All rights reserved.
//

import Foundation

/// TODOC
public protocol Serializable {

/// TODOC
func toDictionary() throws -> [String : AnyObject]
}

// TODO
4 changes: 2 additions & 2 deletions JSONHelperTests/ArrayTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ class ArrayTests: XCTestCase {
}

let dictionaries = [
[ Item.nameKey : "a" ],
[ Item.nameKey : "b" ]
[Item.nameKey : "a"],
[Item.nameKey : "b"]
]

func testArrayToDeserializableArray() {
Expand Down
43 changes: 39 additions & 4 deletions JSONHelperTests/DictionaryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,54 @@ import JSONHelper

class DictionaryTests: XCTestCase {

// MARK: - Convertible Tests

let dateStringDictionary = ["one" : "2014-11-02", "two" : "2015-04-24"]

override func setUp() {
JSONHelper.dateFormatter.dateFormat = "yyyy-MM-dd"
}

func testDictionaryToConvertibleDictionary() {
// TODO
var value = [String : NSDate]()
try! value <-- dateStringDictionary
XCTAssertEqual(JSONHelper.dateFormatter.stringFromDate(value["one"]!), dateStringDictionary["one"])
}

func testDictionaryAsAnyToConvertibleDictionary() {
// TODO
var value = [String : NSDate]()
try! value <-- (dateStringDictionary as Any)
XCTAssertEqual(JSONHelper.dateFormatter.stringFromDate(value["one"]!), dateStringDictionary["one"])
}

// MARK: - Deserializable Tests

let dictionary = [
"one" : ["name" : "a"],
"two" : ["name" : "b"]
]

struct Item: Deserializable {
static let nameKey = "name"

var name = ""

init(dictionary: [String : AnyObject]) throws {
try name <-- dictionary["name"]
}
}

func testDictionaryToMappableDictionary() {
// TODO
var value = [String : Item]()
try! value <-- dictionary
XCTAssertEqual(value["one"]?.name, dictionary["one"]?["name"])
XCTAssertEqual(value["two"]?.name, dictionary["two"]?["name"])
}

func testDictionaryAsAnyToMappableDictionary() {
// TODO
var value = [String : Item]()
try! value <-- (dictionary as Any)
XCTAssertEqual(value["one"]?.name, dictionary["one"]?["name"])
XCTAssertEqual(value["two"]?.name, dictionary["two"]?["name"])
}
}
10 changes: 10 additions & 0 deletions JSONHelperTests/StringTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import JSONHelper
class StringTests: XCTestCase {
let testString = "test"
let testIntAndResult = (1, "1")
let testDateAndResult = (NSDate(timeIntervalSince1970: 0), "1970-01-01")
let testDateFormat = "yyyy-MM-dd"

var value = ""

Expand All @@ -29,4 +31,12 @@ class StringTests: XCTestCase {
try! value <-- (testIntAndResult.0 as Any)
XCTAssertEqual(value, testIntAndResult.1)
}

func testDateConversion() {
JSONHelper.dateFormatter.dateFormat = testDateFormat
JSONHelper.dateFormatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)

try! value <-- (testDateAndResult.0 as Any)
XCTAssertEqual(value, testDateAndResult.1)
}
}

0 comments on commit 82901fd

Please sign in to comment.