Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ Hummingbird documentation is generated using Apple's docc documentation compiler
```
HUMMINGBIRD_VERSION=2.0 ./scripts/build-docc.sh
```
If you are editing documentation inside VSCdde, the default build task will run the code above.
If you are editing documentation inside VS Code, the default build task runs the code above.

## Testing changes

To test changes locally you can use [swift-web](https://github.com/adam-fowler/swift-web). Once it is installed run `swift web docs` to run a local HTTP file server with base directory set to the `docs` folder. You can then access the documentation in your web browser from `http://localhost:8001/<version-number>/documentation/index`.

## Submitting changes

Changes should be submitting in a PR. In the PR please describe what the changes are and why they are needed. Also try to keep PRs to a minimal number of changes as possible. It is a lot easier to review multiple PRs of smaller changes than one big PR.
Changes should be submitted in a PR. In the PR please describe what the changes are and why they are needed. Also try to keep PRs to a minimal number of changes as possible. It is a lot easier to review multiple PRs of smaller changes than one big PR.

## Deploying changes

Expand Down
10 changes: 5 additions & 5 deletions Hummingbird.docc/Mustache/Mustache.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ Mustache template engine.

## Overview

Mustache is a "logic-less" templating language commonly used in web and mobile platforms. You can find out more about Mustache [here](http://mustache.github.io/mustache.5.html).
Mustache is a "logic-less" templating language commonly used in web and mobile platforms. You can find out more about it from the [mustache manual](http://mustache.github.io/mustache.5.html).

While swift-mustache has been designed to be used with the Hummingbird server framework it has no dependencies and can be used as a standalone library.
While swift-mustache has been designed to be used with the Hummingbird server framework, it has no dependencies and can be used as a standalone library.

## Usage

Load your templates from the filesystem
```swift
let library = MustacheLibrary("folder/my/templates/are/in")
```
This will look for all the files with the extension ".mustache" in the specified folder and subfolders and attempt to load them. Each file is registed with the name of the file (with subfolder, if inside a subfolder) minus the "mustache" extension.
This will look for all the files with the extension `.mustache` in the specified folder and subfolders and attempt to load them. Each file is registered with the name of the file (with subfolder, if inside a subfolder) minus the `.mustache` extension.

Render an object with a template
The following code shows how to render an object with a template:
```swift
let output = library.render(object, withTemplate: "myTemplate")
```
`Mustache` treats an object as a set of key/value pairs when rendering and will render both dictionaries and objects via `Mirror` reflection.
`Mustache` treats an object as a set of key/value pairs when rendering and renders both dictionaries and objects via `Mirror` reflection.

## Support

Expand Down
150 changes: 95 additions & 55 deletions Hummingbird.docc/Mustache/MustacheFeatures.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,20 @@ The library provides support for mustache lambdas via the type `MustacheLambda`.

### Rendering variables

The mustache manual section for mustache lambdas when rendered as variables states.
The mustache manual section for rendering lambdas as variables states:

> Manual: If any value found during the lookup is a callable object, such as a function or lambda, this object will be invoked with zero arguments. The value that is returned is then used instead of the callable object itself.
> Manual: If any value found during the lookup is a callable object, such as a function or lambda, this object will be invoked with zero arguments.
> The value that is returned is then used instead of the callable object itself.
>
> An optional part of the specification states that if the final key in the name is a lambda that returns a string, then that string should be rendered as a Mustache template before interpolation. It will be rendered using the default delimiters (see Set Delimiter below) against the current context.

Swift Mustache supports both parts of the specification of lambdas when rendered as variables. Instead of a callable object, swift-mustache requires the type to be a `MustacheLambda` initialized with a closure that has no parameters.
Swift Mustache supports both parts of the specification of lambdas when rendered as variables. Instead of a callable object, swift-mustache requires the type to be an instance of `MustacheLambda` initialized with a closure that has no parameters.

> If the lambda is rendered as a variable and you supply a closure that accepts a `String` then the supplied `String` is empty.

Below we have a couple of examples of rendering mustache lambdas as variables. One returning a tuple and one returning a `String` which is then parsed as a template. If we have the following object
The examples below are a couple of examples of rendering mustache lambdas as variables.

The first lambda in the example returns a tuple, and the second returns a `String` which is parsed as a template.
```swift
let object: [String: Any] = [
"year": 1970,
Expand All @@ -36,33 +39,34 @@ let object: [String: Any] = [
},
]
```
and the following mustache template
With the object defined above, and the following mustache template:
```swift
let mustache = """
* {{time.hour}}
* {{today}}
"""
let template = try MustacheTemplate(string: mustache)
```
then `template.render(object)` will output

Invoking `template.render(object)` outputs:
```
* 0
* 1970-1-1
```

In this example the first part of the template calls lambda `time` and then uses `hour` from the return object. In the second part the `today` lambda returns a string which is then parsed as mustache and renders the year.
The first part of the template calls the lambda `time` and then uses `hour` from the return object. In the second part the `today` lambda returns a string which is then parsed as a mustache template and renders the year.

### Rendering sections

The mustache manual section for mustache lambdas when rendered as a section states.
The mustache manual section for rendering lambdas as a section states:

> Manual: When any value found during the lookup is a callable object, such as a function or lambda, the object will be invoked and passed the block of text. The text passed is the literal block, unrendered. {{tags}} will not have been expanded.
>
> An optional part of the specification states that if the final key in the name is a lambda that returns a string, then that string replaces the content of the section. It will be rendered using the same delimiters as the original section content. In this way you can implement filters or caching.

Swift Mustache does not support the part of the specification of lambdas when rendered as sections pertaining to delimiters. As with variables, instead of a callable object, swift-mustache requires the type to be a `MustacheLambda` which can be initialized with either a closure that accepts a String or nothing. When the lambda is rendered as a section the supplied `String` is the contents of the section.

If we have an object as follows
The example below includes a lambda that returns a string:
```swift
let object: [String: Any] = [
"name": "Willy",
Expand All @@ -71,31 +75,60 @@ let object: [String: Any] = [
}
]
```
and the following mustache template
With the object in the example above, and the following uses that lambda to render as a section:
```swift
let mustache = "{{#wrapped}}{{name}} is awesome.{{/wrapped}}"
let template = try MustacheTemplate(string: mustache)
```
Then `template.render(object)` will output

Calling `template.render(object)` outputs:
```
<b>Willy is awesome.</b>
```

Here when the `wrapped` section is rendered the text inside the section is passed to the `wrapped` lambda and the resulting text passed back is parsed as a new template.
When mustache renders the `wrapped` section, the text inside the section is passed to the `wrapped` lambda. The example parses the returned text as a new template.

## Partial templates

Partial templates let you embed one template inside another.
A partial inherits the context of the template it's embedded within.
Reference a partial template by its name, prefixed with `>`.

For example, given the partial template `included.mustache`:
```
{{! included.mustache }}
Hello world
```

To include this tempalte in another, reference the tag as:
```
{{> included}}
```

> Note: partials and templates using inheritance require that you provide the included templates using a library.

## Template inheritance and parents

Template inheritance allows you to override elements of an included partial. It allows you to create a base page template, or parent as it is called in the mustache manual, and override elements of it with your page content. A parent that includes overriding elements is indicated with a `{{<parent}}`. Note this is different from the normal partial reference which uses `>`. This is a section tag so needs a ending tag as well. Inside the section the tagged sections to override are added using the syntax `{{$tag}}contents{{/tag}}`.
Template inheritance allows you to override elements of an included partial. It allows you to create a base page template, or parent as it is called in the mustache manual, and override elements of it with your page content.

A parent that includes overriding elements is indicated with a `<`.
For example, the tag `{{<parent}}` references a template named `parent` that has elements you override.
The template reference is a section tag, and requires an ending tag: `{{/parent}}`.
This is different from the included partial reference, which uses `>`.

Inside the section, override tagged sections using a start and stop for the section.
The start is prefixed with `$`, and the end with `/`. For example: `{{$tag}}contents{{/tag}}`.

If your template is as follows
For the example template `mypage.mustache`:
```
{{! mypage.mustache }}
{{<base}}
{{$head}}<title>My page title</title>{{/head}}
{{$body}}Hello world{{/body}}
{{/base}}
```
And you partial is as follows

With an example partial `base.mustache`:
```
{{! base.mustache }}
<html>
Expand All @@ -107,7 +140,8 @@ And you partial is as follows
</body>
</html>
```
You would get the following output when rendering `mypage.mustache`.

Mustache renders `mypage.mustache`:
```
<html>
<head>
Expand All @@ -117,78 +151,84 @@ You would get the following output when rendering `mypage.mustache`.
Hello world
</body>
```
Note the `{{$head}}` section in `base.mustache` is replaced with the `{{$head}}` section included inside the `{{<base}}` partial reference from `mypage.mustache`. The same occurs with the `{{$body}}` section. In that case though a default value is supplied for the situation where a `{{$body}}` section is not supplied.

Mustache replaces the `{{$head}}` section in `base.mustache` with the `{{$head}}` section included inside the `{{<base}}` partial reference from `mypage.mustache`.
The same occurs with the `{{$body}}` section.

If a section isn't defined in the template that inherits another, the default value from the template is displayed.
For example, if the section `{{$body}}Hello world{{/body}}` isn't included in the `mypage.mustache` example, mustache renders the value `Default text` from the template.

## Pragmas/Configuration variables

The syntax `{{% var: value}}` can be used to set template rendering configuration variables specific to Hummingbird Mustache. The only variable you can set at the moment is `CONTENT_TYPE`. This can be set to either to `HTML` or `TEXT` and defines how variables are escaped. A content type of `TEXT` means no variables are escaped and a content type of `HTML` will do HTML escaping of the rendered text. The content type defaults to `HTML`.
The syntax `{{% var: value}}` can be used to set template rendering configuration variables specific to Swift-Mustache. The only variable you can set at the moment is `CONTENT_TYPE`. This can be set to either to `HTML` or `TEXT`, and defines how variables are escaped. A content type of `TEXT` means no variables are escaped and a content type of `HTML` will do HTML escaping of the rendered text. The content type defaults to `HTML`.

Given input object `<>`, template
Given input object `<>`, template:
```
{{%CONTENT_TYPE: HTML}}{{.}}
```
will render as `&lt;&gt;` and
renders as `&lt;&gt;` and

```
{{%CONTENT_TYPE: TEXT}}{{.}}
```
will render as `<>`.
renders as `<>`.

## Transforms

Transforms are specific to this implementation of Mustache. They are similar to Lambdas but instead of generating rendered text they allow you to transform an object into another. Transforms are formatted as a function call inside a tag eg
Transforms are specific to this implementation of Mustache. They are similar to Lambdas but instead of generating rendered text, they allow you to transform one object into another. Transforms are formatted as a function call inside a tag, for example:
```
{{uppercase(string)}}
```
They can be applied to variable, section and inverted section tags. If you apply them to a section or inverted section tag the transform name should be included in the end section tag as well eg
They can be applied to variable, section, and inverted section tags. If you apply them to a section tag or an inverted section tag, include the transform name in the end section tag as well. For example:
```
{{#sorted(array)}}{{.}}{{/sorted(array)}}
```
The library comes with a series of transforms for the Swift standard objects.
The library comes with a series of transforms for several standard Swift objects.
- String/Substring
- capitalized: Return string with first letter capitalized
- lowercase: Return lowercased version of string
- uppercase: Return uppercased version of string
- reversed: Reverse string
- capitalized: Returns string with first letter capitalized.
- lowercase: Returns lowercased version of string.
- uppercase: Returns uppercased version of string.
- reversed: Returns a reversed string.
- Int/UInt/Int8/Int16...
- equalzero: Returns if equal to zero
- plusone: Add one to integer
- minusone: Subtract one from integer
- odd: return if integer is odd
- even: return if integer is even
- equalzero: Returns if equal to zero.
- plusone: Add one to an integer.
- minusone: Subtract one from an integer.
- odd: Returns if integer is odd.
- even: Returns if integer is even.
- Array
- first: Return first element of array
- last: Return last element of array
- count: Return number of elements in array
- empty: Returns if array is empty
- reversed: Reverse array
- sorted: If the elements of the array are comparable sort them
- first: Returns first element of an array.
- last: Returns last element of an array.
- count: Returns number of elements in an array.
- empty: Returns if the array is empty.
- reversed: Returns the reversed array.
- sorted: If the elements of the array are comparable, returns the sorted array.
- Dictionary
- count: Return number of elements in dictionary
- empty: Returns if dictionary is empty
- enumerated: Return dictionary as array of key, value pairs
- sorted: If the keys are comparable return as array of key, value pairs sorted by key
- count: Returns number of elements in a dictionary.
- empty: Returns if the dictionary is empty.
- enumerated: Returns the dictionary as an array of (key, value) pairs.
- sorted: If the keys are comparable, returns an array of (key, value) pairs sorted by the key.

If a transform is applied to an object that doesn't recognise it then `nil` is returned.
If a transform is applied to an object that doesn't recognise it, it returns `nil`.

### Sequence context transforms

Sequence context transforms are transforms applied to the current position in the sequence. They are formatted as a function that takes no parameter eg
Sequence context transforms are transforms applied to the current position in the sequence. They are formatted as a function that takes no parameter. For example:
```
{{#array}}{{.}}{{^last()}}, {{/last()}}{{/array}}
```
This will render an array as a comma separated list. The inverted section of the `last()` transform ensures we don't add a comma after the last element.
This example renders an array as a comma separated list.
The inverted section of the `last()` transform ensures it doesn't add a comma after the last element.

The following sequence context transforms are available
- first: Is this the first element of the sequence
- last: Is this the last element of the sequence
- index: Returns the index of the element within the sequence
- odd: Returns if the index of the element is odd
- even: Returns if the index of the element is even
The following sequence context transforms are available:
- first: Returns if the element the first element of the sequence.
- last: Returns if the element the last element of the sequence.
- index: Returns the index of the element within the sequence.
- odd: Returns if the index of the element is odd.
- even: Returns if the index of the element is even.

### Custom transforms

You can add transforms to your own objects. Conform the object to `MustacheTransformable` and provide an implementation of the function `transform`. eg
You can add transforms to your own objects. Conform your object to `MustacheTransformable` and provide an implementation of the function `transform`. For example:
```swift
struct Object: MustacheTransformable {
let either: Bool
Expand All @@ -205,11 +245,11 @@ struct Object: MustacheTransformable {
}
}
```
When we render an instance of this object with `either` or `or` set to true using the following template it will render "Success".
When mustache renders an instance of this object with `either` or `or` set to true, the following template renders "Success".
```
{{#eitherOr(object)}}Success{{/eitherOr(object)}}
```
With this we have got around the fact it is not possible to do logical OR statements in Mustache.
This example illustrates an equivalent of a logical OR statement, which are not possible in the mustache specification.

## See Also

Expand Down
Loading