Skip to content

Commit

Permalink
Added keyPath support to Unboxing starting a custom key
Browse files Browse the repository at this point in the history
Added tests to test keyPath support
  • Loading branch information
clayellis committed Jul 20, 2016
1 parent b376eaf commit 57ed1fb
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 7 deletions.
26 changes: 21 additions & 5 deletions Sources/Unbox.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public func Unbox<T: Unboxable>(dictionary: UnboxableDictionary, context: Any? =
}

/// Unbox a JSON dictionary into a model `T` beginning at a provided key, optionally using a contextual object. Throws `UnboxError`.
public func Unbox<T: Unboxable>(dictionary: UnboxableDictionary, at key: String, context: Any? = nil) throws -> T {
return try Unboxer.unboxer(at: key, in: dictionary, context: context).performUnboxing()
public func Unbox<T: Unboxable>(dictionary: UnboxableDictionary, at key: String, isKeyPath: Bool = false, context: Any? = nil) throws -> T {
return try Unboxer.unboxer(at: key, in: dictionary, isKeyPath: isKeyPath, context: context).performUnboxing()
}

/// Unbox an array of JSON dictionaries into an array of `T`, optionally using a contextual object and/or invalid elements. Throws `UnboxError`.
Expand Down Expand Up @@ -891,9 +891,25 @@ private extension Unboxer {
}
}

static func unboxer(at key: String, in dictionary: UnboxableDictionary, context: Any?) throws -> Unboxer {
guard let nestedDictionary = dictionary[key] as? UnboxableDictionary else {
throw UnboxValueError.MissingValueForKey(key)
static func unboxer(at key: String, in dictionary: UnboxableDictionary, isKeyPath: Bool, context: Any?) throws -> Unboxer {
var dictionary = dictionary
var modifiedKey = key

if isKeyPath && key.containsString(".") {
let components = key.componentsSeparatedByString(".")
for i in 0 ..< components.count {
let keyPathComponent = components[i]

if i == components.count - 1 {
modifiedKey = keyPathComponent
} else if let nestedDictionary = dictionary[keyPathComponent] as? UnboxableDictionary {
dictionary = nestedDictionary
}
}
}

guard let nestedDictionary = dictionary[modifiedKey] as? UnboxableDictionary else {
throw UnboxValueError.MissingValueForKey(modifiedKey)
}

return Unboxer(dictionary: nestedDictionary, context: context)
Expand Down
41 changes: 39 additions & 2 deletions Tests/UnboxTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1229,13 +1229,50 @@ class UnboxTests: XCTestCase {
func testUnboxingStartingAtMissingCustomKey() {
let dictionary: UnboxableDictionary = [
"A": [
"int": 3
"int": 14
]
]

do {
let unboxed: UnboxTestSimpleMock = try Unbox(dictionary, at: "B")
XCTAssertEqual(unboxed.int, 3)
XCTAssertEqual(unboxed.int, 14)
} catch {
switch error {
case UnboxValueError.MissingValueForKey(let missingKey):
XCTAssertEqual(missingKey, "B")
default:
XCTFail("Unexpected error thrown: \(error)")
}
}
}

func testUnboxingStartingAtCustomKeyPath() {
let dictionary: UnboxableDictionary = [
"A": [
"B": [
"int": 14
]
]
]

do {
let unboxed: UnboxTestSimpleMock = try Unbox(dictionary, at: "A.B", isKeyPath: true)
XCTAssertEqual(unboxed.int, 14)
} catch {
XCTFail("Unexpected error thrown: \(error)")
}
}

func testUnboxingStartingAtMissingCustomKeyPath() {
let dictionary: UnboxableDictionary = [
"A": [
"int": 14
]
]

do {
let unboxed: UnboxTestSimpleMock = try Unbox(dictionary, at: "A.B", isKeyPath: true)
XCTAssertEqual(unboxed.int, 14)
} catch {
switch error {
case UnboxValueError.MissingValueForKey(let missingKey):
Expand Down

0 comments on commit 57ed1fb

Please sign in to comment.