Support TokenEscapeChar, add tests
This commit is contained in:
parent
c9c7dd1b22
commit
decc220bfc
@ -22,6 +22,7 @@ type Option struct {
|
||||
ShowLabels bool // Prepend & Append a string to every template, helpful in debugging
|
||||
CommentDelimiters [2]string // Used in conjunction with ShowLabels, if HTML then use '<!--', '-->'
|
||||
FixedIndent bool // Intended to improve readability when inspecting nested templates
|
||||
TokenEscapeChar string // Escapes a token delimiter, i.e. if set to '\' then variables that have '\' prefix won't be replaced
|
||||
}
|
||||
|
||||
type TemplateNest struct {
|
||||
@ -131,6 +132,7 @@ func (nest *TemplateNest) index(filePath string) (TemplateFileIndex, error) {
|
||||
|
||||
delimiterStart := nest.option.Delimiters[0]
|
||||
delimiterEnd := nest.option.Delimiters[1]
|
||||
escapeChar := nest.option.TokenEscapeChar
|
||||
|
||||
re := regexp.MustCompile(fmt.Sprintf(
|
||||
"%s\\s*(.+?)\\s*%s", regexp.QuoteMeta(delimiterStart), regexp.QuoteMeta(delimiterEnd),
|
||||
@ -151,6 +153,22 @@ func (nest *TemplateNest) index(filePath string) (TemplateFileIndex, error) {
|
||||
varName := string(contents[nameStartIdx:nameEndIdx])
|
||||
variableNames[varName] = struct{}{}
|
||||
|
||||
// If token escape char is set then look behind for it and if we
|
||||
// find the escape char then we're only going to remove the escape
|
||||
// char and not remove this variable.
|
||||
if escapeChar != "" && startIdx >= len(escapeChar) {
|
||||
escapeStartIdx := startIdx - len(escapeChar)
|
||||
if contentsStr[escapeStartIdx:startIdx] == escapeChar {
|
||||
variables = append(variables, TemplateFileVariable{
|
||||
Name: "",
|
||||
StartPosition: uint(escapeStartIdx),
|
||||
EndPosition: uint(escapeStartIdx + len(escapeChar)),
|
||||
EscapedToken: true,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// If fixed indent is enabled then record the indent level for this
|
||||
// variable. To get the indent level we look at each character in
|
||||
// reverse from the start position of the variable until we find a
|
||||
@ -276,6 +294,10 @@ func (nest *TemplateNest) Render(toRender interface{}) (string, error) {
|
||||
rendered := tIndex.Contents
|
||||
for i := len(tIndex.Variables) - 1; i >= 0; i-- {
|
||||
variable := tIndex.Variables[i]
|
||||
if variable.EscapedToken {
|
||||
rendered = rendered[:variable.StartPosition] + rendered[variable.EndPosition:]
|
||||
continue
|
||||
}
|
||||
|
||||
// If the variable doesn't exist in template hash then replace it
|
||||
// with an empty string.
|
||||
|
97
tests/07_token_escape_char_test.go
Normal file
97
tests/07_token_escape_char_test.go
Normal file
@ -0,0 +1,97 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"git.virtual.blue/tomgracey/template-nest-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRenderWithEscapedVariable(t *testing.T) {
|
||||
nest, err := templatenest.New(templatenest.Option{
|
||||
TemplateDir: "templates",
|
||||
TokenEscapeChar: "\\",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initialize TemplateNest: %+v", err)
|
||||
}
|
||||
|
||||
page := templatenest.Hash{
|
||||
"TEMPLATE": "00-simple-page",
|
||||
"variable": "Simple Variable",
|
||||
"simple_component": []templatenest.Hash{
|
||||
templatenest.Hash{
|
||||
"TEMPLATE": "01-simple-component-token-escape",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
outputPath := "templates/output/09-simple-page-token-escape.html"
|
||||
outputContents, err := ioutil.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading file (`%s`): %+v", outputPath, err)
|
||||
}
|
||||
|
||||
assert.Equal(
|
||||
t,
|
||||
strings.TrimSpace(string(outputContents)),
|
||||
nest.MustRender(page),
|
||||
"Rendered output does not match expected output",
|
||||
)
|
||||
}
|
||||
|
||||
func TestRenderWithEscapedVariableAtStart(t *testing.T) {
|
||||
nest, err := templatenest.New(templatenest.Option{
|
||||
TemplateDir: "templates",
|
||||
TokenEscapeChar: "\\",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initialize TemplateNest: %+v", err)
|
||||
}
|
||||
|
||||
page := templatenest.Hash{
|
||||
"TEMPLATE": "03-var-at-begin",
|
||||
"variable": "Simple Variable",
|
||||
}
|
||||
|
||||
outputPath := "templates/output/10-var-at-begin.html"
|
||||
outputContents, err := ioutil.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading file (`%s`): %+v", outputPath, err)
|
||||
}
|
||||
|
||||
assert.Equal(
|
||||
t,
|
||||
strings.TrimSpace(string(outputContents)),
|
||||
nest.MustRender(page),
|
||||
"Rendered output does not match expected output",
|
||||
)
|
||||
}
|
||||
|
||||
func TestRenderWithEscapedVariableAtStart01(t *testing.T) {
|
||||
nest, err := templatenest.New(templatenest.Option{
|
||||
TemplateDir: "templates",
|
||||
TokenEscapeChar: "\\",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initialize TemplateNest: %+v", err)
|
||||
}
|
||||
|
||||
page := templatenest.Hash{
|
||||
"TEMPLATE": "03-var-at-begin-with-space",
|
||||
}
|
||||
|
||||
outputPath := "templates/output/10-var-at-begin-with-space.html"
|
||||
outputContents, err := ioutil.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading file (`%s`): %+v", outputPath, err)
|
||||
}
|
||||
|
||||
assert.Equal(
|
||||
t,
|
||||
strings.TrimSpace(string(outputContents)),
|
||||
nest.MustRender(page),
|
||||
"Rendered output does not match expected output",
|
||||
)
|
||||
}
|
1
tests/templates/03-var-at-begin-with-space.html
Normal file
1
tests/templates/03-var-at-begin-with-space.html
Normal file
@ -0,0 +1 @@
|
||||
\<!--% variable %-->
|
1
tests/templates/output/10-var-at-begin-with-space.html
Normal file
1
tests/templates/output/10-var-at-begin-with-space.html
Normal file
@ -0,0 +1 @@
|
||||
<!--% variable %-->
|
Loading…
Reference in New Issue
Block a user