From 6203986ab9e313816809865e8910dae1b6eca23f Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Mon, 9 May 2016 23:57:03 +0200 Subject: [PATCH 01/10] Add a method to return meta instance of the specified type --- Sources/Shared/ViewModel.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/Shared/ViewModel.swift b/Sources/Shared/ViewModel.swift index acaa424..1f82ea0 100644 --- a/Sources/Shared/ViewModel.swift +++ b/Sources/Shared/ViewModel.swift @@ -162,6 +162,10 @@ public struct ViewModel: Mappable { return meta[key] as? T } + public func metaInstance() -> T { + return T(meta) + } + /** A convenience lookup method for resolving view model relations From 8cb1d263a0f66b491ce24716eacf1de2ce0308bb Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Tue, 10 May 2016 00:04:43 +0200 Subject: [PATCH 02/10] Convenience init to create view model with mappable meta --- Sources/Shared/ViewModel.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Sources/Shared/ViewModel.swift b/Sources/Shared/ViewModel.swift index 1f82ea0..ba8839a 100644 --- a/Sources/Shared/ViewModel.swift +++ b/Sources/Shared/ViewModel.swift @@ -138,6 +138,25 @@ public struct ViewModel: Mappable { self.relations = relations } + /** + Initialization a new instance of a ViewModel and map it to a JSON dictionary + + - Parameter title: The title string for the view model, defaults to empty string + - Parameter subtitle: The subtitle string for the view model, default to empty string + - Parameter image: Image name or URL as a string, default to empty string + */ + public init(title: String = "", subtitle: String = "", image: String = "", kind: StringConvertible = "", action: String? = nil, size: CGSize = CGSize(width: 0, height: 0), meta: Mappable, relations: [String : [ViewModel]] = [:]) { + var metaDictionary = JSONDictionary() + + for (key, item) in meta.properties() { + guard let value = item as? AnyObject else { continue } + metaDictionary[key] = value + } + + self.init(title: title, subtitle: subtitle, image: image, kind: kind, action: action, + size: size, meta: metaDictionary, relations: relations) + } + // MARK: - Helpers /** From de2ea3ce75bd412675efffafbf5bcf7987df8b5b Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Tue, 10 May 2016 00:05:32 +0200 Subject: [PATCH 03/10] Add some docs --- Sources/Shared/ViewModel.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/Shared/ViewModel.swift b/Sources/Shared/ViewModel.swift index ba8839a..1f963e3 100644 --- a/Sources/Shared/ViewModel.swift +++ b/Sources/Shared/ViewModel.swift @@ -181,6 +181,11 @@ public struct ViewModel: Mappable { return meta[key] as? T } + /** + A generic convenience method for resolving meta instance + + - Returns: A generic meta instance based on `type` + */ public func metaInstance() -> T { return T(meta) } From bd22eecf6427b092850075f0d0ae7e453d98c271 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Tue, 10 May 2016 00:13:03 +0200 Subject: [PATCH 04/10] Add tests --- Brick.xcodeproj/project.pbxproj | 6 ++++++ BrickTests/Shared/Helpers.swift | 12 ++++++++++++ BrickTests/Shared/VIewModelSpec.swift | 11 ++++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 BrickTests/Shared/Helpers.swift diff --git a/Brick.xcodeproj/project.pbxproj b/Brick.xcodeproj/project.pbxproj index 397cb25..70a3ba0 100644 --- a/Brick.xcodeproj/project.pbxproj +++ b/Brick.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ BD6D7AE21CBA768A00FBF0BD /* Fakery.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD6D7AE11CBA768A00FBF0BD /* Fakery.framework */; }; BDDA5FEB1CBBCF45000FD5A6 /* ViewConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDDA5FEA1CBBCF45000FD5A6 /* ViewConfigurable.swift */; }; BDDA5FEC1CBBCF45000FD5A6 /* ViewConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDDA5FEA1CBBCF45000FD5A6 /* ViewConfigurable.swift */; }; + D57832991CE142DE005ED144 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57832961CE142C8005ED144 /* Helpers.swift */; }; + D578329A1CE142DF005ED144 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57832961CE142C8005ED144 /* Helpers.swift */; }; D5ACAC9A1CCE439F00567809 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACAC991CCE439F00567809 /* Extensions.swift */; }; D5ACAC9B1CCE439F00567809 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACAC991CCE439F00567809 /* Extensions.swift */; }; D5ACAC9F1CCE45CE00567809 /* ExtensionsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACAC9C1CCE449A00567809 /* ExtensionsSpec.swift */; }; @@ -60,6 +62,7 @@ BDDA5FEA1CBBCF45000FD5A6 /* ViewConfigurable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewConfigurable.swift; sourceTree = ""; }; D500FD111C3AABED00782D78 /* Playground-iOS.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Playground-iOS.playground"; sourceTree = ""; }; D500FD121C3AAC8E00782D78 /* Playground-Mac.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Playground-Mac.playground"; sourceTree = ""; }; + D57832961CE142C8005ED144 /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; D5ACAC991CCE439F00567809 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; D5ACAC9C1CCE449A00567809 /* ExtensionsSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionsSpec.swift; sourceTree = ""; }; D5B2E89F1C3A780C00C0327D /* Brick.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Brick.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -206,6 +209,7 @@ children = ( D5C629971C3A8BDA007F7B7C /* VIewModelSpec.swift */, D5ACAC9C1CCE449A00567809 /* ExtensionsSpec.swift */, + D57832961CE142C8005ED144 /* Helpers.swift */, ); path = Shared; sourceTree = ""; @@ -482,6 +486,7 @@ buildActionMask = 2147483647; files = ( D5ACAC9F1CCE45CE00567809 /* ExtensionsSpec.swift in Sources */, + D57832991CE142DE005ED144 /* Helpers.swift in Sources */, D5C6299E1C3A8C75007F7B7C /* VIewModelSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -502,6 +507,7 @@ buildActionMask = 2147483647; files = ( D5ACACA01CCE45CF00567809 /* ExtensionsSpec.swift in Sources */, + D578329A1CE142DF005ED144 /* Helpers.swift in Sources */, D5C6299C1C3A8BDA007F7B7C /* VIewModelSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/BrickTests/Shared/Helpers.swift b/BrickTests/Shared/Helpers.swift new file mode 100644 index 0000000..248cc29 --- /dev/null +++ b/BrickTests/Shared/Helpers.swift @@ -0,0 +1,12 @@ +import Tailor +import Sugar + +struct Meta: Mappable { + var id = 0 + var name = "" + + init(_ map: JSONDictionary) { + id <- map.property("id") + name <- map.property("name") + } +} diff --git a/BrickTests/Shared/VIewModelSpec.swift b/BrickTests/Shared/VIewModelSpec.swift index 7451a5c..29bc857 100644 --- a/BrickTests/Shared/VIewModelSpec.swift +++ b/BrickTests/Shared/VIewModelSpec.swift @@ -64,12 +64,17 @@ class ViewModelSpec: QuickSpec { } describe("#meta") { - beforeEach { + it("resolves meta data created from JSON") { viewModel = ViewModel(data) + expect(viewModel.meta("domain", "")).to(equal(data["meta"]!["domain"])) } - it("resolves meta data") { - expect(viewModel.meta("domain", "")).to(equal(data["meta"]!["domain"])) + it("resolves meta data created from object") { + var data = ["id": 11, "name": "Name"] + + viewModel = ViewModel(meta: Meta(data)) + expect(viewModel.meta("id", 0)).to(equal(data["id"])) + expect(viewModel.meta("name", "")).to(equal(data["name"])) } } From eb44079b8ce09a7e51b9f3ebeefb6cea125d7c94 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Tue, 10 May 2016 00:32:30 +0200 Subject: [PATCH 05/10] Support optionals --- BrickTests/Shared/Helpers.swift | 2 +- Sources/Shared/ViewModel.swift | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/BrickTests/Shared/Helpers.swift b/BrickTests/Shared/Helpers.swift index 248cc29..58b3614 100644 --- a/BrickTests/Shared/Helpers.swift +++ b/BrickTests/Shared/Helpers.swift @@ -3,7 +3,7 @@ import Sugar struct Meta: Mappable { var id = 0 - var name = "" + var name: String? = "" init(_ map: JSONDictionary) { id <- map.property("id") diff --git a/Sources/Shared/ViewModel.swift b/Sources/Shared/ViewModel.swift index 1f963e3..639d2de 100644 --- a/Sources/Shared/ViewModel.swift +++ b/Sources/Shared/ViewModel.swift @@ -149,8 +149,13 @@ public struct ViewModel: Mappable { var metaDictionary = JSONDictionary() for (key, item) in meta.properties() { - guard let value = item as? AnyObject else { continue } - metaDictionary[key] = value + if let value = item as? AnyObject { + metaDictionary[key] = value + } else if let value = Mirror(reflecting: item).descendant("Some") as? AnyObject { + metaDictionary[key] = value + } else { + continue + } } self.init(title: title, subtitle: subtitle, image: image, kind: kind, action: action, From 9f93a07b2b03aa81d844eeec7fb33acc4d8ac4f8 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Tue, 10 May 2016 00:48:01 +0200 Subject: [PATCH 06/10] Remove default value --- BrickTests/Shared/Helpers.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BrickTests/Shared/Helpers.swift b/BrickTests/Shared/Helpers.swift index 58b3614..3207caf 100644 --- a/BrickTests/Shared/Helpers.swift +++ b/BrickTests/Shared/Helpers.swift @@ -3,7 +3,7 @@ import Sugar struct Meta: Mappable { var id = 0 - var name: String? = "" + var name: String? init(_ map: JSONDictionary) { id <- map.property("id") From f6aa5458423bc71b8f4d317ac080fe2b68b04cc5 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Tue, 10 May 2016 01:25:14 +0200 Subject: [PATCH 07/10] Move meta dictionary to description --- BrickTests/Shared/Helpers.swift | 7 +++++-- Sources/Shared/Extensions.swift | 28 ++++++++++++++++++++++++++++ Sources/Shared/ViewModel.swift | 14 +------------- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/BrickTests/Shared/Helpers.swift b/BrickTests/Shared/Helpers.swift index 3207caf..2b6d024 100644 --- a/BrickTests/Shared/Helpers.swift +++ b/BrickTests/Shared/Helpers.swift @@ -1,9 +1,12 @@ import Tailor import Sugar -struct Meta: Mappable { +struct Meta { var id = 0 - var name: String? + var name: String? = "" +} + +extension Meta: Mappable { init(_ map: JSONDictionary) { id <- map.property("id") diff --git a/Sources/Shared/Extensions.swift b/Sources/Shared/Extensions.swift index 5bc77f4..1e03241 100644 --- a/Sources/Shared/Extensions.swift +++ b/Sources/Shared/Extensions.swift @@ -1,3 +1,5 @@ +import Tailor + // MARK: - Array public extension _ArrayType where Generator.Element == ViewModel { @@ -41,3 +43,29 @@ extension Dictionary where Key: StringLiteralConvertible { } } } + +// MARK: - Mappable + +extension Mappable { + + /** + - Returns: A key-value dictionary. + */ + var metaProperties: [String : AnyObject] { + var properties = [String : AnyObject]() + + for tuple in Mirror(reflecting: self).children { + guard let key = tuple.label else { continue } + + if let value = tuple.value as? AnyObject { + properties[key] = value + } else if let value = Mirror(reflecting: tuple.value).descendant("Some") as? AnyObject { + properties[key] = value + } else { + continue + } + } + + return properties + } +} diff --git a/Sources/Shared/ViewModel.swift b/Sources/Shared/ViewModel.swift index 639d2de..cd38676 100644 --- a/Sources/Shared/ViewModel.swift +++ b/Sources/Shared/ViewModel.swift @@ -146,20 +146,8 @@ public struct ViewModel: Mappable { - Parameter image: Image name or URL as a string, default to empty string */ public init(title: String = "", subtitle: String = "", image: String = "", kind: StringConvertible = "", action: String? = nil, size: CGSize = CGSize(width: 0, height: 0), meta: Mappable, relations: [String : [ViewModel]] = [:]) { - var metaDictionary = JSONDictionary() - - for (key, item) in meta.properties() { - if let value = item as? AnyObject { - metaDictionary[key] = value - } else if let value = Mirror(reflecting: item).descendant("Some") as? AnyObject { - metaDictionary[key] = value - } else { - continue - } - } - self.init(title: title, subtitle: subtitle, image: image, kind: kind, action: action, - size: size, meta: metaDictionary, relations: relations) + size: size, meta: meta.metaProperties, relations: relations) } // MARK: - Helpers From d940d91e7b053bda245ae272688dfa560fd5579a Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Tue, 10 May 2016 01:32:23 +0200 Subject: [PATCH 08/10] Add tests for mappable extension --- BrickTests/Shared/ExtensionsSpec.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/BrickTests/Shared/ExtensionsSpec.swift b/BrickTests/Shared/ExtensionsSpec.swift index 1a0c2c3..ea9da08 100644 --- a/BrickTests/Shared/ExtensionsSpec.swift +++ b/BrickTests/Shared/ExtensionsSpec.swift @@ -51,5 +51,19 @@ class ExtensionsSpec: QuickSpec { } } } + + describe("Mappable+Brick") { + let item = Meta(id: 11, name: "Name") + + describe("#metaDictionary") { + it("returns an array of properties") { + var dictionary = ["id": 11, "name": "Name"] + var result = item.metaProperties + + expect(result["id"] as? Int).to(equal(dictionary["id"])) + expect(result["name"] as? String).to(equal(dictionary["name"])) + } + } + } } } From 6a66d65a6fd285165be0fab6cf00d029c7cd03e0 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Tue, 10 May 2016 01:39:26 +0200 Subject: [PATCH 09/10] Meta instance tests --- BrickTests/Shared/VIewModelSpec.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/BrickTests/Shared/VIewModelSpec.swift b/BrickTests/Shared/VIewModelSpec.swift index 29bc857..ad10ca3 100644 --- a/BrickTests/Shared/VIewModelSpec.swift +++ b/BrickTests/Shared/VIewModelSpec.swift @@ -78,6 +78,17 @@ class ViewModelSpec: QuickSpec { } } + describe("#metaInstance") { + it("resolves meta data created from object") { + var data = ["id": 11, "name": "Name"] + viewModel = ViewModel(meta: Meta(data)) + let result: Meta = viewModel.metaInstance() + + expect(result.id).to(equal(data["id"])) + expect(result.name).to(equal(data["name"])) + } + } + describe("#dictionary") { beforeEach { data["relations"] = ["viewmodels" : [data, data]] From 97d8990c5998b83875741feb218e1084e4f835e0 Mon Sep 17 00:00:00 2001 From: Vadym Markov Date: Tue, 10 May 2016 09:33:13 +0200 Subject: [PATCH 10/10] Remove default value --- BrickTests/Shared/Helpers.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BrickTests/Shared/Helpers.swift b/BrickTests/Shared/Helpers.swift index 2b6d024..17087dd 100644 --- a/BrickTests/Shared/Helpers.swift +++ b/BrickTests/Shared/Helpers.swift @@ -3,7 +3,7 @@ import Sugar struct Meta { var id = 0 - var name: String? = "" + var name: String? } extension Meta: Mappable {