Skip to content

Commit

Permalink
Merge pull request #13 from Fenny/master
Browse files Browse the repository at this point in the history
Add support for embedded file systems
  • Loading branch information
Fenny authored Jun 14, 2020
2 parents 1ee351d + e3dcdbc commit 3f9522a
Show file tree
Hide file tree
Showing 35 changed files with 988 additions and 105 deletions.
102 changes: 101 additions & 1 deletion .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</a>
</p>

This package provides universal methods to use multiple template engines with the [Fiber web framework](https://github.com/gofiber/fiber) using the new [Views](https://godoc.org/github.com/gofiber/fiber#Views) interface that is available from `> v1.11.1`. Special thanks to @bdtomlin for helping!
This package provides universal methods to use multiple template engines with the [Fiber web framework](https://github.com/gofiber/fiber) using the new [Views](https://godoc.org/github.com/gofiber/fiber#Views) interface that is available from `> v1.11.1`. Special thanks to @bdtomlin & @arsmn for helping!

8 template engines are supported:
- [html](https://github.com/gofiber/template/tree/master/html)
Expand Down Expand Up @@ -113,3 +113,103 @@ To view more specific examples, you could visit each engine folder to learn more
- [jet](https://github.com/gofiber/template/tree/master/jet)
- [mustache](https://github.com/gofiber/template/tree/master/mustache)
- [pug](https://github.com/gofiber/template/tree/master/pug)


### embedded Systems

We support the `http.FileSystem` interface, so you can use different libraries to load the templates from embedded binaries.

#### pkger
https://github.com/markbates/pkger

```go
package main

import (
"github.com/gofiber/fiber"
"github.com/gofiber/template/html"

"github.com/markbates/pkger"
)

func main() {
engine := html.NewFileSystem(pkger.Dir("/views"), ".html")

app := fiber.New(&fiber.Settings{
Views: engine,
})

// ...
}

```
#### packr
https://github.com/gobuffalo/packr

```go
package main

import (
"github.com/gofiber/fiber"
"github.com/gofiber/template/html"

"github.com/gobuffalo/packr/v2"
)

func main() {
engine := html.NewFileSystem(packr.New("Templates", "/views"), ".html")

app := fiber.New(&fiber.Settings{
Views: engine,
})

// ...
}
```
#### go.rice
https://github.com/GeertJohan/go.rice

```go
package main

import (
"github.com/gofiber/fiber"
"github.com/gofiber/template/html"

"github.com/GeertJohan/go.rice"
)

func main() {
engine := html.NewFileSystem(rice.MustFindBox("views").HTTPBox(), ".html")

app := fiber.New(&fiber.Settings{
Views: engine,
})

// ...
}

```
#### fileb0x
https://github.com/UnnoTed/fileb0x

```go
package main

import (
"github.com/gofiber/fiber"
"github.com/gofiber/template/html"
// your generated package
"github.com/<user>/<repo>/static"
)

func main() {
engine := html.NewFileSystem(static.HTTP, ".html")

app := fiber.New(&fiber.Settings{
Views: engine,
})

// ...
}
```
4 changes: 4 additions & 0 deletions ace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func main() {
// Create a new engine
engine := ace.New("./views", ".ace")

// Or from an embedded system
// See github.com/gofiber/embed for examples
// engine := html.NewFileSystem(http.Dir("./views", ".ace"))

// Pass the engine to the Views
app := fiber.New(&fiber.Settings{
Views: engine,
Expand Down
65 changes: 54 additions & 11 deletions ace/ace.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import (
"fmt"
"html/template"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"sync"

"github.com/gofiber/template/utils"
"github.com/yosssi/ace"
)

Expand All @@ -19,6 +21,8 @@ type Engine struct {
right string
// views folder
directory string
// http.FileSystem supports embedded files
fileSystem http.FileSystem
// views extension
extension string
// layout variable name that incapsulates the template
Expand All @@ -32,7 +36,7 @@ type Engine struct {
// template funcmap
funcmap map[string]interface{}
// templates
Templates map[string]*template.Template
Templates *template.Template
}

// New returns a Ace render engine for Fiber
Expand All @@ -44,7 +48,22 @@ func New(directory, extension string) *Engine {
extension: extension,
layout: "embed",
funcmap: make(map[string]interface{}),
Templates: make(map[string]*template.Template),
}
engine.AddFunc(engine.layout, func() error {
return fmt.Errorf("content called unexpectedly.")
})
return engine
}

func NewFileSystem(fs http.FileSystem, extension string) *Engine {
engine := &Engine{
left: "{{",
right: "}}",
directory: "/",
fileSystem: fs,
extension: extension,
layout: "embed",
funcmap: make(map[string]interface{}),
}
engine.AddFunc(engine.layout, func() error {
return fmt.Errorf("content called unexpectedly.")
Expand Down Expand Up @@ -101,8 +120,13 @@ func (e *Engine) Load() error {
e.mutex.Lock()
defer e.mutex.Unlock()

e.Templates = template.New(e.directory)

e.Templates.Delims(e.left, e.right)
e.Templates.Funcs(e.funcmap)

// Loop trough each directory and register template files
err := filepath.Walk(e.directory, func(path string, info os.FileInfo, err error) error {
walkFn := func(path string, info os.FileInfo, err error) error {
path = strings.TrimRight(path, ".")
// Return error if exist
if err != nil {
Expand All @@ -129,8 +153,21 @@ func (e *Engine) Load() error {
name := filepath.ToSlash(rel)
// Remove ext from name 'index.tmpl' -> 'index'
name = strings.Replace(name, e.extension, "", -1)
// Currently ACE has no partial include support
tmpl, err := ace.Load(strings.Replace(path, e.extension, "", -1), "", &ace.Options{
// Read the file
// #gosec G304
buf, err := utils.ReadFile(path, e.fileSystem)
if err != nil {
return err
}
baseFile := name + ".ace"
base := ace.NewFile(baseFile, buf)
inner := ace.NewFile("", []byte{})
src := ace.NewSource(base, inner, []*ace.File{})
rslt, err := ace.ParseSource(src, nil)
if err != nil {
return err
}
atmpl, err := ace.CompileResult(name, rslt, &ace.Options{
Extension: e.extension[1:],
FuncMap: e.funcmap,
DelimLeft: e.left,
Expand All @@ -139,31 +176,37 @@ func (e *Engine) Load() error {
if err != nil {
return err
}
e.Templates[name] = tmpl
_, err = e.Templates.New(name).Parse(atmpl.Lookup(name).Tree.Root.String())
if err != nil {
return err
}
// Debugging
if e.debug {
fmt.Printf("views: parsed template: %s\n", name)
}
return err
})
return err
}
if e.fileSystem != nil {
return utils.Walk(e.fileSystem, e.directory, walkFn)
}
return filepath.Walk(e.directory, walkFn)
}

// Execute will render the template by name
func (e *Engine) Render(out io.Writer, template string, binding interface{}, layout ...string) error {
// reload the views
if e.reload {
ace.FlushCache()
if err := e.Load(); err != nil {
return err
}
}
tmpl := e.Templates[template]
tmpl := e.Templates.Lookup(template)
if tmpl == nil {
return fmt.Errorf("render: template %s does not exist", template)
}
// TODO: layout does not work
if len(layout) > 0 {
lay := e.Templates[layout[0]]
lay := e.Templates.Lookup(layout[0])
if lay == nil {
return fmt.Errorf("render: layout %s does not exist", layout[0])
}
Expand Down
58 changes: 56 additions & 2 deletions ace/ace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package ace

import (
"bytes"
"io/ioutil"
"net/http"
"regexp"
"strings"
"testing"
Expand All @@ -14,7 +16,7 @@ func trim(str string) string {
return trimmed
}

func Test_Ace_Render(t *testing.T) {
func Test_Render(t *testing.T) {
engine := New("./views", ".ace")
if err := engine.Load(); err != nil {
t.Fatalf("load: %v\n", err)
Expand All @@ -41,7 +43,7 @@ func Test_Ace_Render(t *testing.T) {
}
}

func Test_Ace_Layout(t *testing.T) {
func Test_Layout(t *testing.T) {
engine := New("./views", ".ace")
engine.Debug(true)
if err := engine.Load(); err != nil {
Expand All @@ -61,3 +63,55 @@ func Test_Ace_Layout(t *testing.T) {
t.Fatalf("Expected:\n%s\nResult:\n%s\n", expect, result)
}
}

func Test_FileSystem(t *testing.T) {
engine := NewFileSystem(http.Dir("./views"), ".ace")
engine.Debug(true)
if err := engine.Load(); err != nil {
t.Fatalf("load: %v\n", err)
}

var buf bytes.Buffer
err := engine.Render(&buf, "index", map[string]interface{}{
"Title": "Hello, World!",
}, "layouts/main")
if err != nil {
t.Fatalf("render: %v", err)
}
expect := `<!DOCTYPE html><html><head><title>Main</title></head><body><h2>Header</h2><h1>Hello, World!</h1><h2>Footer</h2></body></html>`
result := trim(buf.String())
if expect != result {
t.Fatalf("Expected:\n%s\nResult:\n%s\n", expect, result)
}
}

func Test_Reload(t *testing.T) {
engine := NewFileSystem(http.Dir("./views"), ".ace")
engine.Reload(true) // Optional. Default: false

engine.AddFunc("isAdmin", func(user string) bool {
return user == "admin"
})
if err := engine.Load(); err != nil {
t.Fatalf("load: %v\n", err)
}

if err := ioutil.WriteFile("./views/reload.ace", []byte("after reload\n"), 0644); err != nil {
t.Fatalf("write file: %v\n", err)
}
defer func() {
if err := ioutil.WriteFile("./views/reload.ace", []byte("before reload\n"), 0644); err != nil {
t.Fatalf("write file: %v\n", err)
}
}()

engine.Load()

var buf bytes.Buffer
engine.Render(&buf, "reload", nil)
expect := "<after>reload</after>"
result := trim(buf.String())
if expect != result {
t.Fatalf("Expected:\n%s\nResult:\n%s\n", expect, result)
}
}
4 changes: 2 additions & 2 deletions ace/views/index.ace
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
= include ./views/partials/header .
= include partials/header .
h1 {{.Title}}
= include ./views/partials/footer .
= include partials/footer .
1 change: 1 addition & 0 deletions ace/views/reload.ace
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
before reload
4 changes: 4 additions & 0 deletions amber/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func main() {
// Create a new engine
engine := amber.New("./views", ".amber")

// Or from an embedded system
// See github.com/gofiber/embed for examples
// engine := html.NewFileSystem(http.Dir("./views", ".amber"))

// Pass the engine to the Views
app := fiber.New(&fiber.Settings{
Views: engine,
Expand Down
Loading

0 comments on commit 3f9522a

Please sign in to comment.