Skip to content

Commit c2cb7b7

Browse files
authored
Merge pull request #1 from vapor/test-cov
Test cov
2 parents ef28394 + 2cc473c commit c2cb7b7

39 files changed

+1010
-538
lines changed

.swift-version

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DEVELOPMENT-SNAPSHOT-2016-08-18-a

.travis.yml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
os:
2+
- linux
3+
- osx
4+
language: generic
5+
sudo: required
6+
dist: trusty
7+
osx_image: xcode8
8+
script:
9+
- eval "$(curl -sL swift.vapor.sh/ci)"
10+
- eval "$(curl -sL swift.vapor.sh/codecov)"

Sources/Leaf/Argument.swift

+11
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,14 @@ public enum Argument {
1313
*/
1414
case constant(value: String)
1515
}
16+
17+
extension Argument {
18+
var value: Node? {
19+
switch self {
20+
case let .constant(value: value):
21+
return .string(value)
22+
case let .variable(path: _, value: value):
23+
return value
24+
}
25+
}
26+
}

Sources/Leaf/Buffer/Buffer+Leaf.swift

+21-14
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ extension BufferProtocol where Element == Byte {
33
var comps: [Leaf.Component] = []
44
while let next = try nextComponent() {
55
if case let .tagTemplate(i) = next, i.isChain {
6-
guard comps.count > 0 else { throw "invalid chain component w/o preceeding tagTemplate" }
6+
guard comps.count > 0 else {
7+
throw ParseError.expectedLeadingTemplate(have: nil)
8+
}
79
while let last = comps.last {
810
var loop = true
911

@@ -30,16 +32,12 @@ extension BufferProtocol where Element == Byte {
3032

3133
mutating func nextComponent() throws -> Leaf.Component? {
3234
guard let token = current else { return nil }
33-
if token == TOKEN {
34-
let tagTemplate = try extractInstruction()
35-
return .tagTemplate(tagTemplate)
36-
} else {
37-
let raw = extractUntil { $0 == TOKEN }
38-
return .raw(raw)
39-
}
35+
guard token == TOKEN else { return .raw(extractUntil { $0 == TOKEN }) }
36+
let tagTemplate = try extractInstruction()
37+
return .tagTemplate(tagTemplate)
4038
}
4139

42-
mutating func extractUntil(_ until: @noescape (Element) -> Bool) -> [Element] {
40+
mutating func extractUntil(_ until: (Element) -> Bool) -> [Element] {
4341
var collection = Bytes()
4442
if let current = current {
4543
guard !until(current) else { return [] }
@@ -53,6 +51,14 @@ extension BufferProtocol where Element == Byte {
5351
}
5452
}
5553

54+
enum ParseError: LeafError {
55+
case tagTemplateNotFound(name: String)
56+
case missingBodyOpener(expected: String, have: String?)
57+
case missingBodyCloser(expected: String)
58+
case expectedOpenParenthesis
59+
case expectedLeadingTemplate(have: Leaf.Component?)
60+
}
61+
5662
/*
5763
Syntax
5864

@@ -77,11 +83,11 @@ extension BufferProtocol where Element == Byte {
7783
}
7884

7985
mutating func extractInstructionName() throws -> String {
80-
// can't extract section because of @@
81-
guard current == TOKEN else { throw "tagTemplate name must lead with token" }
8286
moveForward() // drop initial token from name. a secondary token implies chain
8387
let name = extractUntil { $0 == .openParenthesis }
84-
guard current == .openParenthesis else { throw "tagTemplate names must be alphanumeric and terminated with '('" }
88+
guard current == .openParenthesis else {
89+
throw ParseError.expectedOpenParenthesis
90+
}
8591
return name.string
8692
}
8793

@@ -98,7 +104,8 @@ extension BufferProtocol where Element == Byte {
98104

99105
mutating func extractSection(opensWith opener: Byte, closesWith closer: Byte) throws -> Bytes {
100106
guard current == opener else {
101-
throw "invalid body, missing opener: \([opener].string)"
107+
let have = current.flatMap { [$0] }?.string
108+
throw ParseError.missingBodyOpener(expected: [opener].string, have: have)
102109
}
103110

104111
var subBodies = 0
@@ -112,7 +119,7 @@ extension BufferProtocol where Element == Byte {
112119
}
113120

114121
guard current == closer else {
115-
throw "invalid body, missing closer: \([closer].string), got \([current])"
122+
throw ParseError.missingBodyCloser(expected: [closer].string)
116123
}
117124

118125
return body

Sources/Leaf/Buffer/Buffer.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ struct Buffer<T>: BufferProtocol {
77

88
private var buffer: IndexingIterator<[T]>
99

10-
init<S: Sequence where S.Iterator.Element == T>(_ sequence: S) {
10+
init<S: Sequence>(_ sequence: S) where S.Iterator.Element == T {
1111
buffer = sequence.array.makeIterator()
1212
// queue up first
1313
moveForward() // sets next

Sources/Leaf/Context.swift

+3-14
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,12 @@ public final class Context {
3636

3737
// TODO: Subscripts
3838

39-
public func get(key: String) -> Node? {
40-
return queue.lazy.flatMap { $0[key] } .first
41-
}
42-
43-
public func get(path: String) -> Node? {
39+
subscript(path: String) -> Node? {
4440
let components = path.components(separatedBy: ".")
45-
return get(path: components)
41+
return self[components]
4642
}
4743

48-
public func get(path: [String]) -> Node? {
44+
subscript(path: [String]) -> Node? {
4945
for node in queue {
5046
guard let value = node[path] else { continue }
5147
return value
@@ -62,10 +58,3 @@ public final class Context {
6258
return queue.removeTip()
6359
}
6460
}
65-
66-
67-
extension Context {
68-
internal func renderedSelf() throws -> Bytes? {
69-
return try get(path: "self")?.rendered()
70-
}
71-
}

Sources/Leaf/Leaf.swift

+7-3
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@ public final class Leaf {
2929

3030
extension Leaf: CustomStringConvertible {
3131
public var description: String {
32-
let components = self.components.map { $0.description } .joined(separator: ", ")
33-
return "Leaf: " + components
32+
let components = self.components.map { $0.description } .joined(separator: "\n")
33+
return "Leaf: \n" + components
3434
}
3535
}
3636

3737
extension Leaf: Equatable {}
3838
public func == (lhs: Leaf, rhs: Leaf) -> Bool {
39-
return lhs === rhs
39+
for (l, r) in zip(lhs.components, rhs.components) where l != r {
40+
return false
41+
}
42+
43+
return lhs.raw == rhs.raw
4044
}

Sources/Leaf/LeafComponent.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extension Leaf.Component {
1010
internal mutating func addToChain(_ chainedInstruction: TagTemplate) throws {
1111
switch self {
1212
case .raw(_):
13-
throw "unable to chain \(chainedInstruction) w/o preceding tagTemplate"
13+
throw ParseError.expectedLeadingTemplate(have: self)
1414
case let .tagTemplate(current):
1515
self = .chain([current, chainedInstruction])
1616
case let .chain(chain):
@@ -39,6 +39,8 @@ public func == (lhs: Leaf.Component, rhs: Leaf.Component) -> Bool {
3939
return l == r
4040
case let (.tagTemplate(l), .tagTemplate(r)):
4141
return l == r
42+
case let (.chain(l), .chain(r)):
43+
return l == r
4244
default:
4345
return false
4446
}

Sources/Leaf/LeafError.swift

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
// TODO: Real Errors
22
extension String: Swift.Error {}
3+
protocol LeafError: Swift.Error {}
4+

Sources/Leaf/Link.swift

+3-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public final class Link<Value> { // TODO: Rename Context
5656
/**
5757
Sever the child of this Link. This will also lose all children of that link.
5858
*/
59+
@discardableResult
5960
public func dropChild() -> Link? {
6061
let child = self.child
6162
self.child = nil
@@ -75,8 +76,8 @@ public final class Link<Value> { // TODO: Rename Context
7576
}
7677

7778
/**
78-
Adds a new, or replaces the existing child associated with this link
79-
*/
79+
Adds a new, or replaces the existing child associated with this link
80+
*/
8081
public func addChild(_ link: Link?) {
8182
if let existingChild = child { existingChild.parent = nil }
8283
self.child = link

Sources/Leaf/List.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
where performance lists are required.
44
*/
55
public final class List<Value> {
6-
private var tip: Link<Value>?
6+
public fileprivate(set) var tip: Link<Value>?
77

88
public init() {}
99

@@ -31,7 +31,7 @@ public final class List<Value> {
3131
@discardableResult
3232
public func removeTail() -> Value? {
3333
let tail = tip?.tail()
34-
tail?.dropParent()
34+
_ = tail?.dropParent()
3535
return tail?.value
3636
}
3737
}
@@ -52,7 +52,7 @@ extension List: Sequence {
5252
}
5353

5454
extension List {
55-
public convenience init<S: Sequence where S.Iterator.Element == Value>(_ s: S) {
55+
public convenience init<S: Sequence>(_ s: S) where S.Iterator.Element == Value {
5656
self.init()
5757
s.forEach(insertAtTail)
5858
}

Sources/Leaf/NSData+File.swift

+1-6
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@ import Foundation
22

33
extension Sequence where Iterator.Element == Byte {
44
internal static func load(path: String) throws -> Bytes {
5-
guard let data = NSData(contentsOfFile: path) else {
6-
throw "unable to load bytes \(path)"
7-
}
8-
var bytes = Bytes(repeating: 0, count: data.length)
9-
data.getBytes(&bytes, length: bytes.count)
10-
return bytes
5+
return try DataFile().load(path: path)
116
}
127
}

Sources/Leaf/Parameter.swift

+10-3
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,20 @@ public func == (lhs: Parameter, rhs: Parameter) -> Bool {
4040
}
4141

4242
extension Parameter {
43-
internal init<S: Sequence where S.Iterator.Element == Byte>(_ bytes: S) throws {
43+
public enum Error: LeafError {
44+
case nonEmptyArgumentRequired
45+
}
46+
47+
internal init<S: Sequence>(_ bytes: S) throws where S.Iterator.Element == Byte {
4448
let bytes = bytes.array.trimmed(.whitespace)
45-
guard !bytes.isEmpty else { throw "invalid argument: empty" }
49+
guard !bytes.isEmpty else { throw Error.nonEmptyArgumentRequired }
4650
if bytes.count > 1, bytes.first == .quotationMark, bytes.last == .quotationMark {
4751
self = .constant(value: bytes.dropFirst().dropLast().string)
4852
} else {
49-
let path = bytes.split(separator: .period, omittingEmptySubsequences: true)
53+
let path = bytes.split(
54+
separator: .period,
55+
omittingEmptySubsequences: true
56+
)
5057
.map { $0.string }
5158
self = .variable(path: path)
5259
}

Sources/Leaf/Stem+Render.swift

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
let val = [String](repeating: "Hello, World!", count: 1000).joined(separator: ", ").bytes
21
extension Stem {
32
/*
43
Renders a given leaf with the given context
@@ -41,12 +40,7 @@ extension Stem {
4140
leaf: Leaf,
4241
context: Context
4342
) throws -> (tag: Tag, value: Node?, shouldRender: Bool) {
44-
45-
/*
46-
return (Variable(), Optional(Node("World")), true)
47-
*/
48-
49-
guard let tag = tags[tagTemplate.name] else { throw "unsupported tagTemplate" }
43+
guard let tag = tags[tagTemplate.name] else { throw ParseError.tagTemplateNotFound(name: tagTemplate.name) }
5044

5145
let arguments = try tag.makeArguments(
5246
stem: self,

Sources/Leaf/Stem+Spawn.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
extension Stem {
32
public func spawnLeaf(raw: String) throws -> Leaf {
43
return try spawnLeaf(raw: raw.bytes)
@@ -30,7 +29,7 @@ extension Stem {
3029
private func postCompile(_ component: Leaf.Component) throws -> Leaf.Component {
3130
func commandPostcompile(_ tagTemplate: TagTemplate) throws -> TagTemplate {
3231
guard let command = tags[tagTemplate.name] else {
33-
throw "unsupported tagTemplate: \(tagTemplate.name)"
32+
throw ParseError.tagTemplateNotFound(name: tagTemplate.name)
3433
}
3534
return try command.postCompile(stem: self,
3635
tagTemplate: tagTemplate)

Sources/Leaf/Stem.swift

+8-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
1-
private var workDir: String {
2-
let parent = #file.characters.split(separator: "/").map(String.init).dropLast().joined(separator: "/")
3-
let path = "/\(parent)/../../Resources/"
4-
return path
5-
}
6-
71
public final class Stem {
82
public let workingDirectory: String
9-
public private(set) var tags: [String: Tag] = defaultTags
10-
public private(set) var cache: [String: Leaf] = [:]
3+
public fileprivate(set) var tags: [String: Tag] = defaultTags
4+
public fileprivate(set) var cache: [String: Leaf] = [:]
115

12-
public init(workingDirectory: String = workDir) {
6+
public init(workingDirectory: String) {
137
self.workingDirectory = workingDirectory.finished(with: "/")
148
}
159
}
@@ -26,6 +20,10 @@ extension Stem {
2620
}
2721

2822
public func remove(_ tag: Tag) {
29-
tags[tag.name] = nil
23+
removeTag(named: tag.name)
24+
}
25+
26+
public func removeTag(named name: String) {
27+
tags[name] = nil
3028
}
3129
}

Sources/Leaf/Tag/Models/If.swift

+6-28
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
public final class If: Tag {
2+
public enum Error: LeafError {
3+
case expectedSingleArgument(have: [Argument])
4+
}
5+
26
public let name = "if"
37

48
public func run(
59
stem: Stem,
610
context: Context,
711
tagTemplate: TagTemplate,
812
arguments: [Argument]) throws -> Node? {
9-
guard arguments.count == 1 else { throw "invalid if statement arguments" }
13+
guard arguments.count == 1 else { throw Error.expectedSingleArgument(have: arguments) }
1014
return nil
1115
}
1216

@@ -16,32 +20,6 @@ public final class If: Tag {
1620
tagTemplate: TagTemplate,
1721
arguments: [Argument],
1822
value: Node?) -> Bool {
19-
guard arguments.count == 1 else { return false }
20-
let argument = arguments[0]
21-
switch argument {
22-
case let .constant(value: value):
23-
return value.bool == true
24-
case let .variable(path: _, value: value):
25-
return value?.bool == true
26-
}
27-
/*
28-
let argument = arguments[0]
29-
switch argument {
30-
case let .constant(value: value):
31-
let bool = Bool(value)
32-
return bool == true
33-
case let .variable(key: _, value: value as Bool):
34-
return value
35-
case let .variable(key: _, value: value as String):
36-
let bool = Bool(value)
37-
return bool == true
38-
case let .variable(key: _, value: value as Int):
39-
return value == 1
40-
case let .variable(key: _, value: value as Double):
41-
return value == 1.0
42-
case let .variable(key: _, value: value):
43-
return value != nil
44-
}
45-
*/
23+
return arguments.first?.value?.bool == true
4624
}
4725
}

0 commit comments

Comments
 (0)