Merge pull request #18 from jpsim/nn-further-improve-node

Further improve Node
This commit is contained in:
Norio Nomura 2017-02-04 21:18:30 +09:00 committed by GitHub
commit 2fd2f9c558
3 changed files with 273 additions and 11 deletions

View File

@ -59,7 +59,7 @@ extension Node {
}
public struct Mapping {
public var pairs: [Pair<Node>]
internal var pairs: [Pair<Node>]
public var tag: Tag
public var style: Style
@ -88,7 +88,7 @@ extension Node {
}
public struct Sequence {
public var nodes: [Node]
internal var nodes: [Node]
public var tag: Tag
public var style: Style
@ -248,6 +248,15 @@ extension Node {
self[node] = newValue
}
}
public subscript(string: String) -> Node? {
get {
return self[Node(string)]
}
set {
self[Node(string)] = newValue
}
}
}
// MARK: Hashable
@ -344,6 +353,185 @@ 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: - Node.Sequence
extension Node.Sequence: Equatable {
public static func == (lhs: Node.Sequence, rhs: Node.Sequence) -> Bool {
return lhs.nodes == rhs.nodes
}
}
extension Node.Sequence: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: Node...) {
self.init(nodes: elements, tag: .implicit, style: .any)
}
}
extension Node.Sequence: MutableCollection {
// Sequence
public func makeIterator() -> Array<Node>.Iterator {
return nodes.makeIterator()
}
// Collection
public typealias Index = Array<Node>.Index
public var startIndex: Index {
return nodes.startIndex
}
public var endIndex: Index {
return nodes.endIndex
}
public func index(after index: Index) -> Index {
return nodes.index(after: index)
}
public subscript(index: Index) -> Node {
get {
return nodes[index]
}
// MutableCollection
set {
nodes[index] = newValue
}
}
public subscript(bounds: Range<Index>) -> Array<Node>.SubSequence {
get {
return nodes[bounds]
}
// MutableCollection
set {
nodes[bounds] = newValue
}
}
public var indices: Array<Node>.Indices {
return nodes.indices
}
}
extension Node.Sequence: RandomAccessCollection {
// BidirectionalCollection
public func index(before index: Index) -> Index {
return nodes.index(before: index)
}
// RandomAccessCollection
public func index(_ index: Index, offsetBy num: Int) -> Index {
return nodes.index(index, offsetBy: num)
}
public func distance(from start: Index, to end: Int) -> Index {
return nodes.distance(from: start, to: end)
}
}
extension Node.Sequence: RangeReplaceableCollection {
public init() {
self.init(nodes: [], tag: .implicit, style: .any)
}
public mutating func replaceSubrange<C>(_ subrange: Range<Int>, with newElements: C)
where C : Collection, C.Iterator.Element == Node {
nodes.replaceSubrange(subrange, with: newElements)
}
}
// MARK: - internal
extension Node {
// MARK: Internal convenience accessors
var isScalar: Bool {
@ -367,3 +555,5 @@ extension Node {
return false
}
}
// swiftlint:disable:this file_length

View File

@ -110,15 +110,81 @@ class NodeTests: XCTestCase {
}
func testSubscriptMapping() {
let mapping: Node = ["key1": "value1", "key2": "value2"]
let valueForKey1 = mapping["key1"]?.string
XCTAssertEqual(valueForKey1, "value1")
let mapping: Node = ["key1": "value1", "key2": "value2", "key3": "value3"]
XCTAssertEqual(mapping["key1" as Node]?.string, "value1") // Node resolvable as String
XCTAssertEqual(mapping["key2"]?.string, "value2") // String Literal
XCTAssertEqual(mapping[String("key3")]?.string, "value3") // String
}
func testSubscriptSequence() {
let mapping: Node = ["value1", "value2", "value3"]
let valueAtSecond = mapping[1]?.string
XCTAssertEqual(valueAtSecond, "value2")
XCTAssertEqual(mapping["0" as Node]?.string, "value1") // Node resolvable as Integer
XCTAssertEqual(mapping[1]?.string, "value2") // Integer Literal
XCTAssertEqual(mapping[Int(2)]?.string, "value3") // Int
}
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"])
}
func testSequenceBehavesLikeAnArray() {
let node: Node = ["value1", "value2", "value3"]
let sequence = node.sequence!
XCTAssertEqual(sequence.count, 3)
XCTAssertEqual(sequence.endIndex, 3)
XCTAssertEqual(sequence.first, "value1")
XCTAssertFalse(sequence.isEmpty)
XCTAssertEqual(sequence.last, "value3")
XCTAssertEqual(sequence.lazy.count, 3)
XCTAssertEqual(sequence.startIndex, 0)
XCTAssertEqual(sequence.underestimatedCount, 3)
// subscript
var mutableSequence = sequence
mutableSequence.append("value4")
XCTAssertEqual(mutableSequence.count, 4)
XCTAssertEqual(mutableSequence[3], "value4")
mutableSequence.remove(at: 2)
XCTAssertEqual(mutableSequence.count, 3)
XCTAssertEqual(Array(mutableSequence), ["value1", "value2", "value4"])
// iterator
var iterator = sequence.makeIterator()
XCTAssertEqual(iterator.next(), "value1")
XCTAssertEqual(iterator.next(), "value2")
XCTAssertEqual(iterator.next(), "value3")
XCTAssertNil(iterator.next())
// ExpressibleByArrayLiteral
XCTAssertEqual(sequence, ["value1", "value2", "value3"])
}
}
@ -130,9 +196,12 @@ extension NodeTests {
("testExpressibleByFloatLiteral", testExpressibleByFloatLiteral),
("testExpressibleByIntegerLiteral", testExpressibleByIntegerLiteral),
("testExpressibleByStringLiteral", testExpressibleByStringLiteral),
("testTypedAccessorProperties", testTypedAccessorProperties),
("testArray", testArray),
("testSubscriptMapping", testSubscriptMapping),
("testSubscriptSequence", testSubscriptSequence),
("testArray", testArray)
("testMappingBehavesLikeADictionary", testMappingBehavesLikeADictionary),
("testSequenceBehavesLikeAnArray", testSequenceBehavesLikeAnArray)
]
}
}

View File

@ -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 {