1
0
mirror of https://github.com/golang/go synced 2024-11-19 12:34:47 -07:00

exp/template: tweak behavior of booleans.

Russ suggested this technique, making the "and" and "or" functions handier.
But it's hacky, and I can be talked out of it.

R=dsymonds, rsc
CC=golang-dev
https://golang.org/cl/4698044
This commit is contained in:
Rob Pike 2011-07-14 07:59:04 +10:00
parent c3344d61bd
commit 469e333106
4 changed files with 45 additions and 18 deletions

View File

@ -199,7 +199,10 @@ the set but the Funcs methods can be used to add them.
Predefined global functions are named as follows. Predefined global functions are named as follows.
and and
Returns the boolean AND of its arguments. Returns the boolean AND of its arguments by returning the
first empty argument or the last argument, that is,
"and x y" behaves as "if x then y else x". All the
arguments are evaluated.
html html
Returns the escaped HTML equivalent of the textual Returns the escaped HTML equivalent of the textual
representation of its arguments. representation of its arguments.
@ -213,7 +216,10 @@ Predefined global functions are named as follows.
not not
Returns the boolean negation of its single argument. Returns the boolean negation of its single argument.
or or
Returns the boolean OR of its arguments. Returns the boolean OR of its arguments by returning the
first non-empty argument or the last argument, that is,
"or x y" behaves as "if x then x else y". All the
arguments are evaluated.
print print
An alias for fmt.Sprint An alias for fmt.Sprint
printf printf

View File

@ -289,7 +289,7 @@ func (s *state) evalCommand(dot reflect.Value, cmd *commandNode, final reflect.V
case *stringNode: case *stringNode:
return reflect.ValueOf(word.text) return reflect.ValueOf(word.text)
} }
s.errorf("can't handle command %q", firstWord) s.errorf("can't evaluate command %q", firstWord)
panic("not reached") panic("not reached")
} }

View File

@ -280,8 +280,8 @@ var execTests = []execTest{
// Booleans // Booleans
{"not", "{{not true}} {{not false}}", "false true", nil, true}, {"not", "{{not true}} {{not false}}", "false true", nil, true},
{"and", "{{and 0 0}} {{and 1 0}} {{and 0 1}} {{and 1 1}}", "false false false true", nil, true}, {"and", "{{and false 0}} {{and 1 0}} {{and 0 true}} {{and 1 1}}", "false 0 0 1", nil, true},
{"or", "{{or 0 0}} {{or 1 0}} {{or 0 1}} {{or 1 1}}", "false true true true", nil, true}, {"or", "{{or 0 0}} {{or 1 0}} {{or 0 true}} {{or 1 1}}", "0 1 true 1", nil, true},
{"boolean if", "{{if and true 1 `hi`}}TRUE{{else}}FALSE{{end}}", "TRUE", tVal, true}, {"boolean if", "{{if and true 1 `hi`}}TRUE{{else}}FALSE{{end}}", "TRUE", tVal, true},
{"boolean if not", "{{if and true 1 `hi` | not}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true}, {"boolean if not", "{{if and true 1 `hi` | not}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true},
@ -326,6 +326,10 @@ var execTests = []execTest{
{"range empty map else", "{{range .MSIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true}, {"range empty map else", "{{range .MSIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
{"range empty interface", "{{range .Empty3}}-{{.}}-{{else}}EMPTY{{end}}", "-7--8-", tVal, true}, {"range empty interface", "{{range .Empty3}}-{{.}}-{{else}}EMPTY{{end}}", "-7--8-", tVal, true},
// Cute examples.
{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
{"or as if false", `{{or .SIEmpty "slice is empty"}}`, "slice is empty", tVal, true},
// Error handling. // Error handling.
{"error method, error", "{{.EPERM true}}", "", tVal, false}, {"error method, error", "{{.EPERM true}}", "", tVal, false},
{"error method, no error", "{{.EPERM false}}", "false", tVal, true}, {"error method, no error", "{{.EPERM false}}", "false", tVal, true},

View File

@ -122,22 +122,39 @@ func index(item interface{}, indices ...interface{}) (interface{}, os.Error) {
// Boolean logic. // Boolean logic.
// and returns the Boolean AND of its arguments. func truth(a interface{}) bool {
func and(arg0 interface{}, args ...interface{}) (truth bool) { t, _ := isTrue(reflect.ValueOf(a))
truth, _ = isTrue(reflect.ValueOf(arg0)) return t
for i := 0; truth && i < len(args); i++ {
truth, _ = isTrue(reflect.ValueOf(args[i]))
}
return
} }
// or returns the Boolean OR of its arguments. // and computes the Boolean AND of its arguments, returning
func or(arg0 interface{}, args ...interface{}) (truth bool) { // the first false argument it encounters, or the last argument.
truth, _ = isTrue(reflect.ValueOf(arg0)) func and(arg0 interface{}, args ...interface{}) interface{} {
for i := 0; !truth && i < len(args); i++ { if !truth(arg0) {
truth, _ = isTrue(reflect.ValueOf(args[i])) return arg0
} }
return for i := range args {
arg0 = args[i]
if !truth(arg0) {
break
}
}
return arg0
}
// or computes the Boolean OR of its arguments, returning
// the first true argument it encounters, or the last argument.
func or(arg0 interface{}, args ...interface{}) interface{} {
if truth(arg0) {
return arg0
}
for i := range args {
arg0 = args[i]
if truth(arg0) {
break
}
}
return arg0
} }
// not returns the Boolean negation of its argument. // not returns the Boolean negation of its argument.