Add parent built-in function (#27)

This commit is contained in:
Tyler Sommer 2020-02-04 16:58:39 -07:00 committed by GitHub
parent e8500f5e35
commit a2f5b4b91d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 0 deletions

36
example_parent_test.go Normal file
View file

@ -0,0 +1,36 @@
package stick_test
import (
"fmt"
"os"
"path/filepath"
"github.com/tyler-sommer/stick"
)
// An example of macro definition and usage.
//
// This example uses a macro to list the values, also showing two
// ways to import macros. Check the templates in the testdata folder
// for more information.
func ExampleEnv_Execute_parent() {
d, _ := os.Getwd()
env := stick.New(stick.NewFilesystemLoader(filepath.Join(d, "testdata")))
err := env.Execute("parent.txt.twig", os.Stdout, nil)
if err != nil {
fmt.Println(err)
}
// Output:
// This is a document.
//
// Not A title
//
// Testing parent()
//
// This is a test
//
// Another section
//
// Some extra information.
}

35
exec.go
View file

@ -23,6 +23,7 @@ type state struct {
name string // The name of the template.
meta *metadata // Additional template metadata.
current *parse.BlockNode // Current block, may be nil.
blocks []map[string]*parse.BlockNode // Block scopes.
macros map[string]*parse.MacroNode // Imported macros.
@ -183,6 +184,19 @@ func (s *state) getBlock(name string) *parse.BlockNode {
return nil
}
func (s *state) getParentBlock(name string) *parse.BlockNode {
rootFound := false
for _, blocks := range s.blocks {
if block, ok := blocks[name]; ok {
if rootFound {
return block
}
rootFound = true
}
}
return nil
}
// Method walk is the main entry-point into template execution.
func (s *state) walk(node parse.Node) error {
switch node := node.(type) {
@ -235,6 +249,11 @@ func (s *state) walk(node parse.Node) error {
}(s.name)
s.name = block.Origin
}
prev := s.current
s.current = block
defer func() {
s.current = prev
}()
return s.walk(block.Body)
}
// TODO: It seems this should never occur.
@ -691,6 +710,22 @@ func (s *state) evalExpr(exp parse.Expr) (v Value, e error) {
func (s *state) evalFunction(exp *parse.FuncExpr) (Value, error) {
fnName := exp.Name
switch fnName {
case "parent":
if s.current == nil {
return nil, errors.New("not inside a block!")
}
name := s.current.Name
if blk := s.getParentBlock(name); blk != nil {
pout := s.out
buf := &bytes.Buffer{}
s.out = buf
if err := s.walk(blk.Body); err != nil {
return nil, err
}
s.out = pout
return buf.String(), nil
}
return nil, errors.New("Unable to locate block \"" + name + "\"")
case "block":
eargs := exp.Args
if len(eargs) != 1 {

17
testdata/parent.txt.twig vendored Normal file
View file

@ -0,0 +1,17 @@
{% extends 'base.txt.twig' %}
{% use 'parts.txt.twig' %}
{% block title %}Not {{ parent() }}{% endblock %}
{% block intro %}Testing parent(){% endblock %}
{% block body %}This is a test{% endblock %}
{% block secondary_title %}{{ parent() }}{% endblock %}
{% block secondary_body %}{{ parent() }}{% endblock %}
{% block conclusion %}{% endblock %}
{% block footer %}{% endblock %}