I'm working on a project. In the code, there's the following configuration struct:
public class Config {
static let shared = Config()
private init() {}
var isSeatmapActivated = true
var isLoungeActivated = false
var isBagActivated = true
var isInsuranceActivated = true
var isEnvironmentalActivated = true
}
Now for marketing purposes, I need to transform that into a semicolon-separated string. For example if all the above booleans are true, the semicolon-separated string is SEA;BAG;LOU;INS;ENV
I did the following:
var offeredProductGroups: [String] = []
if Config.shared.isSeatmapActivated {
offeredProductGroups.append("SEA")
}
if Config.shared.isBagActivated {
offeredProductGroups.append("BAG")
}
if Config.shared.isLoungeActivated {
offeredProductGroups.append("LOU")
}
if Config.shared.isInsuranceActivated {
offeredProductGroups.append("INS")
}
if Config.shared.isEnvironmentalActivated {
offeredProductGroups.append("ENV")
}
print(offeredProductGroups.joined(separator: ";"))
That doesn't feel optimal to me What is the shortest way to code the above?
I think this is probably the most maintainable solution that fits your requirements. It doesn't need to be changed at all even if you add more configuration options (unless the abbreviations of two options happen to be the same, which is unlikely but not impossible, in which case you'd run into issues anyway).
var offeredProductGroups: [String] = []
for child in Mirror(reflecting: Config.shared).children {
guard
let label = child.label,
child.value as? Bool == true
else {
continue
}
let abbreviation = label.dropFirst(2).prefix(3).uppercased()
offeredProductGroups.append(abbreviation)
}
print(offeredProductGroups.joined(separator: ";"))
In case you want to learn more about this Swift feature, it's called reflection. Here's an article on it. I haven't read the whole article but it seems like it has all the basics.
I generally avoid reflection, but that's because I mostly work on performance-critical code. In your use case, the performance implications of this approach are negligible (unless you decide to run it thousands of times per second).
public struct Config: OptionSet {
public let rawValue: Int
public static let seatmap = Config(rawValue: 1 << 0)
public static let lounge = Config(rawValue: 1 << 1)
public static let bag = Config(rawValue: 1 << 2)
// etc...
public init(rawValue: Int) {
self.rawValue = rawValue
}
public static func marketingString(for options: [Config]) -> String {
return options.reduce( .... ) //convert the option to a string value and append to the accumulator string; implementation left up to the user :)
}
}
You could also use a Set<Option> and leverage a string-backed enum:
class Config {
static let shared = Self()
var options: Set<Option> = [.seatmap, .bag, .insurance, .environmental]
enum Option: String {
case bag = "BAG"
case environmental = "ENV"
case insurance = "INS"
case lounge = "LOU"
case seatmap = "SEA"
}
}
Config.shared.options.map(\.rawValue).joined(separator: ";")