Does date/time parsing work?
As I understand it, Yaml is supposed to understand dates & times. When I parse a file like this:
datetime: 2001-12-15T02:59:43.1Z
I get:
Dictionary([String(datetime): String(2001-12-15T02:59:43.1Z)])
But I was hoping for
Dictionary([String(datetime): Date(2018-03-29 20:15:16 +0000)])
@JetForMe Unfortunately no, these are the only types supported today.
Maybe it should support some sort of RFC for date just like the spec, but not sure.
It would be nice, to be sure. Thanks!
@JetForMe I think it's better if you handle that yourself after you've gotten the initial YAML object, because I think a minimal foot print of primitives types (String, Dictionary, and etc) works better than adding more cases.
This is how I turn Yaml into primitive types, you could easily add a case where you check if the string value is a date and make it into a date instead.
Some clause like this could help.
case let .string(value) where checkIfStringIsDate(value) : dict[key] = parseStringToDate(value)
Obviously this needs refactoring (and updating to latest Swift syntax), but I hope you get the gist:
import Foundation
extension Yaml {
internal enum YamlError : Error {
case failedParsingWithMessage(String)
}
static fileprivate func reduce(_ initial:Dictionary<String, AnyObject>, combine:Yaml, key:String) -> Dictionary<String, AnyObject> {
var dict = initial
switch combine {
case .null: break
case let .bool(value): dict[key] = value
case let .int(value): dict[key] = value
case let .double(value): dict[key] = value
case let .string(value) where checkIfStringIsDate(value) : dict[key] = parseStringToDate(value)
case let .string(value): dict[key] = value
case let .array(value): dict[key] = map(withList:value)
case let .dictionary(value):
let reduced = value.reduce(Dictionary<String, AnyObject>()) { self.reduce($0, combine:$1.1, key:$1.0.string!) }
dict[key] = reduced
}
return dict
}
static fileprivate func map(withList list: Array<Yaml>) -> Array<AnyObject> {
return list.reduce(Array<AnyObject>()) {
var mutatedMemo = $0
switch $1 {
case .null: break
case let .bool(value): mutatedMemo.append(value)
case let .int(value): mutatedMemo.append(value)
case let .double(value): mutatedMemo.append(value)
case let .string(value) where checkIfStringIsDate(value) : mutatedMemo.append(parseStringToDate(value))
case let .string(value):
case let .array(value): mutatedMemo.append(map(withList:value))
case let .dictionary(value):
let reduced = value.reduce(Dictionary<String, AnyObject>()) { self.reduce($0, combine:$1.1, key:$1.0.string!) }
mutatedMemo.append(reduced)
}
return mutatedMemo
}
}
static func yamlObject(with rawContent:String) throws -> AnyObject {
let loadedYaml = try self.load(rawContent)
switch loadedYaml {
case let .array(value): return self.map(withList: value) as AnyObject
case let .dictionary(value): return (value.reduce(Dictionary<String, AnyObject>()) { self.reduce($0, combine:$1.1, key:$1.0.string!) }) as AnyObject
default: throw Yaml.YamlError.failedParsingWithMessage("Must have a dictionary or array as root object")
}
}
}
Really? That seems non-ideal. Date parsing is part of the Yaml spec. Why make every user of your library implement it?
I am sorry if it's not optimal, even worse, not all parts of the specification are supported unfortunately. I'm working on a reimplementation using parser combinator but even then I would also consider just expose primitive types.
It's a bit of a shame, but it makes the foot print of cases to handle less. What if I expose a function to give you foundation objects (Array and Dictionary) where if applicable, the string would be a date?
I'm not sure I understand what you're suggesting. But think of the footprint across all the clients of your library. If everyone is reimplementing missing functionality, that just means more repeated effort and more potential for bugs. It also means people might search for a different Yaml library.
I actually think that's a better approach since the YAML spec isn't implemented entirely. I think I saw one earlier that allowed the use of Encodable/Decodable from Swift 4, so you could define your own encoding callback for dates.