Skip to content

Commit

Permalink
added partial helper (tweaked) (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
markbates authored Oct 31, 2018
1 parent afe7054 commit eae6e13
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 0 deletions.
5 changes: 5 additions & 0 deletions compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,11 @@ func (c *compiler) evalForExpression(node *ast.ForExpression) (interface{}, erro
c.ctx = octx
}()
c.ctx = octx.New()
// must copy all data from original (it includes application defined helpers)
for k, v := range octx.data {
c.ctx.data[k] = v
}

iter, err := c.evalExpression(node.Iterable)
if err != nil {
return nil, errors.WithStack(err)
Expand Down
1 change: 1 addition & 0 deletions helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func init() {
Helpers.Add("truncate", truncateHelper)
Helpers.Add("env", envy.MustGet)
Helpers.Add("envOr", envy.Get)
Helpers.Add("partial", partialHelper)
Helpers.Add("raw", func(s string) template.HTML {
return template.HTML(s)
})
Expand Down
49 changes: 49 additions & 0 deletions partial_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package plush

import (
"html/template"
"strings"

"github.com/pkg/errors"
)

// PartialFeeder is callback function should implemented on application side.
type PartialFeeder func(string) (string, error)

func partialHelper(name string, data map[string]interface{}, help HelperContext) (template.HTML, error) {
if help.Context == nil || help.Context.data == nil {
return "", errors.New("invalid context. abort")
}
for k, v := range data {
help.Set(k, v)
}

pf, ok := help.Value("partialFeeder").(func(string) (string, error))
if !ok {
return "", errors.New("could not found partial feeder from helpers")
}

var part string
var err error
if part, err = pf(name); err != nil {
return "", err
}

if part, err = Render(part, help.Context); err != nil {
return "", err
}

if layout, ok := data["layout"].(string); ok {
return partialHelper(
layout,
map[string]interface{}{"yield": template.HTML(part)},
help)
}

if ct, ok := help.Value("contentType").(string); ok {
if strings.Contains(ct, "javascript") && strings.HasSuffix(name, ".html") {
part = template.JSEscapeString(string(part))
}
}
return template.HTML(part), err
}
190 changes: 190 additions & 0 deletions partial_helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package plush

import (
"testing"

"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)

func Test_PartialHelper_Nil_Context(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{}
help := HelperContext{}

html, err := partialHelper(name, data, help)
r.Error(err)
r.Contains(err.Error(), "invalid context")
r.Equal("", string(html))
}

func Test_PartialHelper_Blank_Data(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{}
help := HelperContext{Context: NewContext()}
help.Context.data = nil

html, err := partialHelper(name, data, help)
r.Error(err)
r.Contains(err.Error(), "invalid context")
r.Equal("", string(html))
}

func Test_PartialHelper_Blank_Context(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{}
help := HelperContext{Context: NewContext()}

html, err := partialHelper(name, data, help)
r.Error(err)
r.Contains(err.Error(), "could not found")
r.Equal("", string(html))
}

func Test_PartialHelper_Invalid_Feeder(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{}
help := HelperContext{Context: NewContext()}
help.Set("partialFeeder", "me-rong")

html, err := partialHelper(name, data, help)
r.Error(err)
r.Contains(err.Error(), "could not found")
r.Equal("", string(html))
}

func Test_PartialHelper_Invalid_FeederFunction(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{}
help := HelperContext{Context: NewContext()}
help.Set("partialFeeder", func(string) string {
return "me-rong"
})

html, err := partialHelper(name, data, help)
r.Error(err)
r.Contains(err.Error(), "could not found")
r.Equal("", string(html))
}

func Test_PartialHelper_Feeder_Error(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{}
help := HelperContext{Context: NewContext()}
help.Set("partialFeeder", func(string) (string, error) {
return "", errors.New("me-rong")
})

_, err := partialHelper(name, data, help)
r.Error(err)
r.Contains(err.Error(), "me-rong")
}

func Test_PartialHelper_Good(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{}
help := HelperContext{Context: NewContext()}
help.Set("partialFeeder", func(string) (string, error) {
return `<div class="test">Plush!</div>`, nil
})

html, err := partialHelper(name, data, help)
r.NoError(err)
r.Equal(`<div class="test">Plush!</div>`, string(html))
}

func Test_PartialHelper_With_Data(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{"name": "Yonghwan"}
help := HelperContext{Context: NewContext()}
help.Set("partialFeeder", func(string) (string, error) {
return `<div class="test">Hello <%= name %></div>`, nil
})

html, err := partialHelper(name, data, help)
r.NoError(err)
r.Equal(`<div class="test">Hello Yonghwan</div>`, string(html))
}

func Test_PartialHelper_Render_Error(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{}
help := HelperContext{Context: NewContext()}
help.Set("partialFeeder", func(string) (string, error) {
return `<div class="test">Hello <%= name </div>`, nil
})

_, err := partialHelper(name, data, help)
r.Error(err)
}

func Test_PartialHelper_With_Layout(t *testing.T) {
r := require.New(t)

name := "index"
data := map[string]interface{}{
"name": "Yonghwan",
"layout": "container",
}
help := HelperContext{Context: NewContext()}
help.Set("partialFeeder", func(name string) (string, error) {
if name == "container" {
return `<html><%= yield %></html>`, nil
}
return `<div class="test">Hello <%= name %></div>`, nil
})

html, err := partialHelper(name, data, help)
r.NoError(err)
r.Equal(`<html><div class="test">Hello Yonghwan</div></html>`, string(html))
}

func Test_PartialHelper_JavaScript(t *testing.T) {
r := require.New(t)

name := "index.js"
data := map[string]interface{}{}
help := HelperContext{Context: NewContext()}
help.Set("contentType", "application/javascript")
help.Set("partialFeeder", func(string) (string, error) {
return `alert('\'Hello\'');`, nil
})

html, err := partialHelper(name, data, help)
r.NoError(err)
r.Equal(`alert('\'Hello\'');`, string(html))
}

func Test_PartialHelper_Javascript_With_HTML(t *testing.T) {
r := require.New(t)

name := "index.html"
data := map[string]interface{}{}
help := HelperContext{Context: NewContext()}
help.Set("contentType", "application/javascript")
help.Set("partialFeeder", func(string) (string, error) {
return `alert('\'Hello\'');`, nil
})

html, err := partialHelper(name, data, help)
r.NoError(err)
r.Equal(`alert(\'\\\'Hello\\\'\');`, string(html))
}

0 comments on commit eae6e13

Please sign in to comment.