/** * Plot * Copyright (c) John Sundell 2019 * MIT license, see LICENSE file for details */ import Foundation /// let someUrl:URL = try URL("hello") ?! AppError("What") infix operator ?!: NilCoalescingPrecedence public func ?!(value: T?, error: @autoclosure () -> Error) throws -> T { if let value = value { return value } throw error() } internal extension String { func asSubstring() -> Substring { return self[self.startIndex.. String { var pendingAmpersandString: String? func flushPendingAmpersandString( withSuffix suffix: String? = nil, resettingTo newValue: String? = nil ) -> String { let pending = pendingAmpersandString pendingAmpersandString = newValue return pending.map { "&\($0)\(suffix ?? "")" } ?? suffix ?? "" } return String(flatMap { character -> String in switch character { case "<": return flushPendingAmpersandString(withSuffix: "<") case ">": return flushPendingAmpersandString(withSuffix: ">") case "&": return flushPendingAmpersandString(resettingTo: "") case ";": let pending = pendingAmpersandString.map { "&\($0);" } pendingAmpersandString = nil return pending ?? ";" case "#" where pendingAmpersandString?.isEmpty == true: pendingAmpersandString = "#" return "" default: if let pending = pendingAmpersandString { guard character.isLetter || character.isNumber else { return flushPendingAmpersandString(withSuffix: String(character)) } pendingAmpersandString = "\(pending)\(character)" return "" } return "\(character)" } }) + flushPendingAmpersandString() } static func parseList(_ value:String?, _ separator:String = " ") throws -> [String] { guard let value = value else { return [] } var iterator = value.componentsIterator(separatedBy: separator) return iterator.map({String($0)}) } } extension Array where Element: RawRepresentable, Element.RawValue == String { /// Converts an array of String-backed enums to an array of their raw string values. func toStringList(_ seperator:String) -> String { let strList = self.map { $0.rawValue } return strList.joined(separator: seperator) } } extension Array where Element == String { /// Converts an array of String-backed enums to an array of their raw string values. func toStringList(_ seperator:String) -> String { let strList = self.map { $0 } return strList.joined(separator: seperator) } } extension Array where Element == URL { /// Converts an array of String-backed enums to an array of their raw string values. func toStringList(_ seperator:String) -> String { let strList = self.map { $0.absoluteString } return strList.joined(separator: seperator) } } extension Array where Element == Float { /// Converts an array of String-backed enums to an array of their raw string values. func toStringList(_ seperator:String) -> String { let strList = self.map { String($0) } return strList.joined(separator: seperator) } } extension Set where Element: RawRepresentable, Element.RawValue == String { /// Converts an array of String-backed enums to an array of their raw string values. func toStringList(_ seperator:String) -> String { let strList = self.map { $0.rawValue } return strList.joined(separator: seperator) } } extension Float { static func parseList(_ value:String?, _ separator:String = " ") throws -> [Float] { guard let value = value else { return [] } var iterator = value.componentsIterator(separatedBy: separator) return try iterator.map({ try Float.expect($0) }) } static func expect(_ value:String) throws -> Float { if let result = Float(value) { return result } throw AppError("Unable to map value to float") } static func expect(_ value:Substring) throws -> Float { if let result = Float(value) { return result } throw AppError("Unable to map value to float") } } extension URL { static func parseList(_ value:String?, _ separator:String = " ") throws -> [URL] { guard let value = value else { return [] } var iterator = value.componentsIterator(separatedBy: separator) return try iterator.map({ guard let result = URL(string:String($0)) else { throw AppError("Invalid URL: \(String($0))") } return result }) } } extension Bool { public init(expect: String) throws { if (expect == "true") { self = true return } if (expect == "false") { self = false return } throw AppError("Unexpected value for bool: \(expect)") } public init(expectYesOrNo: String) throws { if (expectYesOrNo == "yes") { self = true return } if (expectYesOrNo == "no") { self = false return } throw AppError("Unexpected value for bool: \(expectYesOrNo)") } }