From 6d104758165b91968ece2f614599296aaacc3226 Mon Sep 17 00:00:00 2001 From: Tomasz Popi Date: Thu, 8 Aug 2024 17:19:47 +0200 Subject: [PATCH 1/4] Adds support for NSDictionary, NSAray, NSValue and NSString --- Sources/Yams/Representer.swift | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Sources/Yams/Representer.swift b/Sources/Yams/Representer.swift index 70310ff8..41e7296d 100644 --- a/Sources/Yams/Representer.swift +++ b/Sources/Yams/Representer.swift @@ -57,6 +57,14 @@ extension Array: NodeRepresentable { } } +extension NSArray: NodeRepresentable { + /// This value's `Node` representation. + public func represented() throws -> Node { + let nodes = try map(represent) + return Node(nodes, Tag(.seq)) + } +} + extension Dictionary: NodeRepresentable { /// This value's `Node` representation. public func represented() throws -> Node { @@ -65,6 +73,14 @@ extension Dictionary: NodeRepresentable { } } +extension NSDictionary: NodeRepresentable { + /// This value's `Node` representation. + public func represented() throws -> Node { + let pairs = try map { (key: try represent($0.0), value: try represent($0.1)) } + return Node(pairs.sorted { $0.key < $1.key }, Tag(.map)) + } +} + private func represent(_ value: Any) throws -> Node { if let representable = value as? NodeRepresentable { return try representable.represented() @@ -187,6 +203,13 @@ extension Float: ScalarRepresentable { } } +extension NSValue: ScalarRepresentable { + /// This value's `Node.scalar` representation. + public func represented() -> Node.Scalar { + return .init(floatFormatter.string(for: self)!.replacingOccurrences(of: "+-", with: "-"), Tag(.float)) + } +} + private func numberFormatter(with significantDigits: Int) -> NumberFormatter { let formatter = NumberFormatter() formatter.locale = Locale(identifier: "en_US") @@ -258,6 +281,14 @@ extension String: ScalarRepresentable { } } +extension NSString: ScalarRepresentable { + /// This value's `Node.scalar` representation. + public func represented() -> Node.Scalar { + let scalar = Node.Scalar(String(self)) + return scalar.resolvedTag.name == .str ? scalar : .init(String(self), Tag(.str), .singleQuoted) + } +} + extension UUID: ScalarRepresentable { /// This value's `Node.scalar` representation. public func represented() -> Node.Scalar { From d77e196bcb468bb227ecc78f9d6210bde3d8ddb3 Mon Sep 17 00:00:00 2001 From: Tomasz Popi Date: Sat, 10 Aug 2024 10:39:15 +0200 Subject: [PATCH 2/4] Adds the Mapping Map for NSMutableDictionary, NSMutableArray and NSMutableSet --- Sources/Yams/Constructor.swift | 100 +++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/Sources/Yams/Constructor.swift b/Sources/Yams/Constructor.swift index 4120202c..7077eead 100644 --- a/Sources/Yams/Constructor.swift +++ b/Sources/Yams/Constructor.swift @@ -98,6 +98,17 @@ extension Constructor { .omap: [Any].construct_omap, .pairs: [Any].construct_pairs ] + + public static let dynamicMappingMap: MappingMap = [ + .map: NSMutableDictionary.construct_mapping, + .set: NSMutableSet.construct_set + ] + + public static let dynamicSequenceMap: SequenceMap = [ + .seq: NSMutableArray.construct_seq, + .omap: NSMutableArray.construct_omap, + .pairs: NSMutableArray.construct_pairs + ] } // MARK: - ScalarConstructible @@ -433,6 +444,31 @@ private extension Dictionary { } } +extension NSMutableDictionary { + /// Construct an `NSMutableDictionary`, if possible, from the specified mapping. + /// + /// - parameter mapping: The `Node.Mapping` from which to extract an `NSMutableDictionary`, if possible. + /// + /// - returns: An instance of `NSMutableDictionary`, if one was successfully extracted from the mapping. + public static func construct_mapping(from mapping: Node.Mapping) -> NSMutableDictionary? { + _construct_mapping(from: mapping) + } +} + +private extension NSMutableDictionary { + static func _construct_mapping(from mapping: Node.Mapping) -> NSMutableDictionary { + let result = NSMutableDictionary() + let mapping = mapping.flatten() + + mapping.forEach { key, value in + if let keyString = String.construct(from: key) { + result[keyString] = mapping.tag.constructor.any(from: value) + } + } + return result + } +} + extension Set { /// Construct a `Set`, if possible, from the specified mapping. /// @@ -447,6 +483,23 @@ extension Set { } } +extension NSMutableSet { + /// Construct an `NSMutableSet`, if possible, from the specified mapping. + /// + /// - parameter mapping: The `Node.Mapping` from which to extract an `NSMutableSet`, if possible. + /// + /// - returns: An instance of `NSMutableSet`, if one was successfully extracted from the mapping. + public static func construct_set(from mapping: Node.Mapping) -> NSMutableSet? { + let result = NSMutableSet() + mapping.forEach { key, _ in + if let keyString = String.construct(from: key) { + result.add(keyString as AnyHashable) + } + } + return result + } +} + // MARK: Sequence extension Array { @@ -488,6 +541,53 @@ extension Array { } } +extension NSMutableArray { + /// Construct an NSMutableArray of `Any` from the specified `sequence`. + /// + /// - parameter sequence: Sequence to convert to `NSMutableArray`. + /// + /// - returns: NSMutableArray of `Any`. + public static func construct_seq(from sequence: Node.Sequence) -> NSMutableArray { + let result = NSMutableArray() + sequence.forEach { subnode in + result.add(sequence.tag.constructor.any(from: subnode)) + } + return result + } + + /// Construct an "O-map" (NSMutableArray of `(Any, Any)` tuples) from the specified `sequence`. + /// + /// - parameter sequence: Sequence to convert to `NSMutableArray`. + /// + /// - returns: NSMutableArray of `(Any, Any)` tuples. + public static func construct_omap(from sequence: Node.Sequence) -> NSMutableArray { + let result = NSMutableArray() + sequence.forEach { subnode in + // TODO: Should raise error if subnode is not mapping or mapping.count != 1 + if let (key, value) = subnode.mapping?.first { + result.add((sequence.tag.constructor.any(from: key), sequence.tag.constructor.any(from: value))) + } + } + return result + } + + /// Construct an NSMutableArray of `(Any, Any)` tuples from the specified `sequence`. + /// + /// - parameter sequence: Sequence to convert to `NSMutableArray`. + /// + /// - returns: NSMutableArray of `(Any, Any)` tuples. + public static func construct_pairs(from sequence: Node.Sequence) -> NSMutableArray { + let result = NSMutableArray() + sequence.forEach { subnode in + if let (key, value) = subnode.mapping?.first { + result.add((sequence.tag.constructor.any(from: key), sequence.tag.constructor.any(from: value))) + } + } + return result + } +} + + private extension String { func substring(with range: NSRange) -> Substring? { guard range.location != NSNotFound else { return nil } From a821cd9c7b78940f80b75a62681b0b8aa9a8216f Mon Sep 17 00:00:00 2001 From: Tomasz Popi Date: Mon, 12 Aug 2024 16:45:21 +0200 Subject: [PATCH 3/4] fixes for the linter. --- Sources/Yams/Constructor.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/Yams/Constructor.swift b/Sources/Yams/Constructor.swift index 7077eead..4a46edee 100644 --- a/Sources/Yams/Constructor.swift +++ b/Sources/Yams/Constructor.swift @@ -98,12 +98,14 @@ extension Constructor { .omap: [Any].construct_omap, .pairs: [Any].construct_pairs ] - + + ///`Tag.Name` to `Node.Mapping` map that support dynamic collection. public static let dynamicMappingMap: MappingMap = [ .map: NSMutableDictionary.construct_mapping, .set: NSMutableSet.construct_set ] + ///`Tag.Name` to `Node.Sequence` map that support dynamic collection. public static let dynamicSequenceMap: SequenceMap = [ .seq: NSMutableArray.construct_seq, .omap: NSMutableArray.construct_omap, @@ -587,7 +589,6 @@ extension NSMutableArray { } } - private extension String { func substring(with range: NSRange) -> Substring? { guard range.location != NSNotFound else { return nil } From fdc9878302e1a2d4a6d087ab305e485bcba7ebf0 Mon Sep 17 00:00:00 2001 From: Tomasz Popi Date: Mon, 12 Aug 2024 17:10:47 +0200 Subject: [PATCH 4/4] Code cleaning for the scalar.string to infinity conversion --- Sources/Yams/Constructor.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/Yams/Constructor.swift b/Sources/Yams/Constructor.swift index 4a46edee..41633d69 100644 --- a/Sources/Yams/Constructor.swift +++ b/Sources/Yams/Constructor.swift @@ -265,12 +265,12 @@ extension ScalarConstructible where Self: FloatingPoint & SexagesimalConvertible return nil } - switch scalar.string { - case ".inf", ".Inf", ".INF", "+.inf", "+.Inf", "+.INF": + switch scalar.string.lowercased() { + case ".inf", "+.inf": return .infinity - case "-.inf", "-.Inf", "-.INF": + case "-.inf": return -.infinity - case ".nan", ".NaN", ".NAN": + case ".nan": return .nan default: let string = scalar.string.replacingOccurrences(of: "_", with: "")