Skip to content

Commit

Permalink
Get rid of the container.Vector dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
hoisie committed Jan 17, 2012
1 parent 7ab1fda commit fbe1396
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 46 deletions.
3 changes: 2 additions & 1 deletion Makefile
@@ -1,6 +1,7 @@
include $(GOROOT)/src/Make.inc

TARG=mustache
TARG=github.com/hoisie/mustache.go

GOFILES=\
mustache.go\

Expand Down
4 changes: 3 additions & 1 deletion Readme.md
Expand Up @@ -8,8 +8,10 @@ For more information about mustache, check out the [mustache project page](http:

Also check out some [example mustache files](http://github.com/defunkt/mustache/tree/master/examples/)

## Usage
## Installation
To install mustache.go, simply run `goinstall github.com/hoisie/mustache.go`. To use it in a program, use `import "github.com/hoisie/mustache.go"`

## Usage
There are only four methods in this package:

func Render(data string, context ...interface{}) string
Expand Down
84 changes: 40 additions & 44 deletions mustache.go
Expand Up @@ -2,7 +2,6 @@ package mustache

import (
"bytes"
"container/vector"
"fmt"
"io"
"io/ioutil"
Expand All @@ -25,7 +24,7 @@ type sectionElement struct {
name string
inverted bool
startline int
elems *vector.Vector
elems []interface{}
}

type Template struct {
Expand All @@ -35,7 +34,7 @@ type Template struct {
p int
curline int
dir string
elems *vector.Vector
elems []interface{}
}

type parseError struct {
Expand Down Expand Up @@ -162,7 +161,7 @@ func (tmpl *Template) parseSection(section *sectionElement) os.Error {

// put text into an item
text = text[0 : len(text)-len(tmpl.otag)]
section.elems.Push(&textElement{[]byte(text)})
section.elems = append(section.elems, &textElement{[]byte(text)})
if tmpl.p < len(tmpl.data) && tmpl.data[tmpl.p] == '{' {
text, err = tmpl.readString("}" + tmpl.ctag)
} else {
Expand Down Expand Up @@ -194,12 +193,12 @@ func (tmpl *Template) parseSection(section *sectionElement) os.Error {
tmpl.p += 2
}

se := sectionElement{name, tag[0] == '^', tmpl.curline, new(vector.Vector)}
se := sectionElement{name, tag[0] == '^', tmpl.curline, []interface{}{}}
err := tmpl.parseSection(&se)
if err != nil {
return err
}
section.elems.Push(&se)
section.elems = append(section.elems, &se)
case '/':
name := strings.TrimSpace(tag[1:])
if name != section.name {
Expand All @@ -213,7 +212,7 @@ func (tmpl *Template) parseSection(section *sectionElement) os.Error {
if err != nil {
return err
}
section.elems.Push(partial)
section.elems = append(section.elems, partial)
case '=':
if tag[len(tag)-1] != '=' {
return parseError{tmpl.curline, "Invalid meta tag"}
Expand All @@ -227,10 +226,10 @@ func (tmpl *Template) parseSection(section *sectionElement) os.Error {
case '{':
if tag[len(tag)-1] == '}' {
//use a raw tag
section.elems.Push(&varElement{tag[1 : len(tag)-1], true})
section.elems = append(section.elems, &varElement{tag[1 : len(tag)-1], true})
}
default:
section.elems.Push(&varElement{tag, false})
section.elems = append(section.elems, &varElement{tag, false})
}
}

Expand All @@ -240,16 +239,15 @@ func (tmpl *Template) parseSection(section *sectionElement) os.Error {
func (tmpl *Template) parse() os.Error {
for {
text, err := tmpl.readString(tmpl.otag)

if err == os.EOF {
//put the remaining text in a block
tmpl.elems.Push(&textElement{[]byte(text)})
tmpl.elems = append(tmpl.elems, &textElement{[]byte(text)})
return nil
}

// put text into an item
text = text[0 : len(text)-len(tmpl.otag)]
tmpl.elems.Push(&textElement{[]byte(text)})
tmpl.elems = append(tmpl.elems, &textElement{[]byte(text)})

if tmpl.p < len(tmpl.data) && tmpl.data[tmpl.p] == '{' {
text, err = tmpl.readString("}" + tmpl.ctag)
Expand Down Expand Up @@ -280,12 +278,12 @@ func (tmpl *Template) parse() os.Error {
tmpl.p += 2
}

se := sectionElement{name, tag[0] == '^', tmpl.curline, new(vector.Vector)}
se := sectionElement{name, tag[0] == '^', tmpl.curline, []interface{}{}}
err := tmpl.parseSection(&se)
if err != nil {
return err
}
tmpl.elems.Push(&se)
tmpl.elems = append(tmpl.elems, &se)
case '/':
return parseError{tmpl.curline, "unmatched close tag"}
case '>':
Expand All @@ -294,7 +292,7 @@ func (tmpl *Template) parse() os.Error {
if err != nil {
return err
}
tmpl.elems.Push(partial)
tmpl.elems = append(tmpl.elems, partial)
case '=':
if tag[len(tag)-1] != '=' {
return parseError{tmpl.curline, "Invalid meta tag"}
Expand All @@ -308,10 +306,10 @@ func (tmpl *Template) parse() os.Error {
case '{':
//use a raw tag
if tag[len(tag)-1] == '}' {
tmpl.elems.Push(&varElement{tag[1 : len(tag)-1], true})
tmpl.elems = append(tmpl.elems, &varElement{tag[1 : len(tag)-1], true})
}
default:
tmpl.elems.Push(&varElement{tag, false})
tmpl.elems = append(tmpl.elems, &varElement{tag, false})
}
}

Expand Down Expand Up @@ -369,16 +367,16 @@ func call(v reflect.Value, method reflect.Method) reflect.Value {

// Evaluate interfaces and pointers looking for a value that can look up the name, via a
// struct field, method, or map key, and return the result of the lookup.
func lookup(contextChain *vector.Vector, name string) reflect.Value {
func lookup(contextChain []interface{}, name string) reflect.Value {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Panic while looking up %q: %s\n", name, r)
}
}()

Outer:
for i := contextChain.Len() - 1; i >= 0; i-- {
v := contextChain.At(i).(reflect.Value)
for i := len(contextChain) - 1; i >= 0; i-- {
v := contextChain[i].(reflect.Value)
for v.IsValid() {
typ := v.Type()
if n := v.Type().NumMethod(); n > 0 {
Expand Down Expand Up @@ -449,10 +447,10 @@ loop:
return v
}

func renderSection(section *sectionElement, contextChain *vector.Vector, buf io.Writer) {
func renderSection(section *sectionElement, contextChain []interface{}, buf io.Writer) {
value := lookup(contextChain, section.name)
var context = contextChain.At(contextChain.Len() - 1).(reflect.Value)
var contexts = new(vector.Vector)
var context = contextChain[len(contextChain)-1].(reflect.Value)
var contexts = []interface{}{}
// if the value is nil, check if it's an inverted section
isNil := isNil(value)
if isNil && !section.inverted || !isNil && section.inverted {
Expand All @@ -462,31 +460,31 @@ func renderSection(section *sectionElement, contextChain *vector.Vector, buf io.
switch val := valueInd; val.Kind() {
case reflect.Slice:
for i := 0; i < val.Len(); i++ {
contexts.Push(val.Index(i))
contexts = append(contexts, val.Index(i))
}
case reflect.Array:
for i := 0; i < val.Len(); i++ {
contexts.Push(val.Index(i))
contexts = append(contexts, val.Index(i))
}
case reflect.Map, reflect.Struct:
contexts.Push(value)
contexts = append(contexts, value)
default:
contexts.Push(context)
contexts = append(contexts, context)
}
}

//by default we execute the section
for j := 0; j < contexts.Len(); j++ {
ctx := contexts.At(j).(reflect.Value)
contextChain.Push(ctx)
for i := 0; i < section.elems.Len(); i++ {
renderElement(section.elems.At(i), contextChain, buf)
for _, ctx := range contexts {
contextChain = append(contextChain, ctx)
for _, elem := range section.elems {
renderElement(elem, contextChain, buf)
}
contextChain.Pop()
//either 1 or 2
contextChain = contextChain[0 : len(contextChain)-1]
}
}

func renderElement(element interface{}, contextChain *vector.Vector, buf io.Writer) {
func renderElement(element interface{}, contextChain []interface{}, buf io.Writer) {
switch elem := element.(type) {
case *textElement:
buf.Write(elem.text)
Expand All @@ -513,26 +511,26 @@ func renderElement(element interface{}, contextChain *vector.Vector, buf io.Writ
}
}

func (tmpl *Template) renderTemplate(contextChain *vector.Vector, buf io.Writer) {
for i := 0; i < tmpl.elems.Len(); i++ {
renderElement(tmpl.elems.At(i), contextChain, buf)
func (tmpl *Template) renderTemplate(contextChain []interface{}, buf io.Writer) {
for _, elem := range tmpl.elems {
renderElement(elem, contextChain, buf)
}
}

func (tmpl *Template) Render(context ...interface{}) string {
var buf bytes.Buffer
var contextChain vector.Vector
var contextChain []interface{}
for _, c := range context {
val := reflect.ValueOf(c)
contextChain.Push(val)
contextChain = append(contextChain, val)
}
tmpl.renderTemplate(&contextChain, &buf)
tmpl.renderTemplate(contextChain, &buf)
return buf.String()
}

func ParseString(data string) (*Template, os.Error) {
cwd := os.Getenv("CWD")
tmpl := Template{data, "{{", "}}", 0, 1, cwd, new(vector.Vector)}
tmpl := Template{data, "{{", "}}", 0, 1, cwd, []interface{}{}}
err := tmpl.parse()

if err != nil {
Expand All @@ -550,7 +548,7 @@ func ParseFile(filename string) (*Template, os.Error) {

dirname, _ := path.Split(filename)

tmpl := Template{string(data), "{{", "}}", 0, 1, dirname, new(vector.Vector)}
tmpl := Template{string(data), "{{", "}}", 0, 1, dirname, []interface{}{}}
err = tmpl.parse()

if err != nil {
Expand All @@ -562,11 +560,9 @@ func ParseFile(filename string) (*Template, os.Error) {

func Render(data string, context ...interface{}) string {
tmpl, err := ParseString(data)

if err != nil {
return err.String()
}

return tmpl.Render(context...)
}

Expand Down

0 comments on commit fbe1396

Please sign in to comment.