Make `Node.Mapping` behave like a `Dictionary<Node, Node>`
This commit is contained in:
parent
71e81e9fbc
commit
c625d66880
|
@ -344,6 +344,98 @@ extension Node: ExpressibleByStringLiteral {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Node.Mapping
|
||||
|
||||
extension Node.Mapping: Equatable {
|
||||
public static func == (lhs: Node.Mapping, rhs: Node.Mapping) -> Bool {
|
||||
return lhs.pairs == rhs.pairs
|
||||
}
|
||||
}
|
||||
|
||||
extension Node.Mapping: ExpressibleByDictionaryLiteral {
|
||||
public init(dictionaryLiteral elements: (Node, Node)...) {
|
||||
self.init(pairs: elements.map(Pair.init), tag: .implicit, style: .any)
|
||||
}
|
||||
}
|
||||
|
||||
extension Node.Mapping: MutableCollection {
|
||||
public typealias Element = (key: Node, value: Node)
|
||||
|
||||
// Sequence
|
||||
public func makeIterator() -> Array<Element>.Iterator {
|
||||
let iterator = pairs.map({ (key: $0.key, value: $0.value) }).makeIterator()
|
||||
return iterator
|
||||
}
|
||||
|
||||
// Collection
|
||||
public typealias Index = Array<Element>.Index
|
||||
|
||||
public var startIndex: Int {
|
||||
return pairs.startIndex
|
||||
}
|
||||
|
||||
public var endIndex: Int {
|
||||
return pairs.endIndex
|
||||
}
|
||||
|
||||
public func index(after index: Int) -> Int {
|
||||
return pairs.index(after:index)
|
||||
}
|
||||
|
||||
public subscript(index: Int) -> Element {
|
||||
get {
|
||||
return (key: pairs[index].key, value: pairs[index].value)
|
||||
}
|
||||
// MutableCollection
|
||||
set {
|
||||
pairs[index] = Pair(newValue.key, newValue.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Node.Mapping {
|
||||
public var keys: LazyMapCollection<Node.Mapping, Node> {
|
||||
return lazy.map { $0.key }
|
||||
}
|
||||
|
||||
public var values: LazyMapCollection<Node.Mapping, Node> {
|
||||
return lazy.map { $0.value }
|
||||
}
|
||||
|
||||
public subscript(string: String) -> Node? {
|
||||
get {
|
||||
return self[Node(string)]
|
||||
}
|
||||
set {
|
||||
self[Node(string)] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public subscript(node: Node) -> Node? {
|
||||
get {
|
||||
let v = pairs.reversed().first(where: { $0.key == node })
|
||||
return v?.value
|
||||
}
|
||||
set {
|
||||
if let newValue = newValue {
|
||||
if let index = pairs.reversed().index(where: { $0.key == node }) {
|
||||
let actualIndex = pairs.index(before: index.base)
|
||||
pairs[actualIndex] = Pair(pairs[actualIndex].key, newValue)
|
||||
} else {
|
||||
pairs.append(Pair(node, newValue))
|
||||
}
|
||||
} else {
|
||||
if let index = pairs.reversed().index(where: { $0.key == node }) {
|
||||
let actualIndex = pairs.index(before: index.base)
|
||||
pairs.remove(at: actualIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - internal
|
||||
|
||||
extension Node {
|
||||
// MARK: Internal convenience accessors
|
||||
var isScalar: Bool {
|
||||
|
@ -367,3 +459,5 @@ extension Node {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:this file_length
|
||||
|
|
|
@ -120,6 +120,38 @@ class NodeTests: XCTestCase {
|
|||
let valueAtSecond = mapping[1]?.string
|
||||
XCTAssertEqual(valueAtSecond, "value2")
|
||||
}
|
||||
|
||||
func testMappingBehavesLikeADictionary() {
|
||||
let node: Node = ["key1": "value1", "key2": "value2"]
|
||||
let mapping = node.mapping!
|
||||
XCTAssertEqual(mapping.count, 2)
|
||||
XCTAssertEqual(mapping.endIndex, 2)
|
||||
XCTAssertTrue(mapping.first! == ("key1", "value1"))
|
||||
XCTAssertFalse(mapping.isEmpty)
|
||||
XCTAssertEqual(Set(mapping.keys), ["key1", "key2"])
|
||||
XCTAssertEqual(mapping.lazy.count, 2)
|
||||
XCTAssertEqual(mapping.startIndex, 0)
|
||||
XCTAssertEqual(mapping.underestimatedCount, 2)
|
||||
XCTAssertEqual(Set(mapping.values), ["value1", "value2"])
|
||||
|
||||
// subscript
|
||||
var mutableMapping = mapping
|
||||
mutableMapping["key3"] = "value3"
|
||||
XCTAssertEqual(mutableMapping["key3"], "value3")
|
||||
mutableMapping["key3"] = "value3changed"
|
||||
XCTAssertEqual(mutableMapping["key3"], "value3changed")
|
||||
mutableMapping["key3"] = nil
|
||||
XCTAssertNil(mutableMapping["key3"])
|
||||
|
||||
// iterator
|
||||
var iterator = mapping.makeIterator()
|
||||
XCTAssertTrue(iterator.next()! == ("key1", "value1"))
|
||||
XCTAssertTrue(iterator.next()! == ("key2", "value2"))
|
||||
XCTAssertNil(iterator.next())
|
||||
|
||||
// ExpressibleByDictionaryLiteral
|
||||
XCTAssertEqual(mapping, ["key1": "value1", "key2": "value2"])
|
||||
}
|
||||
}
|
||||
|
||||
extension NodeTests {
|
||||
|
@ -130,9 +162,11 @@ extension NodeTests {
|
|||
("testExpressibleByFloatLiteral", testExpressibleByFloatLiteral),
|
||||
("testExpressibleByIntegerLiteral", testExpressibleByIntegerLiteral),
|
||||
("testExpressibleByStringLiteral", testExpressibleByStringLiteral),
|
||||
("testTypedAccessorProperties", testTypedAccessorProperties),
|
||||
("testArray", testArray),
|
||||
("testSubscriptMapping", testSubscriptMapping),
|
||||
("testSubscriptSequence", testSubscriptSequence),
|
||||
("testArray", testArray)
|
||||
("testMappingBehavesLikeADictionary", testMappingBehavesLikeADictionary)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,11 +62,12 @@ class PerformanceTests: XCTestCase {
|
|||
XCTFail("Can't load \(filename)")
|
||||
return
|
||||
}
|
||||
let spmName = "SourceKittenFramework"
|
||||
self.measure {
|
||||
do {
|
||||
guard let yaml = try Yams.load(yaml: yamlString) as? [String:Any],
|
||||
let commands = yaml["commands"] as? [String:Any],
|
||||
let moduleCommand = commands["<SourceKittenFramework.module>"] as? [String:Any],
|
||||
let commands = (yaml["commands"] as? [String:[String:Any]])?.values,
|
||||
let moduleCommand = commands.first(where: { ($0["module-name"] as? String ?? "") == spmName }),
|
||||
let imports = moduleCommand["import-paths"] as? [String],
|
||||
let otherArguments = moduleCommand["other-args"] as? [String],
|
||||
let sources = moduleCommand["sources"] as? [String] else {
|
||||
|
@ -87,10 +88,12 @@ class PerformanceTests: XCTestCase {
|
|||
XCTFail("Can't load \(filename)")
|
||||
return
|
||||
}
|
||||
let spmName = "SourceKittenFramework"
|
||||
self.measure {
|
||||
do {
|
||||
guard let yaml = try Yams.compose(yaml: yamlString),
|
||||
let moduleCommand = yaml["commands"]?["<SourceKittenFramework.module>"],
|
||||
let commands = yaml["commands"]?.mapping?.values,
|
||||
let moduleCommand = commands.first(where: { $0["module-name"]?.string == spmName }),
|
||||
let imports = moduleCommand["import-paths"]?.array(of: String.self),
|
||||
let otherArguments = moduleCommand["other-args"]?.array(of: String.self),
|
||||
let sources = moduleCommand["sources"]?.array(of: String.self) else {
|
||||
|
|
Loading…
Reference in New Issue