Skip to content

Instantly share code, notes, and snippets.

@bobspryn
Created March 18, 2016 05:19
Show Gist options
  • Save bobspryn/b97923d5893e058c64cb to your computer and use it in GitHub Desktop.
Save bobspryn/b97923d5893e058c64cb to your computer and use it in GitHub Desktop.
// example json being mapped in
// {
// "pageName": "home", // string from a known set
// "slots": [ {
// "name": "homeTopSlot", // string from a known set, only found in the specific pageName
// "message": "Some message"
// },
// {
// "name": "bottomTopSlot", // ditto
// "message": "Some message"
// },
// ]
// }
// Could model this with just enums and associated values for the message
public enum PageEnum {
// spell out the slots in each page
public enum HomePageSlots {
case homeTopSlot(message: String)
case homeBottomSlot(message: String)
}
// maybe cart only has one slot right now
public enum CartPageSlots {
case defaultSlot(message: String)
}
// etc
// then associate the slots with the page case
case homePage([HomePageSlots])
case cartPage([CartPageSlots])
}
// feels good, but due to the oddities around instantiating an enum with an associated value
// each slot enum is going to need it's own custom initializer, extra boilerplatey when done in an extension
protocol PageSlot {
init?(slotIdentifier: String, message: String)
}
// pages with only one slot feel awful heavy
extension PageEnum.CartPageSlots: PageSlot {
init?(slotIdentifier: String, message: String) throws {
// guard against unknown values coming for slot names
guard(slotIdentifier == "cartSlot") else { return nil }
self = .defaultSlot(message)
}
}
extension PageEnum.HomePageSlots: PageSlot {
init?(slotIdentifier: String, message: String) throws {
switch slotIdentifier {
case "homeTopSlot":
self = .homeTopSlot(message)
case "homeBottomSlot":
self = .homeBottomSlot(message)
default:
return nil
}
}
}
// kick off the parsing
extension PageEnum: JSONDecodable {
// Extracts the valid info and uses the generic initializer
private static func initSlot<T:PageSlot>(json:JSON) throws -> T {
let slotIdentifier = try json.string("name")
let message = try json.string("message")
return try T.init(slotIdentifier: slotIdentifier, message: message)
}
// just a convenience wrapper
private static func mapSlots<T:PageSlot>(slots:[JSON]) throws -> [T] {
return try slots.map(PageEnum.initSlot)
}
public init(json value: JSON) throws {
let pageName = try value.string("response", "pageName")
let slots = try value.array("response", "slotResponseBean")
switch pageName {
case "homePage":
self = .homePage(try PageEnum.mapSlots(slots))
case "cartPage":
self = .cartPage(try PageEnum.mapSlots(slots))
default:
throw PageEnum.SomeErrorEnum.pageNotFound(pageName)
}
}
}
// Another thought is to use structs for the slots, and they own an enum that describes the slots available
// can somewhat be accomplished with associated types (typealias in 2.1), but with side effects
// ultimately doesn't limit boilerplate that much
// defines the interface all the slot enums adhere to for instantiation
public protocol PageSlotStruct {
// failable initializer
init?(slotIdentifier: String, message: String)
// typealias representing the enum concrete types will provide
typealias AvailableSlots: RawRepresentable
// define the storage for slot and message, settable unfortunately
var slot: AvailableSlots {set get}
var message: String {set get}
// we need a valid init to chain on in the extension
init()
}
extension PageSlotStruct where AvailableSlots.RawValue == String {
// get to use a default implementation initializer, but with some ugliness (settable properties in the protocol, weird init dance)
public init?(slotIdentifier: String, message: String) {
guard let theSlot = AvailableSlots(rawValue: slotIdentifier) else {
return nil
}
self.init()
self.slot = theSlot
self.message = message
}
}
// get to use an enum with a rawType, nice for matching the service
public enum HomePageSlots: String {
case homeTopSlot
case homeBottomSlot = "HomeBottomslot"
}
public struct HomePage: PageSlotStruct {
// need to satisy init and set slot to a default value
public var slot: HomePageSlots = .defaultSlot
public var message:String = ""
public init(){}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment