Beispiel #1
0
func RenderSoy(c *gin.Context) {
	var testdata = []data.Map{
		{"names": data.List{}},
		{"names": data.List{data.String("Rob")}},
		{"names": data.List{data.String("Rob"), data.String("Joe")}},
	}
	if err := tofu.Render(c.Writer, "soy.examples.simple.helloNames", testdata[2]); err != nil {
		c.Error(err)
		return
	}
}
Beispiel #2
0
func directiveInsertWordBreaks(value data.Value, args []data.Value) data.Value {
	var (
		input    = template.HTMLEscapeString(value.String())
		maxChars = int(args[0].(data.Int))
		chars    = 0
		output   *bytes.Buffer // create the buffer lazily
	)
	for i, ch := range input {
		switch {
		case ch == ' ':
			chars = 0
		case chars >= maxChars:
			if output == nil {
				output = bytes.NewBufferString(input[:i])
			}
			output.WriteString("<wbr>")
			chars = 1
		default:
			chars++
		}
		if output != nil {
			output.WriteRune(ch)
		}
	}
	if output == nil {
		return value
	}
	return data.String(output.String())
}
Beispiel #3
0
func directiveJson(value data.Value, _ []data.Value) data.Value {
	j, err := json.Marshal(value)
	if err != nil {
		panic(fmt.Errorf("Error JSON encoding value: %v", err))
	}
	return data.String(j)
}
Beispiel #4
0
func BenchmarkSimpleTemplate_Soy(b *testing.B) {
	var tofu, err = NewBundle().
		AddTemplateString("", `
{namespace small}
/**
 * @param foo
 * @param bar
 * @param baz
 */
{template .test}
some {$foo}, some {$bar}, more {$baz}
{/template}`).
		CompileToTofu()
	if err != nil {
		panic(err)
	}
	b.ResetTimer()
	var buf = new(bytes.Buffer)
	for i := 0; i < b.N; i++ {
		buf.Reset()
		err = tofu.Render(buf, "small.test", data.Map{
			"foo": data.String("foostring"),
			"bar": data.Int(42),
			"baz": data.Bool(true),
		})
		if err != nil {
			b.Error(err)
		}
	}
}
Beispiel #5
0
func funcKeys(v []data.Value) data.Value {
	var keys data.List
	for k, _ := range v[0].(data.Map) {
		keys = append(keys, data.String(k))
	}
	return keys
}
Beispiel #6
0
func BenchmarkExecuteSimple_Soy(b *testing.B) {
	var tofu, err = NewBundle().
		AddTemplateString("", mustReadFile("testdata/simple.soy")).
		CompileToTofu()
	if err != nil {
		panic(err)
	}
	b.ResetTimer()
	var buf = new(bytes.Buffer)
	var testdata = []data.Map{
		{"names": data.List{}},
		{"names": data.List{data.String("Rob")}},
		{"names": data.List{data.String("Rob"), data.String("Joe")}},
	}
	for i := 0; i < b.N; i++ {
		for _, data := range testdata {
			buf.Reset()
			err = tofu.Render(buf, "soy.examples.simple.helloNames", data)
			if err != nil {
				b.Error(err)
			}
		}
	}
}
Beispiel #7
0
func BenchmarkSimpleTemplate_Go(b *testing.B) {
	var tmpl = template.Must(template.New("").Parse(`
{{define "small.test"}}
some {{.foo}}, some {{.bar}}, more {{.baz}}
{{end}}`))
	b.ResetTimer()
	var buf = new(bytes.Buffer)
	for i := 0; i < b.N; i++ {
		buf.Reset()
		var err = tmpl.ExecuteTemplate(buf, "small.test", data.Map{
			"foo": data.String("foostring"),
			"bar": data.Int(42),
			"baz": data.Bool(true),
		})
		if err != nil {
			b.Error(err)
		}
	}
}
Beispiel #8
0
func TestIsnonnull(t *testing.T) {
	var tests = []struct {
		input    data.Value
		expected bool
	}{
		{data.Null{}, false},
		{data.Undefined{}, false},
		{data.Bool(false), true},
		{data.Int(0), true},
		{data.Float(0), true},
		{data.String(""), true},
		{data.List{}, true},
		{data.Map{}, true},
	}

	for _, test := range tests {
		var actual = funcIsNonnull([]data.Value{test.input}).(data.Bool)
		if bool(actual) != test.expected {
			t.Errorf("isNonnull(%v) => %v, expected %v", test.input, actual, test.expected)
		}
	}
}
Beispiel #9
0
func handler(res http.ResponseWriter, req *http.Request) {
	var tofu, err = soy.NewBundle().
		AddTemplateFile(os.Args[1]).
		CompileToTofu()
	if err != nil {
		http.Error(res, err.Error(), 500)
		return
	}

	var m = make(data.Map)
	for k, v := range req.URL.Query() {
		m[k] = data.String(v[0])
	}

	var buf bytes.Buffer
	err = tofu.Render(&buf, "soyweb.soyweb", m)
	if err != nil {
		http.Error(res, err.Error(), 500)
		return
	}

	io.Copy(res, &buf)
}
Beispiel #10
0
func directiveTruncate(value data.Value, args []data.Value) data.Value {
	if !isInt(args[0]) {
		panic(fmt.Errorf("First parameter of '|truncate' is not an integer: %v", args[0]))
	}
	var maxLen = int(args[0].(data.Int))
	var str = value.String()
	if len(str) <= maxLen {
		return value
	}

	var ellipsis = data.Bool(true)
	if len(args) == 2 {
		var ok bool
		ellipsis, ok = args[1].(data.Bool)
		if !ok {
			panic(fmt.Errorf("Second parameter of '|truncate' is not a bool: %v", args[1]))
		}
	}

	if ellipsis {
		if maxLen > 3 {
			maxLen -= 3
		} else {
			ellipsis = false
		}
	}

	for !utf8.RuneStart(str[maxLen]) {
		maxLen--
	}

	str = str[:maxLen]
	if ellipsis {
		str += "..."
	}
	return data.String(str)
}
Beispiel #11
0
	{"log", "{log}Hello {$name}{/log}", tFile(
		&ast.LogNode{0, tList(
			newText(0, "Hello "),
			&ast.PrintNode{0, &ast.DataRefNode{0, "name", nil}, nil},
		)},
	)},
	{"log+comment", "{log}Hello {$name} // comment\n{/log}", tFile(
		&ast.LogNode{0, tList(
			newText(0, "Hello "),
			&ast.PrintNode{0, &ast.DataRefNode{0, "name", nil}, nil},
		)},
	)},

	{"debugger", "{debugger}", tFile(&ast.DebuggerNode{0})},
	{"global", "{GLOBAL_STR}{app.GLOBAL}", tFile(
		&ast.PrintNode{0, &ast.GlobalNode{0, "GLOBAL_STR", data.String("a")}, nil},
		&ast.PrintNode{0, &ast.GlobalNode{0, "app.GLOBAL", data.String("b")}, nil},
	)},

	{"expression1", "{not false and (isFirst($foo) or (-$x - 5) > 3.1)}", tFile(&ast.PrintNode{0, &ast.AndNode{bin(
		&ast.NotNode{0, &ast.BoolNode{0, false}},
		&ast.OrNode{bin(
			&ast.FunctionNode{0, "isFirst", []ast.Node{&ast.DataRefNode{0, "foo", nil}}},
			&ast.GtNode{bin(
				&ast.SubNode{bin(
					&ast.NegateNode{0, &ast.DataRefNode{0, "x", nil}},
					&ast.IntNode{0, 5})},
				&ast.FloatNode{0, 3.1})})})}, nil})},

	{"expression2", `{null or ('foo' == 'f'+true ? -3 <= 5 : not $foo ?: bar(5))}`, tFile(&ast.PrintNode{0, &ast.OrNode{bin(
		&ast.NullNode{0},
Beispiel #12
0
func directiveChangeNewlineToBr(value data.Value, _ []data.Value) data.Value {
	return data.String(newlinePattern.ReplaceAllString(
		template.HTMLEscapeString(value.String()),
		"<br>"))
}
Beispiel #13
0
func directiveEscapeJsString(value data.Value, _ []data.Value) data.Value {
	return data.String(template.JSEscapeString(value.String()))
}
Beispiel #14
0
func directiveEscapeUri(value data.Value, _ []data.Value) data.Value {
	return data.String(url.QueryEscape(value.String()))
}
Beispiel #15
0
// walk recursively goes through each node and executes the indicated logic and
// writes the output
func (s *state) walk(node ast.Node) {
	s.val = data.Undefined{}
	s.at(node)
	switch node := node.(type) {
	case *ast.SoyFileNode:
		for _, node := range node.Body {
			s.walk(node)
		}
	case *ast.TemplateNode:
		if node.Autoescape != ast.AutoescapeUnspecified {
			s.autoescape = node.Autoescape
		}
		s.walk(node.Body)
	case *ast.ListNode:
		for _, node := range node.Nodes {
			s.walk(node)
		}

		// Output nodes ----------
	case *ast.PrintNode:
		s.evalPrint(node)
	case *ast.RawTextNode:
		if _, err := s.wr.Write(node.Text); err != nil {
			s.errorf("%s", err)
		}
	case *ast.MsgNode:
		s.walk(node.Body)
	case *ast.CssNode:
		var prefix = ""
		if node.Expr != nil {
			prefix = s.eval(node.Expr).String() + "-"
		}
		if _, err := io.WriteString(s.wr, prefix+node.Suffix); err != nil {
			s.errorf("%s", err)
		}
	case *ast.DebuggerNode:
		// nothing to do
	case *ast.LogNode:
		Logger.Print(string(s.renderBlock(node.Body)))

		// Control flow ----------
	case *ast.IfNode:
		for _, cond := range node.Conds {
			if cond.Cond == nil || s.eval(cond.Cond).Truthy() {
				s.walk(cond.Body)
				break
			}
		}
	case *ast.ForNode:
		var list, ok = s.eval(node.List).(data.List)
		if !ok {
			s.errorf("In for loop %q, %q does not resolve to a list.",
				node.String(), node.List.String())
		}
		if len(list) == 0 {
			if node.IfEmpty != nil {
				s.walk(node.IfEmpty)
			}
			break
		}
		s.context.push()
		for i, item := range list {
			s.context.set(node.Var, item)
			s.context.set(node.Var+"__index", data.Int(i))
			s.context.set(node.Var+"__lastIndex", data.Int(len(list)-1))
			s.walk(node.Body)
		}
		s.context.pop()
	case *ast.SwitchNode:
		var switchValue = s.eval(node.Value)
		for _, caseNode := range node.Cases {
			for _, caseValueNode := range caseNode.Values {
				if switchValue.Equals(s.eval(caseValueNode)) {
					s.walk(caseNode.Body)
					return
				}
			}
			if len(caseNode.Values) == 0 { // default/last case
				s.walk(caseNode.Body)
				return
			}
		}
	case *ast.CallNode:
		s.evalCall(node)
	case *ast.LetValueNode:
		s.context.set(node.Name, s.eval(node.Expr))
	case *ast.LetContentNode:
		s.context.set(node.Name, data.String(s.renderBlock(node.Body)))

		// Values ----------
	case *ast.NullNode:
		s.val = data.Null{}
	case *ast.StringNode:
		s.val = data.String(node.Value)
	case *ast.IntNode:
		s.val = data.Int(node.Value)
	case *ast.FloatNode:
		s.val = data.Float(node.Value)
	case *ast.BoolNode:
		s.val = data.Bool(node.True)
	case *ast.GlobalNode:
		s.val = node.Value
	case *ast.ListLiteralNode:
		var items = make(data.List, len(node.Items))
		for i, item := range node.Items {
			items[i] = s.eval(item)
		}
		s.val = data.List(items)
	case *ast.MapLiteralNode:
		var items = make(data.Map, len(node.Items))
		for k, v := range node.Items {
			items[k] = s.eval(v)
		}
		s.val = data.Map(items)
	case *ast.FunctionNode:
		s.val = s.evalFunc(node)
	case *ast.DataRefNode:
		s.val = s.evalDataRef(node)

		// Arithmetic operators ----------
	case *ast.NegateNode:
		switch arg := s.evaldef(node.Arg).(type) {
		case data.Int:
			s.val = data.Int(-arg)
		case data.Float:
			s.val = data.Float(-arg)
		default:
			s.errorf("can not negate non-number: %q", arg.String())
		}
	case *ast.AddNode:
		var arg1, arg2 = s.eval2def(node.Arg1, node.Arg2)
		switch {
		case isInt(arg1) && isInt(arg2):
			s.val = data.Int(arg1.(data.Int) + arg2.(data.Int))
		case isString(arg1) || isString(arg2):
			s.val = data.String(arg1.String() + arg2.String())
		default:
			s.val = data.Float(toFloat(arg1) + toFloat(arg2))
		}
	case *ast.SubNode:
		var arg1, arg2 = s.eval2def(node.Arg1, node.Arg2)
		switch {
		case isInt(arg1) && isInt(arg2):
			s.val = data.Int(arg1.(data.Int) - arg2.(data.Int))
		default:
			s.val = data.Float(toFloat(arg1) - toFloat(arg2))
		}
	case *ast.DivNode:
		var arg1, arg2 = s.eval2def(node.Arg1, node.Arg2)
		s.val = data.Float(toFloat(arg1) / toFloat(arg2))
	case *ast.MulNode:
		var arg1, arg2 = s.eval2def(node.Arg1, node.Arg2)
		switch {
		case isInt(arg1) && isInt(arg2):
			s.val = data.Int(arg1.(data.Int) * arg2.(data.Int))
		default:
			s.val = data.Float(toFloat(arg1) * toFloat(arg2))
		}
	case *ast.ModNode:
		var arg1, arg2 = s.eval2def(node.Arg1, node.Arg2)
		s.val = data.Int(arg1.(data.Int) % arg2.(data.Int))

		// Arithmetic comparisons ----------
	case *ast.EqNode:
		s.val = data.Bool(s.eval(node.Arg1).Equals(s.eval(node.Arg2)))
	case *ast.NotEqNode:
		s.val = data.Bool(!s.eval(node.Arg1).Equals(s.eval(node.Arg2)))
	case *ast.LtNode:
		s.val = data.Bool(toFloat(s.evaldef(node.Arg1)) < toFloat(s.evaldef(node.Arg2)))
	case *ast.LteNode:
		s.val = data.Bool(toFloat(s.evaldef(node.Arg1)) <= toFloat(s.evaldef(node.Arg2)))
	case *ast.GtNode:
		s.val = data.Bool(toFloat(s.evaldef(node.Arg1)) > toFloat(s.evaldef(node.Arg2)))
	case *ast.GteNode:
		s.val = data.Bool(toFloat(s.evaldef(node.Arg1)) >= toFloat(s.evaldef(node.Arg2)))

		// Boolean operators ----------
	case *ast.NotNode:
		s.val = data.Bool(!s.eval(node.Arg).Truthy())
	case *ast.AndNode:
		s.val = data.Bool(s.eval(node.Arg1).Truthy() && s.eval(node.Arg2).Truthy())
	case *ast.OrNode:
		s.val = data.Bool(s.eval(node.Arg1).Truthy() || s.eval(node.Arg2).Truthy())
	case *ast.ElvisNode:
		var arg1 = s.eval(node.Arg1)
		if arg1 != (data.Null{}) && arg1 != (data.Undefined{}) {
			s.val = arg1
		} else {
			s.val = s.eval(node.Arg2)
		}
	case *ast.TernNode:
		var arg1 = s.eval(node.Arg1)
		if arg1.Truthy() {
			s.val = s.eval(node.Arg2)
		} else {
			s.val = s.eval(node.Arg3)
		}

	default:
		s.errorf("unknown node: %T", node)
	}
}
Beispiel #16
0
func TestInjectedData(t *testing.T) {
	ij["foo"] = data.String("abc")
	runExecTests(t, []execTest{
		exprtest("ij", `{$ij.foo}`, `abc`),
	})
}
Beispiel #17
0
func directiveEscapeHtml(value data.Value, _ []data.Value) data.Value {
	return data.String(template.HTMLEscapeString(value.String()))
}