1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-09 21:15:56 +00:00

add 'iris.Ace' template engine: _examples/view/template_ace_0

This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-08-03 05:46:04 +03:00
parent dfa08041a1
commit 6844be57ea
20 changed files with 197 additions and 52 deletions

View File

@@ -1,7 +1,7 @@
# View
Iris supports 6 template engines out-of-the-box, developers can still use any external golang template engine,
as `context/context#ResponseWriter()` is an `io.Writer`.
Iris supports 7 template engines out-of-the-box, developers can still use any external golang template engine,
as `Context.ResponseWriter()` is an `io.Writer`.
All of these six template engines have common features with common API,
like Layout, Template Funcs, Party-specific layout, partial rendering and more.
@@ -12,6 +12,7 @@ like Layout, Template Funcs, Party-specific layout, partial rendering and more.
- Handlebars, its template parser is the [github.com/aymerick/raymond](https://github.com/aymerick/raymond)
- Amber, its template parser is the [github.com/eknkc/amber](https://github.com/eknkc/amber)
- Jet, its template parser is the [github.com/CloudyKit/jet](https://github.com/CloudyKit/jet)
- Ace, its template parser is the [github.com/yosssi/ace](https://github.com/yosssi/ace)
## Examples
@@ -27,8 +28,9 @@ like Layout, Template Funcs, Party-specific layout, partial rendering and more.
- [Pug (Jade) Actions`](https://github.com/kataras/iris/blob/master/_examples/view/template_pug_1)
- [Pug (Jade) Includes`](https://github.com/kataras/iris/blob/master/_examples/view/template_pug_2)
- [Pug (Jade) Extends`](https://github.com/kataras/iris/blob/master/_examples/view/template_pug_3)
- [Jet](https://github.com/kataras/iris/blob/master/_examples/view/template_jet_0) **NEW**
- [Jet Embedded](https://github.com/kataras/iris/blob/master/_examples/view/template_jet_1_embedded) **NEW**
- [Jet](https://github.com/kataras/iris/blob/master/_examples/view/template_jet_0)
- [Jet Embedded](https://github.com/kataras/iris/blob/master/_examples/view/template_jet_1_embedded)
- [Ace](https://github.com/kataras/iris/blob/master/_examples/view/template_ace_0)
You can serve [quicktemplate](https://github.com/valyala/quicktemplate) files too, simply by using the `context#ResponseWriter`, take a look at the [iris/_examples/view/quicktemplate](https://github.com/kataras/iris/tree/master/_examples/view/quicktemplate) example.

57
view/ace.go Normal file
View File

@@ -0,0 +1,57 @@
package view
import (
"path"
"sync"
"github.com/yosssi/ace"
)
// Ace returns a new ace view engine.
// It shares the same exactly logic with the
// html view engine, it uses the same exactly configuration.
//
// Read more about the Ace Go Parser: https://github.com/yosssi/ace
func Ace(directory, extension string) *HTMLEngine {
s := HTML(directory, extension)
funcs := make(map[string]interface{}, 0)
once := new(sync.Once)
s.middleware = func(name string, text []byte) (contents string, err error) {
once.Do(func() { // on first template parse, all funcs are given.
for k, v := range s.funcs {
funcs[k] = v
}
for k, v := range emptyFuncs {
funcs[k] = v
}
})
name = path.Join(path.Clean(directory), name)
src := ace.NewSource(
ace.NewFile(name, text),
ace.NewFile("", []byte{}),
[]*ace.File{},
)
rslt, err := ace.ParseSource(src, nil)
if err != nil {
return "", err
}
t, err := ace.CompileResult(name, rslt, &ace.Options{
Extension: extension[1:],
FuncMap: funcs,
DelimLeft: s.left,
DelimRight: s.right,
})
if err != nil {
return "", err
}
return t.Lookup(name).Tree.Root.String(), nil
}
return s
}

View File

@@ -220,5 +220,5 @@ func (s *AmberEngine) ExecuteWriter(w io.Writer, filename string, layout string,
return tmpl.Execute(w, bindingData)
}
return fmt.Errorf("Template with name %s doesn't exists in the dir", filename)
return fmt.Errorf("Template with name: %s does not exist in the dir: %s", filename, s.directory)
}

View File

@@ -376,5 +376,5 @@ func (s *DjangoEngine) ExecuteWriter(w io.Writer, filename string, layout string
return tmpl.ExecuteWriter(getPongoContext(bindingData), w)
}
return fmt.Errorf("template with name %s doesn't exists in the dir", filename)
return fmt.Errorf("template with name: %s ddoes not exist in the dir: %s", filename, s.directory)
}

View File

@@ -291,5 +291,5 @@ func (s *HandlebarsEngine) ExecuteWriter(w io.Writer, filename string, layout st
return err
}
return fmt.Errorf("template with name %s[original name = %s] doesn't exists in the dir", renderFilename, filename)
return fmt.Errorf("template with name: %s[original name = %s] does not exist in the dir: %s", renderFilename, filename, s.directory)
}

View File

@@ -26,8 +26,8 @@ type HTMLEngine struct {
right string
layout string
rmu sync.RWMutex // locks for layoutFuncs and funcs
layoutFuncs map[string]interface{}
funcs map[string]interface{}
layoutFuncs template.FuncMap
funcs template.FuncMap
//
middleware func(name string, contents []byte) (string, error)
@@ -38,7 +38,7 @@ type HTMLEngine struct {
var _ Engine = (*HTMLEngine)(nil)
var emptyFuncs = template.FuncMap{
"yield": func() (string, error) {
"yield": func(binding interface{}) (string, error) {
return "", fmt.Errorf("yield was called, yet no layout defined")
},
"part": func() (string, error) {
@@ -52,7 +52,8 @@ var emptyFuncs = template.FuncMap{
},
"current": func() (string, error) {
return "", nil
}, "render": func() (string, error) {
},
"render": func() (string, error) {
return "", nil
},
}
@@ -70,8 +71,8 @@ func HTML(directory, extension string) *HTMLEngine {
left: "{{",
right: "}}",
layout: "",
layoutFuncs: make(map[string]interface{}),
funcs: make(map[string]interface{}),
layoutFuncs: make(template.FuncMap),
funcs: make(template.FuncMap),
}
return s
@@ -172,10 +173,34 @@ func (s *HTMLEngine) AddLayoutFunc(funcName string, funcBody interface{}) *HTMLE
// - url func(routeName string, args ...string) string
// - urlpath func(routeName string, args ...string) string
// - render func(fullPartialName string) (template.HTML, error).
func (s *HTMLEngine) AddFunc(funcName string, funcBody interface{}) {
func (s *HTMLEngine) AddFunc(funcName string, funcBody interface{}) *HTMLEngine {
s.rmu.Lock()
s.funcs[funcName] = funcBody
s.rmu.Unlock()
return s
}
// SetFuncs overrides the template funcs with the given "funcMap".
func (s *HTMLEngine) SetFuncs(funcMap template.FuncMap) *HTMLEngine {
s.rmu.Lock()
s.funcs = funcMap
s.rmu.Unlock()
return s
}
// Funcs adds the elements of the argument map to the template's function map.
// It is legal to overwrite elements of the map. The return
// value is the template, so calls can be chained.
func (s *HTMLEngine) Funcs(funcMap template.FuncMap) *HTMLEngine {
s.rmu.Lock()
for k, v := range funcMap {
s.funcs[k] = v
}
s.rmu.Unlock()
return s
}
// Load parses the templates to the engine.
@@ -266,6 +291,7 @@ func (s *HTMLEngine) loadDirectory() error {
name := filepath.ToSlash(rel)
tmpl := s.Templates.New(name)
tmpl.Option(s.options...)
if s.middleware != nil {
contents, err = s.middleware(name, buf)
}
@@ -275,7 +301,12 @@ func (s *HTMLEngine) loadDirectory() error {
}
// s.mu.Lock()
// Add our funcmaps.
_, err = tmpl.Funcs(emptyFuncs).Funcs(s.funcs).Parse(contents)
_, err = tmpl.
Funcs(emptyFuncs).
// Funcs(s.makeDefaultLayoutFuncs(name)).
// Funcs(s.layoutFuncs).
Funcs(s.funcs).
Parse(contents)
// s.mu.Unlock()
if err != nil {
templateErr = err
@@ -393,15 +424,28 @@ func (s *HTMLEngine) executeTemplateBuf(name string, binding interface{}) (*byte
return buf, err
}
func (s *HTMLEngine) layoutFuncsFor(name string, binding interface{}) {
func (s *HTMLEngine) layoutFuncsFor(lt *template.Template, name string, binding interface{}) {
s.runtimeFuncsFor(lt, name, binding)
funcs := template.FuncMap{
"yield": func() (template.HTML, error) {
buf, err := s.executeTemplateBuf(name, binding)
// Return safe HTML here since we are rendering our own template.
return template.HTML(buf.String()), err
},
}
for k, v := range s.layoutFuncs {
funcs[k] = v
}
lt.Funcs(funcs)
}
func (s *HTMLEngine) runtimeFuncsFor(t *template.Template, name string, binding interface{}) {
funcs := template.FuncMap{
"part": func(partName string) (template.HTML, error) {
nameTemp := strings.Replace(name, ".html", "", -1)
nameTemp := strings.Replace(name, s.extension, "", -1)
fullPartName := fmt.Sprintf("%s-%s", nameTemp, partName)
buf, err := s.executeTemplateBuf(fullPartName, binding)
if err != nil {
@@ -440,25 +484,7 @@ func (s *HTMLEngine) layoutFuncsFor(name string, binding interface{}) {
},
}
for k, v := range s.layoutFuncs {
funcs[k] = v
}
if tpl := s.Templates.Lookup(name); tpl != nil {
tpl.Funcs(funcs)
}
}
func (s *HTMLEngine) runtimeFuncsFor(name string, binding interface{}) {
funcs := template.FuncMap{
"render": func(fullPartialName string) (template.HTML, error) {
buf, err := s.executeTemplateBuf(fullPartialName, binding)
return template.HTML(buf.String()), err
},
}
if tpl := s.Templates.Lookup(name); tpl != nil {
tpl.Funcs(funcs)
}
t.Funcs(funcs)
}
// ExecuteWriter executes a template and writes its result to the w writer.
@@ -474,14 +500,21 @@ func (s *HTMLEngine) ExecuteWriter(w io.Writer, name string, layout string, bind
}
}
layout = getLayout(layout, s.layout)
if layout = getLayout(layout, s.layout); layout != "" {
lt := s.Templates.Lookup(layout)
if lt == nil {
return fmt.Errorf("layout: %s does not exist in the dir: %s", name, s.directory)
}
if layout != "" {
s.layoutFuncsFor(name, bindingData)
name = layout
} else {
s.runtimeFuncsFor(name, bindingData)
s.layoutFuncsFor(lt, name, bindingData)
return lt.Execute(w, bindingData)
}
return s.Templates.ExecuteTemplate(w, name, bindingData)
t := s.Templates.Lookup(name)
if t == nil {
return fmt.Errorf("template: %s does not exist in the dir: %s", name, s.directory)
}
s.runtimeFuncsFor(t, name, bindingData)
return t.Execute(w, bindingData)
}

View File

@@ -12,8 +12,7 @@ import (
// Pug (or Jade) returns a new pug view engine.
// It shares the same exactly logic with the
// html view engine, it uses the same exactly configuration.
// It has got some features and a lot of functions
// which will make your life easier.
//
// Read more about the Jade Go Parser: https://github.com/Joker/jade
//
// Examples: