Skip to content

Commit

Permalink
refactor(renderer): replace UserMacroFunc with MacroTemplate
Browse files Browse the repository at this point in the history
  • Loading branch information
odknt committed May 13, 2019
1 parent 9194304 commit f58e764
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 59 deletions.
20 changes: 12 additions & 8 deletions pkg/renderer/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,26 @@ package renderer

import (
"context"
"errors"
"io"
"time"

"github.com/bytesparadise/libasciidoc/pkg/types"
log "github.com/sirupsen/logrus"
)

// MacroFunc represents a user macro function.
type MacroFunc func(e types.UserMacro) ([]byte, error)
// MacroTemplate an interface of template for user macro.
type MacroTemplate interface {
Execute(wr io.Writer, data interface{}) error
}

// Context is a custom implementation of the standard golang context.Context interface,
// which carries the types.Document which is being processed
type Context struct {
context context.Context
Document types.Document
options map[string]interface{}
macros map[string]MacroFunc
macros map[string]MacroTemplate
}

// Wrap wraps the given `ctx` context into a new context which will contain the given `document` document.
Expand All @@ -26,7 +30,7 @@ func Wrap(ctx context.Context, document types.Document, options ...Option) *Cont
context: ctx,
Document: document,
options: make(map[string]interface{}),
macros: make(map[string]MacroFunc),
macros: make(map[string]MacroTemplate),
}
for _, option := range options {
option(result)
Expand Down Expand Up @@ -160,13 +164,13 @@ func (ctx *Context) GetImagesDir() string {
return ""
}

// UserMacro finds and returns a user macro function by specified name.
func (ctx *Context) UserMacro(name string) MacroFunc {
// MacroTemplate finds and returns a user macro function by specified name.
func (ctx *Context) MacroTemplate(name string) (MacroTemplate, error) {
macro, ok := ctx.macros[name]
if ok {
return macro
return macro, nil
}
return nil
return nil, errors.New("Unknown user macro: " + name)
}

// -----------------------
Expand Down
13 changes: 13 additions & 0 deletions pkg/renderer/html5/_macros/hello
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{- if eq .Kind "block" -}}
<div class="helloblock">
<div class="content">
{{end -}}
<span>
{{- if .Attributes.Has "prefix"}}{{escape (.Attributes.GetAsString "prefix")}} {{else}}hello {{end -}}
{{- if ne .Value ""}}{{escape .Value}}{{else}}world{{- end -}}
{{- escape (.Attributes.GetAsString "suffix") -}}
</span>
{{- if eq .Kind "block"}}
</div>
</div>
{{- end -}}
16 changes: 10 additions & 6 deletions pkg/renderer/html5/user_macro.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package html5

import (
"errors"
"bytes"

"github.com/bytesparadise/libasciidoc/pkg/renderer"
"github.com/bytesparadise/libasciidoc/pkg/types"
)

func renderUserMacro(ctx *renderer.Context, cm types.UserMacro) ([]byte, error) {
macro := ctx.UserMacro(cm.Name)
if macro == nil {
return nil, errors.New("Unknown user macro: " + cm.Name)
func renderUserMacro(ctx *renderer.Context, um types.UserMacro) ([]byte, error) {
macro, err := ctx.MacroTemplate(um.Name)
if err != nil {
return nil, err
}
buf := bytes.NewBuffer([]byte{})
if macro.Execute(buf, um) != nil {
return nil, err
}

return macro(cm)
return buf.Bytes(), nil
}
64 changes: 23 additions & 41 deletions pkg/renderer/html5/user_macro_test.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,32 @@
package html5_test

import (
"bytes"
"html"
texttemplate "text/template"

"github.com/bytesparadise/libasciidoc/pkg/renderer"
"github.com/bytesparadise/libasciidoc/pkg/types"
. "github.com/onsi/ginkgo"
)

var helloTmplStr = `{{- if eq .Kind "block" -}}
<div class="helloblock">
<div class="content">
{{end -}}
<span>
{{- if .Attributes.Has "prefix"}}{{escape (.Attributes.GetAsString "prefix")}} {{else}}hello {{end -}}
{{- if ne .Value ""}}{{escape .Value}}{{else}}world{{- end -}}
{{- escape (.Attributes.GetAsString "suffix") -}}
</span>
{{- if eq .Kind "block"}}
</div>
</div>
{{- end -}}`

var helloTmpl texttemplate.Template

func helloMacro(cm types.UserMacro) ([]byte, error) {
buf := bytes.NewBuffer(nil)
err := helloTmpl.Execute(buf, cm)
if err != nil {
return nil, err
// an example for find and define user macro
func findMacroTemplate() []renderer.Option {
t := texttemplate.New("user macro")
t.Funcs(texttemplate.FuncMap{
"escape": html.EscapeString,
})
tmpl := texttemplate.Must(t.ParseGlob("_macros/*"))
tmpls := tmpl.Templates()
opts := make([]renderer.Option, len(tmpls))
for i, tt := range tmpls {
opts[i] = renderer.DefineMacro(tt.Name(), tt)
}

return buf.Bytes(), nil
return opts
}

var _ = Describe("user macros", func() {

Context("user macros", func() {
opts := findMacroTemplate()

It("undefined macro", func() {

Expand All @@ -54,7 +42,7 @@ var _ = Describe("user macros", func() {
<span>hello world</span>
</div>
</div>`
verify(GinkgoT(), expectedResult, actualContent, renderer.DefineMacro("hello", helloMacro))
verify(GinkgoT(), expectedResult, actualContent, opts...)
})

It("user macro block with attribute", func() {
Expand All @@ -65,7 +53,7 @@ var _ = Describe("user macros", func() {
<span>hello world!!!!</span>
</div>
</div>`
verify(GinkgoT(), expectedResult, actualContent, renderer.DefineMacro("hello", helloMacro))
verify(GinkgoT(), expectedResult, actualContent, opts...)
})

It("user macro block with value", func() {
Expand All @@ -76,18 +64,18 @@ var _ = Describe("user macros", func() {
<span>hello John Doe</span>
</div>
</div>`
verify(GinkgoT(), expectedResult, actualContent, renderer.DefineMacro("hello", helloMacro))
verify(GinkgoT(), expectedResult, actualContent, opts...)
})

It("user macro block with value and attributes", func() {

actualContent := `hello::John Doe[prefix="Hi",suffix="!!"]`
actualContent := `hello::John Doe[prefix="Hi ",suffix="!!"]`
expectedResult := `<div class="helloblock">
<div class="content">
<span>Hi John Doe!!</span>
</div>
</div>`
verify(GinkgoT(), expectedResult, actualContent, renderer.DefineMacro("hello", helloMacro))
verify(GinkgoT(), expectedResult, actualContent, opts...)
})

It("inline macro", func() {
Expand All @@ -96,7 +84,7 @@ var _ = Describe("user macros", func() {
expectedResult := `<div class="paragraph">
<p>AAA <span>hello world</span></p>
</div>`
verify(GinkgoT(), expectedResult, actualContent, renderer.DefineMacro("hello", helloMacro))
verify(GinkgoT(), expectedResult, actualContent, opts...)
})

It("inline macro with attribute", func() {
Expand All @@ -105,7 +93,7 @@ var _ = Describe("user macros", func() {
expectedResult := `<div class="paragraph">
<p>AAA <span>hello world!!!!!</span></p>
</div>`
verify(GinkgoT(), expectedResult, actualContent, renderer.DefineMacro("hello", helloMacro))
verify(GinkgoT(), expectedResult, actualContent, opts...)
})

It("inline macro with value", func() {
Expand All @@ -114,23 +102,17 @@ var _ = Describe("user macros", func() {
expectedResult := `<div class="paragraph">
<p>AAA <span>hello John Doe</span></p>
</div>`
verify(GinkgoT(), expectedResult, actualContent, renderer.DefineMacro("hello", helloMacro))
verify(GinkgoT(), expectedResult, actualContent, opts...)
})

It("inline macro with value and attributes", func() {

actualContent := `AAA hello:John Doe[prefix="Hi",suffix="!!"]`
actualContent := `AAA hello:John Doe[prefix="Hi ",suffix="!!"]`
expectedResult := `<div class="paragraph">
<p>AAA <span>Hi John Doe!!</span></p>
</div>`
verify(GinkgoT(), expectedResult, actualContent, renderer.DefineMacro("hello", helloMacro))
verify(GinkgoT(), expectedResult, actualContent, opts...)
})

})
})

func init() {
helloTmpl = newTextTemplate("hello", helloTmplStr, texttemplate.FuncMap{
"escape": html.EscapeString,
})
}
10 changes: 6 additions & 4 deletions pkg/renderer/options.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package renderer

import "time"
import (
"time"
)

//Option the options when rendering a document
type Option func(ctx *Context)
Expand Down Expand Up @@ -38,10 +40,10 @@ func Entrypoint(entrypoint string) Option {
}
}

// DefineMacro defines the given function to a user macro with the given name
func DefineMacro(name string, cm MacroFunc) Option {
// DefineMacro defines the given template to a user macro with the given name
func DefineMacro(name string, t MacroTemplate) Option {
return func(ctx *Context) {
ctx.macros[name] = cm
ctx.macros[name] = t
}
}

Expand Down

0 comments on commit f58e764

Please sign in to comment.