Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/gobuffalo/velvet

A sweet velvety templating package
https://github.com/gobuffalo/velvet

go golang handlebars template template-engine

Last synced: 3 months ago
JSON representation

A sweet velvety templating package

Lists

README

        

# Velvet [![GoDoc](https://godoc.org/github.com/gobuffalo/velvet?status.svg)](https://godoc.org/github.com/gobuffalo/velvet) [![Build Status](https://travis-ci.org/gobuffalo/velvet.svg?branch=master)](https://travis-ci.org/gobuffalo/velvet) [![Code Climate](https://codeclimate.com/github/gobuffalo/velvet/badges/gpa.svg)](https://codeclimate.com/github/gobuffalo/velvet)

Velvet is a templating package for Go. It bears a striking resemblance to "handlebars" based templates, there are a few small changes/tweaks, that make it slightly different.

## General Usage

If you know handlebars, you basically know how to use Velvet.

Let's assume you have a template (a string of some kind):

```handlebars

{{ name }}



    {{#each names}}
  • {{ @value }}

  • {{/each}}

```

Given that string, you can render the template like such:

```go
ctx := velvet.NewContext()
ctx.Set("name", "Mark")
ctx.Set("names", []string{"John", "Paul", "George", "Ringo"})
s, err := velvet.Render(input, ctx)
if err != nil {
// handle errors
}
```
Which would result in the following output:

```html

Mark



  • John

  • Paul

  • George

  • Ringo


```

## Helpers

### If Statements

What to do? Should you render the content, or not? Using Velvet's built in `if`, `else`, and `unless` helpers, let you figure it out for yourself.

```handlebars
{{#if true }}
render this
{{/if}}
```

#### Else Statements

```handlebars
{{#if false }}
won't render this
{{ else }}
render this
{{/if}}
```

#### Unless Statements

```handlebars
{{#unless true }}
won't render this
{{/unless}}
```

### Each Statements

Into everyone's life a little looping must happen. We can't avoid the need to write loops in applications, so Velvet helps you out by coming loaded with an `each` helper to iterate through `arrays`, `slices`, and `maps`.

#### Arrays

When looping through `arrays` or `slices`, the block being looped through will be access to the "global" context, as well as have four new variables available within that block:

* `@first` [`bool`] - is this the first pass through the iteration?
* `@last` [`bool`] - is this the last pass through the iteration?
* `@index` [`int`] - the counter of where in the loop you are, starting with `0`.
* `@value` - the current element in the array or slice that is being iterated over.

```handlebars


    {{#each names}}
  • {{ @index }} - {{ @value }}

  • {{/each}}

```

By using "block parameters" you can change the "key" of the element being accessed from `@value` to a key of your choosing.

```handlebars


    {{#each names as |name|}}
  • {{ name }}

  • {{/each}}

```

To change both the key and the index name you can pass two "block parameters"; the first being the new name for the index and the second being the name for the element.

```handlebars


    {{#each names as |index, name|}}
  • {{ index }} - {{ name }}

  • {{/each}}

```

#### Maps

Looping through `maps` using the `each` helper is also supported, and follows very similar guidelines to looping through `arrays`.

* `@first` [`bool`] - is this the first pass through the iteration?
* `@last` [`bool`] - is this the last pass through the iteration?
* `@key` - the key of the pair being accessed.
* `@value` - the value of the pair being accessed.

```handlebars


    {{#each users}}
  • {{ @key }} - {{ @value }}

  • {{/each}}

```

By using "block parameters" you can change the "key" of the element being accessed from `@value` to a key of your choosing.

```handlebars


    {{#each users as |user|}}
  • {{ @key }} - {{ user }}

  • {{/each}}

```

To change both the key and the value name you can pass two "block parameters"; the first being the new name for the key and the second being the name for the value.

```handlebars


    {{#each users as |key, user|}}
  • {{ key }} - {{ user }}

  • {{/each}}

```

### Other Builtin Helpers

* `json` - returns a JSON marshaled string of the value passed to it.
* `js_escape` - safely escapes a string to be used in a JavaScript bit of code.
* `html_escape` - safely escapes a string to be used in an HTML bit of code.
* `upcase` - upper cases the entire string passed to it.
* `downcase` - lower cases the entire string passed to it.
* `markdown` - converts markdown to HTML.
* `len` - returns the length of an array or slice

Velvet also imports all of the helpers found [https://github.com/markbates/inflect/blob/master/helpers.go](https://github.com/markbates/inflect/blob/master/helpers.go)

## Custom Helpers

No templating package would be complete without allowing for you to build your own, custom, helper functions.

### Return Values

The first thing to understand about building custom helper functions is their are a few "valid" return values:

#### `string`

Return just a `string`. The `string` will be HTML escaped, and deemed "not"-safe.

```go
func() string {
return ""
}
```

#### `string, error`

Return a `string` and an error. The `string` will be HTML escaped, and deemed "not"-safe.

```go
func() (string, error) {
return "", nil
}
```

#### `template.HTML`

[https://golang.org/pkg/html/template/#HTML](https://golang.org/pkg/html/https://golang.org/pkg/html/template/#HTMLlate/#HTML)

Return a `template.HTML` string. The `template.HTML` will **not** be HTML escaped, and will be deemed safe.

```go
func() template.HTML {
return template.HTML("")
}
```

#### `template.HTML, error`

Return a `template.HTML` string and an error. The `template.HTML` will **not** be HTML escaped, and will be deemed safe.

```go
func() ( template.HTML, error ) {
return template.HTML(""), error
}
```

### Input Values

Custom helper functions can take any type, and any number of arguments. There is an option last argument, [`velvet.HelperContext`](https://godoc.org/github.com/gobuffalo/velvet#HelperContext), that can be received. It's quite useful, and I would recommend taking it, as it provides you access to things like the context of the call, the block associated with the helper, etc...

### Registering Helpers

Custom helpers can be registered in one of two different places; globally and per template.

#### Global Helpers

```go
err := velvet.Helpers.Add("greet", func(name string) string {
return fmt.Sprintf("Hi %s!", name)
})
if err != nil {
// handle errors
}
```

The `greet` function is now available to all templates that use Velvet.

```go
s, err := velvet.Render(`

{{greet "mark"}}

`, velvet.NewContext())
if err != nil {
// handle errors
}
fmt.Print(s) //

Hi mark!


```

#### Per Template Helpers

```go
t, err := velvet.Parse(`

{{greet "mark"}}

`)
if err != nil {
// handle errors
}
t.Helpers.Add("greet", func(name string) string {
return fmt.Sprintf("Hi %s!", name)
})
if err != nil {
// handle errors
}
```

The `greet` function is now only available to the template it was added to.

```go
s, err := t.Exec(velvet.NewContext())
if err != nil {
// handle errors
}
fmt.Print(s) //

Hi mark!


```

### Block Helpers

Like the `if` and `each` helpers, block helpers take a "block" of text that can be evaluated and potentially rendered, manipulated, or whatever you would like. To write a block helper, you have to take the `velvet.HelperContext` as the last argument to your helper function. This will give you access to the block associated with that call.

#### Example

```go
velvet.Helpers.Add("upblock", func(help velvet.HelperContext) (template.HTML, error) {
s, err := help.Block()
if err != nil {
return "", err
}
return strings.ToUpper(s), nil
})

s, err := velvet.Render(`{{#upblock}}hi{{/upblock}}`, velvet.NewContext())
if err != nil {
// handle errors
}
fmt.Print(s) // HI
```