diff --git a/README.md b/README.md
index ed52e8a2..67ec075d 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,10 @@ Read this in [正體中文](https://github.com/vapor/documentation/blob/master/R
You can read this guide by clicking through the folders and markdown files on [GitHub](https://github.com/vapor/documentation) or through the rendered [GitHub Pages](https://vapor.github.io/documentation/).
+## API
+
+Auto-generated API documentation is located at [api.vapor.codes](http://api.vapor.codes).
+
## Packages
Here are a list of all the packages and modules included with Vapor (also useable individually).
@@ -36,7 +40,7 @@ Here are a list of all the packages and modules included with Vapor (also useabl
- [Crypto](https://github.com/vapor/crypto): Cryptography from LibreSSL and Swift.
- Digests: Hashing with and without authentication.
- Ciphers: Encryption and decryption
- - Random: Psuedo and cryptographically secure randomness.
+ - Random: Pseudo and cryptographically secure randomness.
- BCrypt: Pure Swift implementation.
- [Node](https://github.com/vapor/node): Data structure for easy type conversions.
- [Polymorphic](https://github.com/vapor/polymorphic): Syntax for easily accessing values from common types like JSON.
@@ -70,6 +74,9 @@ Here are a list of providers and third party packages that work great with Vapor
- [VaporS3Signer](https://github.com/JustinM1/VaporS3Signer): Generate V4 Auth Header/Pre-Signed URL for AWS S3 REST API
- [Flock](https://github.com/jakeheis/Flock): Automated deployment of Swift projects to servers
- [VaporFlock](https://github.com/jakeheis/VaporFlock): Use Flock to deploy Vapor applications
+- [VaporForms](https://github.com/bygri/vapor-forms): Brings simple, dynamic and re-usable web form handling to Vapor.
+- [Jobs](https://github.com/BrettRToomey/Jobs): A minimalistic job/background-task system for Swift.
+- [Heimdall](https://github.com/himani93/heimdall): An easy to use HTTP request logger.
## Authors
diff --git a/README.zh-hant.md b/README.zh-hant.md
index 3a4a702e..967902d4 100644
--- a/README.zh-hant.md
+++ b/README.zh-hant.md
@@ -67,6 +67,8 @@ Vapor 是一個在 Swift 上很受歡迎的 Web framework。它提供了清楚
- [VaporS3Signer](https://github.com/JustinM1/VaporS3Signer): 用來產生 HTTP request 的 headers 及已經簽證過的 URL,用來 request AWS S3 的 REST API。
- [Flock](https://github.com/jakeheis/Flock): 自動將 Swift 專案發佈上主機。
- [VaporFlock](https://github.com/jakeheis/VaporFlock): 利用 Flock 發佈 Vapor applications。
+- [VaporForms](https://github.com/bygri/vapor-forms)。
+- [Jobs](https://github.com/BrettRToomey/Jobs)。
## 作者們
diff --git a/deploy/supervisor.md b/deploy/supervisor.md
index 9b3a3a86..c84b7217 100644
--- a/deploy/supervisor.md
+++ b/deploy/supervisor.md
@@ -33,7 +33,7 @@ The `--env=production` flag will disable verbose logging and prioritize the `Con
### Environment
-You can export variables to your Vapor app with sueprvisor.
+You can export variables to your Vapor app with supervisor.
```sh
environment=PORT=8123
diff --git a/fluent/driver.md b/fluent/driver.md
index 285b2eea..062899a4 100644
--- a/fluent/driver.md
+++ b/fluent/driver.md
@@ -13,8 +13,8 @@ This graphic shows the relation between Drivers and Providers using MySQL as an
If you want to use Fluent without Vapor, you will import Drivers into your package. If you are using Vapor, you will import Providers.
Search GitHub for:
-- [Fluent Drivers](https://github.com/vapor?utf8=✓&query=-driver)
-- [Vapor Providers](https://github.com/vapor?utf8=✓&query=-provider)
+- [Fluent Drivers](https://github.com/vapor?utf8=✓&q=-driver)
+- [Vapor Providers](https://github.com/vapor?utf8=✓&q=-provider)
Not all drivers have providers yet, and not all drivers or providers are up to date with the latest Vapor 1.0. This is a great way to contribute!
diff --git a/getting-started/manual.md b/getting-started/manual.md
index 5333ab1c..ba91aa2b 100644
--- a/getting-started/manual.md
+++ b/getting-started/manual.md
@@ -60,7 +60,7 @@ import PackageDescription
let package = Package(
name: "Hello",
dependencies: [
- .Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 0)
+ .Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 1)
]
)
```
diff --git a/guide/config.md b/guide/config.md
index e5e3af5e..24c15b49 100644
--- a/guide/config.md
+++ b/guide/config.md
@@ -46,7 +46,7 @@ Let's add a custom key to the `servers.json` file:
This can be accessed from your application's config using the following.
```swift
-let customValue = app.config["server", "http", "custom-key"].string
+let customValue = drop.config["server", "http", "custom-key"]?.string ?? "default"
```
That's it, feel free to add and utilize keys as necessary to make your application configuration easier.
@@ -71,13 +71,13 @@ You can access your config directory with the following syntax. `app.config[<#fi
We can access this file by making sure the first argument in our subscript is keys. To get the first name in our list:
```swift
-let name = app.config["keys", "test-names", 0].string
+let name = drop.config["keys", "test-names", 0]?.string ?? "default"
```
Or our mongo url:
```swift
-let mongoUrl = app.config["keys", "mongo", "url"].string
+let mongoUrl = drop.config["keys", "mongo", "url"].?string ?? "default"
```
## Advanced Configurations
diff --git a/guide/droplet.md b/guide/droplet.md
index cce77d7f..20ebfba5 100644
--- a/guide/droplet.md
+++ b/guide/droplet.md
@@ -94,7 +94,7 @@ The `Droplet` will continue to use the default logger until you modify the `Conf
The `Droplet` init method is fairly simple since most properties are variable and can be changed after initialization.
-Most plugins for Vapor come with a [Provider](providers.md), these take care of configuration details for you.
+Most plugins for Vapor come with a [Provider](provider.md), these take care of configuration details for you.
```swift
Droplet(
diff --git a/guide/json.md b/guide/json.md
index 2579ede9..8b6d4fd9 100644
--- a/guide/json.md
+++ b/guide/json.md
@@ -27,11 +27,11 @@ To specifically target JSON, use the `request.json` property.
```swift
drop.post("json") { request in
- guard let name = request.json["name"].string else {
- throw Abort.badRequest
- }
+ guard let name = request.json?["name"]?.string else {
+ throw Abort.badRequest
+ }
- return "Hello, \(name)!"
+ return "Hello, \(name)!"
}
```
The above snippet will only work if the request is sent with JSON data.
diff --git a/guide/leaf.md b/guide/leaf.md
index b8c964f0..e34bc6f6 100644
--- a/guide/leaf.md
+++ b/guide/leaf.md
@@ -4,7 +4,7 @@ currentMenu: guide-leaf
# Leaf
-Welcome to Leaf. Leaf's goal is to be a simple templating language that can make generating views easier. There's a lot of great templating languages, use what's best for you, maybe that's leaf! The goals of leaf are as follows:
+Welcome to Leaf. Leaf's goal is to be a simple templating language that can make generating views easier. There's a lot of great templating languages, use what's best for you, maybe that's Leaf! The goals of Leaf are as follows:
- Small set of strictly enforced rules
- Consistency
@@ -12,78 +12,88 @@ Welcome to Leaf. Leaf's goal is to be a simple templating language that can make
- Extensibility
## Syntax
-
-Leaf syntax is based around a single token, in this case, the hashtag: `#`.
-
->It's important to note that _all_ hashtags will be parsed, there is no escaping. Use `#()` to render a plain `#`. `#()Leaf` => `#Leaf`. Or, for larger sections, use the `raw` tag. `#raw() { #Do #whatever #you #want #to #in #here!. }`
-
### Structure
-Here we see all the components of a Leaf tag.
+Leaf Tags are made up of 4 Elements:
+ - Token: `#` is the Token
+ - Name: A `string` that identifies the tag
+ - Parameter List: `()` May accept 0 or more arguments
+ - Body(optional): `{}` Must be separated from the Parameter List by a space
-```leaf
-#someTag(parameter.list, goes, "here") {
- This is an optional body here
-}
+There can be many different usages of these 4 elements depending on the Tag's implementation. Let's look at a few examples of how Leaf's built-in Tags might be used:
+
+ - `#()`
+ - `#(variable)`
+ - `#import("template")`
+ - `#export("link") { }`
+ - `#index(friends, "0")`
+ - `#loop(friends, "friend") {
#(friend.name) }`
+ - `#raw() { Anything goes!@#$%^&* }`
+
+### Using the `#` token in HTML
+
+The token cannot be escaped. Use the `#()` or `#raw() {}` Tag to output a `#` in a Leaf Template. `#()` => `#`
+
+### Raw HTML
+
+All Leaf output is escaped by default. Use the `#raw() {}` Tag for unescaped output.
+`#raw() { Link }` => `Link`
+> IMPORTANT! Make sure you are not using the `#raw() {}` Tag with user input.
+
+### Chaining
+
+The double token: `##` indicates a chain. It can be applied to any standard Tag. If the previous Tag fails, the chained Tag will be given an opportunity to run.
+
+```
+#if(hasFriends) ##embed("getFriends")
```
-##### Token
+### Leaf's built-in Tags
->The `#` token will define we're a tag
+#### Token: `#()`
-##### Name
+```
+#() #()hashtags #()FTW => # #Hashtags #FTW
+```
->In above example, it would be `someTag`. While not strictly enforced, it is **highly** encouraged that users only use alphanumeric characters in names. This may be enforced in future versions.
+#### Raw: `#raw() {}`
-##### Parameter List
-
-`Var(parameter, list), Var(goes), Const("here")`
-
-##### Body
-
-> This is an optional body here indicated w/ open and closed curly brackets.
-
-#### Using # in html with Leaf
-
-If you need # to appear alone in your html, simply using `#()` will render as #. Alternatively, the raw tag is available for larger sections of code:
-
-```leaf
+```
#raw() {
- Do whatever w/ #'s here, this code
- won't be rendered as leaf document.
- It's a great place for things like Javascript or large HTML sections.
+ Do whatever w/ #'s here, this code won't be rendered as leaf document and is not escaped.
+ It's a great place for things like Javascript or large HTML sections.
}
```
-## Syntax Highlighting
+#### Equal: `#equal(lhs, rhs) {}`
-### Atom
+```
+#equal(leaf, leaf) { Leaf == Leaf } => Leaf == Leaf
+#equal(leaf, mustache) { Leaf == Mustache } =>
+```
-[language-leaf](https://atom.io/packages/language-leaf) by ButkiewiczP
+#### Variable: `#(variable)`
-## Examples
-
-#### Variable
-
-Variables are added w/ just a number sign.
-
-```leaf
+```
Hello, #(name)!
```
-#### Loop
+#### Loop: `#loop(object, "index")`
-Loop a variable
-
-```leaf
+```
#loop(friends, "friend") {
Hello, #(friend.name)!
}
```
+#### Index: `#loop(object, "index")`
-#### If - Else
+```
+Hello, #index(friends, "0")!
+```
-```leaf
+#### If - Else: `#if(bool) ##else() { this }`
+
+```
#if(entering) {
Hello, there!
} ##if(leaving) {
@@ -93,21 +103,14 @@ Loop a variable
}
```
-#### Chaining
+#### Import: `#import("template")`
+#### Export: `#export("template") { Leaf/HTML }`
+#### Extend: `#extend("template")`
+#### Embed: `#embed("template")`
-The double token, `##` indicates a chain. If the previous tag fails, this tag will be given an opportunity to run. It can be applied to any standard tag, for example, above we chain to else, but we could also chain to loops.
+> When using these Layout Tags, omit the template file's .leaf extension.
```
-#empty(friends) {
- Try adding some friends!
-} ##loop(friends, "friend") {
- #(friend.name)
-}
-```
-
-#### Extending
-
-```swift
/// base.leaf
#import("html")
@@ -115,38 +118,15 @@ The double token, `##` indicates a chain. If the previous tag fails, this tag wi
/// html.leaf
#extend("base")
-#export("html") {
-
-}
-```
-
-Leaf renders `html.leaf` as:
-
-```html
-
-
-```
-
-#### Embedding
-
-```swift
-/// base.leaf
-
-#import("html")
-
-/// html.leaf
-#extend("base")
-
-#export("html") {
- #embed("body")
-}
+#export("html") { #embed("body") }
/// body.leaf
```
+
Leaf renders `html.leaf` as:
-```html
+```
```
@@ -155,40 +135,45 @@ Leaf renders `html.leaf` as:
Look at the existing tags for advanced scenarios, let's look at a basic example by creating `Index` together. This tag will take two arguments, an array, and an index to access.
-```
+```swift
class Index: BasicTag {
- let name = "index"
+ let name = "index"
- func run(arguments: [Argument]) throws -> Node? {
- guard
- arguments.count == 2,
- let array = arguments[0].value?.nodeArray,
- let index = arguments[1].value?.int,
- index < array.count
- else { return nil }
+ func run(arguments: [Argument]) throws -> Node? {
+ guard
+ arguments.count == 2,
+ let array = arguments[0].value?.nodeArray,
+ let index = arguments[1].value?.int,
+ index < array.count
+ else { return nil }
return array[index]
}
}
```
-Now, after creating our `Stem`, we can register the tag:
+We can now register this Tag in our `main.swift` file with:
-```
-stem.register(Index())
-```
-
-And use it like so:
-
-```
-Hello, #index(friends, "0")!
-```
-
-We can also chain `else` to this like we did earlier if we want to check existence first:
-
-```
-#index(friends, "0") {
- Hello, #(self)!
-} ##else() {
- Nobody's there!
+```swift
+if let leaf = drop.view as? LeafRenderer {
+ leaf.stem.register(Version())
}
```
+
+And use it just like we did [above](#index).
+
+> Note: Use of non-alphanumeric characters in Tag Names is **strongly discouraged** and may be disallowed in future versions of Leaf.
+
+## Syntax Highlighting
+
+### Atom
+
+[language-leaf](https://atom.io/packages/language-leaf) by ButkiewiczP
+
+### Xcode
+It is not currently possible to implement Leaf Syntax Highlighting in Xcode, however, using Xcode's HTML Syntax Coloring can help a bit. Select one or more Leaf files and then choose Editor > Syntax Coloring > HTML. Your selected Leaf files will now use Xcode's HTML Syntax Coloring. Unfortunately the usefulness of this is limited because this association will be removed when `vapor xcode` is run.
+
+There appears to be a way to [make Xcode file associations persist](http://stackoverflow.com/questions/9050035/how-to-make-xcode-recognize-a-custom-file-extension-as-objective-c-for-syntax-hi) but that requires a bit more kung-fu.
+
+### CLion & AppCode
+
+Some preliminary work has been done to implement a Leaf Plugin for CLion & AppCode but lack of skill and interest in Java has slowed progress! If you have IntelliJ SDK experience and want to help with this, message Tom Holland on [Vapor Slack](http://vapor.team)
diff --git a/guide/middleware.md b/guide/middleware.md
index a1b2dcd4..de9fa764 100644
--- a/guide/middleware.md
+++ b/guide/middleware.md
@@ -84,7 +84,7 @@ enum FooError: Error {
}
```
-Say there is a custom error that either you defined or one of the APIs you are using `throw`s. This error must be caught when thrown, or else it will end up as a server error which may be unexpected to a user. The most obvious solution is to catch the error in the route closure.
+Say there is a custom error that either you defined or one of the APIs you are using `throws`. This error must be caught when thrown, or else it will end up as a server error which may be unexpected to a user. The most obvious solution is to catch the error in the route closure.
```swift
app.get("foo") { request in
@@ -180,14 +180,14 @@ Middleware pairs great with request/response extensions and storage.
final class PokemonMiddleware: Middleware {
let drop: Droplet
init(drop: Droplet) {
- self.drop = dropt
+ self.drop = drop
}
func respond(to request: Request, chainingTo next: Responder) throws -> Response {
let response = try next.respond(to: request)
if let pokemon = response.pokemon {
- request.accept.prefers("html") {
+ if request.accept.prefers("html") {
response.view = try drop.view("pokemon.mustache", context: pokemon)
} else {
response.json = try pokemon.makeJSON()
diff --git a/guide/provider.md b/guide/provider.md
index 506e83ac..2a4b5920 100644
--- a/guide/provider.md
+++ b/guide/provider.md
@@ -12,7 +12,7 @@ Adding a provider to your application takes 2-3 steps.
### Add Package
-All of Vapor's providers end with the `-provider` syntax. You can see a list of [available providers](https://github.com/vapor?utf8=✓&query=-provider) by searching on our GitHub.
+All of Vapor's providers end with the `-provider` syntax. You can see a list of [available providers](https://github.com/vapor?utf8=✓&q=-provider) by searching on our GitHub.
To add the provider to your package, add it as a dependency in your `Package.swift` file.
@@ -74,8 +74,8 @@ import VaporMySQL
let drop = Droplet()
-let mysql = VaporMySQL.Provider(host: "localhost", user: "root")
-try drop.addProvider(mysql)
+let mysql = try VaporMySQL.Provider(host: "localhost", user: "root", password: "", database: "vapor")
+drop.addProvider(mysql)
...
diff --git a/routing/parameters.md b/routing/parameters.md
index 846b8a5e..a0886167 100644
--- a/routing/parameters.md
+++ b/routing/parameters.md
@@ -20,7 +20,7 @@ This creates a route that matches `users/:id` where the `:id` is an `Int`. Here'
```swift
drop.get("users", ":id") { request in
- guard let userId = request.parameters["id"].int else {
+ guard let userId = request.parameters["id"]?.int else {
throw Abort.badRequest
}
@@ -109,7 +109,7 @@ The resulting path for the above example is `/v1/users/:userId/posts/:postId`. I
As shown briefly above, you are still free to do traditional routing. This can be useful for especially complex situations.
```swift
-drop.get("v1", "users", ":userId", "posts", ":postId", "comments": ":commentId") { request in
+drop.get("v1", "users", ":userId", "posts", ":postId", "comments", ":commentId") { request in
let userId = try request.parameters.extract("userId") as Int
let postId = try request.parameters.extract("postId") as Int
let commentId = try request.parameters.extract("commentId") as Int
diff --git a/template/default.twig b/template/default.twig
index b5d91911..f12e7f22 100644
--- a/template/default.twig
+++ b/template/default.twig
@@ -69,6 +69,46 @@
+
+
",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"?",e:"/?>",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("http",function(e){var t="HTTP/[0-9\\.]+";return{aliases:["https"],i:"\\S",c:[{b:"^"+t,e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{b:"^[A-Z]+ (.*?) "+t+"$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0},{b:t},{cN:"keyword",b:"[A-Z]+"}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{e:"$",r:0}},{b:"\\n\\n",starts:{sL:[],eW:!0}}]}});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b:/,e:/(\/\w+|\w+\/)>/,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\._]+/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("swift",function(e){var t={keyword:"__COLUMN__ __FILE__ __FUNCTION__ __LINE__ as as! as? associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip"},i={cN:"type",b:"\\b[A-Z][\\wÀ-ʸ']*",r:0},n=e.C("/\\*","\\*/",{c:["self"]}),r={cN:"subst",b:/\\\(/,e:"\\)",k:t,c:[]},a={cN:"number",b:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",r:0},o=e.inherit(e.QSM,{c:[r,e.BE]});return r.c=[a],{k:t,c:[o,e.CLCM,n,i,a,{cN:"function",bK:"func",e:"{",eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{b:/,e:/>/},{cN:"params",b:/\(/,e:/\)/,endsParent:!0,k:t,c:["self",a,o,e.CBCM,{b:":"}],i:/["']/}],i:/\[|%/},{cN:"class",bK:"struct protocol class extension enum",k:t,e:"\\{",eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{cN:"meta",b:"(@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain)"},{bK:"import",e:/$/,c:[e.CLCM,n]}]}});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});
\ No newline at end of file
diff --git a/testing/basic.md b/testing/basic.md
index 1c3a5a3b..d70d1cc0 100644
--- a/testing/basic.md
+++ b/testing/basic.md
@@ -48,7 +48,7 @@ drop.run()
The first thing we'll do is in my testing target, add a file called `Droplet+Test.swift`. It will look like this:
```swift
-import Vapor
+@testable import Vapor
func makeTestDroplet() throws -> Droplet {
let drop = Droplet(arguments: ["dummy/path/", "prepare"], ...)
@@ -58,7 +58,7 @@ func makeTestDroplet() throws -> Droplet {
}
```
-This looks a lot like our initializer in `main.swift`, but there are 2 very key differences.
+This looks a lot like our initializer in `main.swift`, but there are 3 very key differences.
### Droplet(arguments: ["dummy/path/", "prepare"], ...
@@ -68,6 +68,10 @@ The `arguments:` parameter in our `Droplet` creation. This is rarely used except
You'll notice here that we're calling `runCommands()` instead of `run()`. This allows the `Droplet` to do all the setup it would normally do before booting without actually binding to a socket or exiting.
+### `@testable import Vapor`
+
+We'll need to import the testable compilation of Vapor to access the `runCommands` function. This is currently not public as a protection against accidental bugs in live apps.
+
## Test Our Droplet
Now that all of this has been created, we're ready to start testing our application's `Droplet`. Here's how a really basic test might look: