Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to treat missing variables as errors #53

Open
wants to merge 123 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
f9b4cbf
Return errors to caller as errors, not strings
Jul 22, 2015
91d6951
Switch from Fatal to Error
Jul 22, 2015
0fd4262
Make sure errors are always bubbled up
Jul 22, 2015
cffa282
Add option to treat missing variables as errors
Jul 22, 2015
ee3f06a
Add explanation about fork changes
cbroglie Jul 22, 2015
52efb87
Delete unused make file
Jul 22, 2015
04e40ac
Update examples to this fork
cbroglie Oct 3, 2015
5b736f9
Allow missing variables in section checks
Oct 27, 2015
dffd9f0
Add test demonstrating behavior of method receivers
Feb 13, 2016
48eb547
Update README for function signature changes
cbroglie Feb 19, 2016
dbed877
Fix golint warnings
Feb 19, 2016
5ca748e
Add Travis CI integration
Feb 19, 2016
53e0acb
Rename README file
Feb 19, 2016
18a32b1
Add Travis CI build status badge
cbroglie Feb 19, 2016
726b5f7
Delete unused code
Feb 28, 2016
e00ffc7
Add support for examining the parsed tags
Feb 29, 2016
19fb7bf
Merge pull request #4 from cbroglie/extract-tags
cbroglie Feb 29, 2016
8c0c2fe
Integrate the mustache spec tests
Mar 21, 2016
260d97b
Fix syntax highlighting in README
cbroglie Mar 21, 2016
cd74d13
Remove golint step from Travis CI build
Mar 21, 2016
f499c19
fix(isEmpty): Ignore empty strings on list iteration.
themihai Jun 7, 2016
74a96fe
Merge pull request #7 from epek/master
cbroglie Jun 29, 2016
214307b
Add test to validate behavior on falsy sections
Jun 29, 2016
bbddb45
Support rendering directly to an io.Writer
danielwhite Jul 6, 2016
d8db48b
Add FRenderInLayout for parity with FRender
danielwhite Jul 9, 2016
422aa0d
Merge pull request #8 from danielwhite/direct-writer-rendering
cbroglie Jul 11, 2016
685ab1a
Non-file partial handling
Sep 28, 2016
7a8cf7d
Partial handling via file *or* a static provider (or any implementer …
Sep 28, 2016
bcd5dfe
Use only public members
Sep 28, 2016
8575e86
Enable one more test
Sep 28, 2016
b0c50b2
Add partials version of RenderInLayout
Sep 28, 2016
dfa7243
Handle (and make use of) nil Paths and Extensions slices
Sep 28, 2016
1cd6a4f
Document the PartialProvider stuff
Sep 28, 2016
cd3cb8b
Clean up multi-return err handling
Oct 20, 2016
cc1a441
Fix godoc for new Partials functions
Oct 20, 2016
23b3dcf
Restore & fix compareTags test for partials
Oct 20, 2016
a201511
Change StaticProvider to struct; add godoc
Oct 20, 2016
42355e6
Go fmt
Oct 20, 2016
6857e4b
Merge pull request #11 from pdbogen/master
cbroglie Oct 20, 2016
fd5c990
forceRaw option to disable HTML escaping.
Oct 18, 2017
ab2a86f
Fix regression.
Oct 25, 2017
753f22d
Merge pull request #14 from udhos/master
cbroglie Oct 25, 2017
4b76837
Add detection that the tag is standalone or not
kei10in Oct 31, 2017
5531882
Enable tests about standalone line
kei10in Nov 2, 2017
6adb117
Merge pull request #15 from kei10in/master
cbroglie Nov 14, 2017
859074c
Update README.md
cbroglie Nov 14, 2017
7330840
Use default partial provider instead of dirname
kei10in Nov 20, 2017
57a3466
Change return type of PartialProvider.Get
kei10in Nov 21, 2017
dfeb856
Implement partial template indentation
kei10in Nov 21, 2017
035110b
Enable tests now pass
kei10in Nov 21, 2017
a40b16f
Merge pull request #17 from kei10in/indent-partials
cbroglie Nov 24, 2017
c758762
Update README.md
cbroglie Nov 27, 2017
42a25e9
Support ampersand
kei10in Nov 27, 2017
1632570
Remove padding arround triple mustache
kei10in Nov 27, 2017
84c99c9
Enable test now pass
kei10in Nov 27, 2017
cd8d6fc
Merge pull request #18 from kei10in/support-some-interpolation-specs
cbroglie Nov 28, 2017
9796b5b
Update README now that all tests are passing
cbroglie Nov 28, 2017
6b01858
Update README.md
cbroglie Nov 28, 2017
bab85ea
Add CLI wrapper
cbroglie Jan 22, 2018
96133d6
Fix CI build
cbroglie Jan 22, 2018
47d92c5
Vendor dependencies using dep
cbroglie Jan 22, 2018
de38813
Revert "Fix CI build"
cbroglie Jan 22, 2018
7628120
Update Travis CI supported versions
cbroglie Jan 22, 2018
2eb1712
Update README.md
cbroglie Jan 22, 2018
57bb519
Integrate go releaser for automated binary generation. Fixes #20
kishaningithub May 8, 2018
18252c8
Fix lint errors in README.md
kishaningithub May 8, 2018
8962e6c
Merge pull request #26 from kishaningithub/go_releaser_integration
cbroglie May 8, 2018
830bbda
Add Go Doc, Go Report Card, No of downloads and Latest Release badge
kishaningithub May 8, 2018
5b5576f
Add code coverage report
kishaningithub May 8, 2018
901cc8d
Upgrade go version from 1.9 to 1.10
kishaningithub May 9, 2018
eb931a9
Merge pull request #27 from kishaningithub/readme_badges
cbroglie May 10, 2018
ec3fca6
correct installation instructions
ags799 May 25, 2018
d1db521
Merge pull request #29 from ags799/patch-1
cbroglie May 25, 2018
9dd9d9c
fix installation instructions (again)
ags799 May 25, 2018
73b1f39
Merge pull request #30 from ags799/patch-1
cbroglie May 26, 2018
6328bef
fix(isEmpty): treat golang zero values as falsy
Dec 18, 2019
c219793
Merge pull request #33 from flisky/master
cbroglie Dec 23, 2019
dffa93e
Fix filename
cbroglie May 8, 2018
f84b224
Go 1.13 is required for reflect.Value.IsZero
cbroglie Dec 23, 2019
9c31b21
Migrate to Go modules
cbroglie Dec 23, 2019
f164316
Merge pull request #34 from cbroglie/cbroglie/modules
cbroglie Dec 23, 2019
751ce30
Add logo to readme
cbroglie Feb 19, 2020
7b1d416
Merge pull request #38 from cbroglie/logo
cbroglie Feb 19, 2020
e039f8c
Support missing variables at any depth
iwamot Apr 25, 2020
c6bae88
Merge pull request #39 from iwamot/deepmissing
cbroglie May 12, 2020
d53aad3
add layout feature
jmadler May 28, 2020
0fd54a4
Add support for override data yaml maps
jmadler May 28, 2020
04f3ba6
Merge pull request #43 from jmadler/master
cbroglie Jun 4, 2020
c7bf765
document new features
jmadler Jun 4, 2020
40ff356
Merge pull request #44 from jmadler/master
cbroglie Jun 4, 2020
e9ee1d7
Fix typo in help text
cbroglie Jul 13, 2020
8658597
Migrate to golangci-lint
cbroglie Jul 13, 2020
2ebfd28
Merge pull request #47 from cbroglie/golangci-lint
cbroglie Jul 13, 2020
4f2dfd2
sections: Fix building context stack for inner elements of sections. …
roblillack Jun 7, 2021
d22c883
Fix rendering non-false value sections.
roblillack Jun 8, 2021
f01d98a
Merge pull request #54 from roblillack/cbroglie-53-fix-context-stacks…
cbroglie Jun 9, 2021
1e9f7de
Update mustache/spec submodule to latest
cbroglie Jun 9, 2021
c5eea54
Merge pull request #56 from cbroglie/update-spec
cbroglie Jun 9, 2021
e25d805
Merge remote-tracking branch 'upstream/master' into fix-rendering-non…
roblillack Jun 10, 2021
10eb828
Enable formerly skipped spec tests for sections
roblillack Jun 10, 2021
1fb86e2
Merge pull request #55 from roblillack/fix-rendering-non-false-value-…
cbroglie Jun 10, 2021
ea8abd9
Update README to reflect spec version v1.2.1
cbroglie Jun 10, 2021
1d34a93
Migrate to github actions and un-vendor golangci-lint.
xakep666 Jul 7, 2021
1e82fde
mustache: expose missing variable control
Aug 26, 2021
027013f
Merge pull request #63 from mattalberts/mattalberts/cmd-flag-allow-mi…
cbroglie Aug 26, 2021
b3e5b6d
Merge pull request #59 from xakep666/github-actions
cbroglie Sep 20, 2021
2dffa0e
Update Golang and packages to latest versions
cbroglie Sep 20, 2021
b2d8af2
Merge pull request #66 from cbroglie/upgrade
cbroglie Sep 20, 2021
08d1d98
Experimental support for lambda sections
frohmut May 10, 2018
444b549
Merge pull request #67 from cbroglie/lambda
cbroglie Sep 20, 2021
d6701a6
fix: README manual page broken link
jornh Dec 7, 2021
f268266
Update installation instructions
cbroglie Jan 11, 2022
42f9fad
Update dependencies, remove vendor folder
cbroglie Jan 11, 2022
807cf85
Update goreleaser to not expect vendor folder
cbroglie Jan 11, 2022
803afaf
Upgrade to latest versions Github Actions
cbroglie Jun 16, 2022
3fabeb4
release arm64
jsoizo May 31, 2022
c1e7de1
Improve Error system (#70)
gsempe Jul 12, 2022
5229524
Support raw tags in lambda.
fuktommy Jul 11, 2022
6017cf8
Print errors to stderr
amarshall Jul 29, 2022
c0cf5d2
updates installation instructions in CLI Overview
Oct 4, 2022
c72b272
add option to customize escape function
reddec May 30, 2023
2926dd6
Update dependencies
cbroglie Jun 2, 2023
d50b8fb
fix typo in RenderFile docs
vieiralucas Aug 30, 2023
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
27 changes: 27 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Release

on:
push:
tags:
- '*'

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: true

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.20.4

- name: GoReleaser
uses: goreleaser/goreleaser-action@v4
with:
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28 changes: 28 additions & 0 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Go Test

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.20.4

- name: Test
run: make test

- name: Upload results to codecov
uses: codecov/codecov-action@v3
with:
verbose: true
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ _obj
_test
_testmain.go
*.swp
coverage.txt
/bin
/dist
/vendor
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "spec"]
path = spec
url = https://github.com/mustache/spec.git
13 changes: 13 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
env:
- GO111MODULE=on
- CGO_ENABLED=0
builds:
- main: ./cmd/mustache
binary: mustache
goos:
- windows
- darwin
- linux
goarch:
- amd64
- arm64
27 changes: 21 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
.PHONY: all
all: bin/mustache

GOFMT=gofmt -s -tabs=false -tabwidth=4
.PHONY: clean
clean:
rm -rf bin

GOFILES=\
mustache.go\
.PHONY: test
test:
go test -race -coverprofile=coverage.txt -covermode=atomic ./...

format:
${GOFMT} -w ${GOFILES}
${GOFMT} -w mustache_test.go
.PHONY: fmt
fmt:
go fmt ./...

.PHONY: lint
lint:
golangci-lint run ./...

SOURCES := $(shell find . -name '*.go')
BUILD_FLAGS ?= -v
LDFLAGS ?= -w -s

bin/%: $(SOURCES)
CGO_ENABLED=0 go build -o $@ $(BUILD_FLAGS) -ldflags "$(LDFLAGS)" ./cmd/$(@F)
233 changes: 233 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
# Mustache Template Engine for Go

[![Build Status](https://img.shields.io/travis/cbroglie/mustache.svg)](https://travis-ci.org/cbroglie/mustache)
[![Go Doc](https://godoc.org/github.com/cbroglie/mustache?status.svg)](https://godoc.org/github.com/cbroglie/mustache)
[![Go Report Card](https://goreportcard.com/badge/github.com/cbroglie/mustache)](https://goreportcard.com/report/github.com/cbroglie/mustache)
[![codecov](https://codecov.io/gh/cbroglie/mustache/branch/master/graph/badge.svg)](https://codecov.io/gh/cbroglie/mustache)
[![Downloads](https://img.shields.io/github/downloads/cbroglie/mustache/latest/total.svg)](https://github.com/cbroglie/mustache/releases)
[![Latest release](https://img.shields.io/github/release/cbroglie/mustache.svg)](https://github.com/cbroglie/mustache/releases)


<img src="./images/logo.jpeg" alt="logo" width="100"/>

----

## Why a Fork?

I forked [hoisie/mustache](https://github.com/hoisie/mustache) because it does not appear to be maintained, and I wanted to add the following functionality:

- Update the API to follow the idiomatic Go convention of returning errors (this is a breaking change)
- Add option to treat missing variables as errors

----

## CLI Overview

```bash
➜ ~ go install github.com/cbroglie/mustache/cmd/mustache@latest
➜ ~ mustache
Usage:
mustache [data] template [flags]

Examples:
$ mustache data.yml template.mustache
$ cat data.yml | mustache template.mustache
$ mustache --layout wrapper.mustache data template.mustache
$ mustache --overide over.yml data.yml template.mustache

Flags:
-h, --help help for mustache
--layout a file to use as the layout template
--override a data.yml file whose definitions supercede data.yml
➜ ~
```

----

## Package Overview

This library is an implementation of the Mustache template language in Go.

### Mustache Spec Compliance

[mustache/spec](https://github.com/mustache/spec) contains the formal standard for Mustache, and it is included as a submodule (using v1.2.1) for testing compliance. All of the tests pass (big thanks to [kei10in](https://github.com/kei10in)), with the exception of the null interpolation tests added in v1.2.1. There is experimental support for a subset of the optional lambda functionality (thanks to [fromhut](https://github.com/fromhut)). The optional inheritance functionality has not been implemented.

----

## Documentation

For more information about mustache, check out the [mustache project page](https://github.com/mustache/mustache) or the [mustache manual](https://mustache.github.io/mustache.5.html).

Also check out some [example mustache files](http://github.com/mustache/mustache/tree/master/examples/).

----

## Installation

To install the CLI, run `go install github.com/cbroglie/mustache/cmd/mustache@latest`. To use it in a program, run `go get github.com/cbroglie/mustache` and use `import "github.com/cbroglie/mustache"`.

----

## Usage

There are four main methods in this package:

```go
Render(data string, context ...interface{}) (string, error)

RenderFile(filename string, context ...interface{}) (string, error)

ParseString(data string) (*Template, error)

ParseFile(filename string) (*Template, error)
```

There are also two additional methods for using layouts (explained below); as well as several more that can provide a custom Partial retrieval.

The Render method takes a string and a data source, which is generally a map or struct, and returns the output string. If the template file contains an error, the return value is a description of the error. There's a similar method, RenderFile, which takes a filename as an argument and uses that for the template contents.

```go
data, err := mustache.Render("hello {{c}}", map[string]string{"c": "world"})
```

If you're planning to render the same template multiple times, you do it efficiently by compiling the template first:

```go
tmpl, _ := mustache.ParseString("hello {{c}}")
var buf bytes.Buffer
for i := 0; i < 10; i++ {
tmpl.FRender(&buf, map[string]string{"c": "world"})
}
```

For more example usage, please see `mustache_test.go`

----

## Escaping

mustache.go follows the official mustache HTML escaping rules. That is, if you enclose a variable with two curly brackets, `{{var}}`, the contents are HTML-escaped. For instance, strings like `5 > 2` are converted to `5 &gt; 2`. To use raw characters, use three curly brackets `{{{var}}}`.

----

## Layouts

It is a common pattern to include a template file as a "wrapper" for other templates. The wrapper may include a header and a footer, for instance. Mustache.go supports this pattern with the following two methods:

```go
RenderInLayout(data string, layout string, context ...interface{}) (string, error)

RenderFileInLayout(filename string, layoutFile string, context ...interface{}) (string, error)
```

The layout file must have a variable called `{{content}}`. For example, given the following files:

layout.html.mustache:

```html
<html>
<head><title>Hi</title></head>
<body>
{{{content}}}
</body>
</html>
```

template.html.mustache:

```html
<h1>Hello World!</h1>
```

A call to `RenderFileInLayout("template.html.mustache", "layout.html.mustache", nil)` will produce:

```html
<html>
<head><title>Hi</title></head>
<body>
<h1>Hello World!</h1>
</body>
</html>
```

----

## Custom PartialProvider

Mustache.go has been extended to support a user-defined repository for mustache partials, instead of the default of requiring file-based templates.

Several new top-level functions have been introduced to take advantage of this:

```go

func RenderPartials(data string, partials PartialProvider, context ...interface{}) (string, error)

func RenderInLayoutPartials(data string, layoutData string, partials PartialProvider, context ...interface{}) (string, error)

func ParseStringPartials(data string, partials PartialProvider) (*Template, error)

func ParseFilePartials(filename string, partials PartialProvider) (*Template, error)

```

A `PartialProvider` is any object that responds to `Get(string)
(*Template,error)`, and two examples are provided- a `FileProvider` that
recreates the old behavior (and is indeed used internally for backwards
compatibility); and a `StaticProvider` alias for a `map[string]string`. Using
either of these is simple:

```go

fp := &FileProvider{
Paths: []string{ "", "/opt/mustache", "templates/" },
Extensions: []string{ "", ".stache", ".mustache" },
}

tmpl, err := ParseStringPartials("This partial is loaded from a file: {{>foo}}", fp)

sp := StaticProvider(map[string]string{
"foo": "{{>bar}}",
"bar": "some data",
})

tmpl, err := ParseStringPartials("This partial is loaded from a map: {{>foo}}", sp)
```

----

## A note about method receivers

Mustache.go supports calling methods on objects, but you have to be aware of Go's limitations. For example, lets's say you have the following type:

```go
type Person struct {
FirstName string
LastName string
}

func (p *Person) Name1() string {
return p.FirstName + " " + p.LastName
}

func (p Person) Name2() string {
return p.FirstName + " " + p.LastName
}
```

While they appear to be identical methods, `Name1` has a pointer receiver, and `Name2` has a value receiver. Objects of type `Person`(non-pointer) can only access `Name2`, while objects of type `*Person`(person) can access both. This is by design in the Go language.

So if you write the following:

```go
mustache.Render("{{Name1}}", Person{"John", "Smith"})
```

It'll be blank. You either have to use `&Person{"John", "Smith"}`, or call `Name2`

## Supported features

- Variables
- Comments
- Change delimiter
- Sections (boolean, enumerable, and inverted)
- Partials
Loading