]> Cypherpunks repositories - gostls13.git/commitdiff
exp/template: tweak behavior of booleans.
authorRob Pike <r@golang.org>
Wed, 13 Jul 2011 21:59:04 +0000 (07:59 +1000)
committerRob Pike <r@golang.org>
Wed, 13 Jul 2011 21:59:04 +0000 (07:59 +1000)
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

src/pkg/exp/template/doc.go
src/pkg/exp/template/exec.go
src/pkg/exp/template/exec_test.go
src/pkg/exp/template/funcs.go

index 3764bc70d501aaf835b831abac9b363e5158821a..9c439057d129136c29f4e6bfb142c5ef91080630 100644 (file)
@@ -199,7 +199,10 @@ the set but the Funcs methods can be used to add them.
 Predefined global functions are named as follows.
 
        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
                Returns the escaped HTML equivalent of the textual
                representation of its arguments.
@@ -213,7 +216,10 @@ Predefined global functions are named as follows.
        not
                Returns the boolean negation of its single argument.
        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
                An alias for fmt.Sprint
        printf
index 69558093088632ed910b49a4b424ab48bd9de473..b00f6a75829bf3366084e4622da81c2d010180cd 100644 (file)
@@ -289,7 +289,7 @@ func (s *state) evalCommand(dot reflect.Value, cmd *commandNode, final reflect.V
        case *stringNode:
                return reflect.ValueOf(word.text)
        }
-       s.errorf("can't handle command %q", firstWord)
+       s.errorf("can't evaluate command %q", firstWord)
        panic("not reached")
 }
 
index fc77c48e959f57bc1548f61a19a2c79517826266..7e0301c8d8459c09af4b7c3eb4998894972a0d8f 100644 (file)
@@ -280,8 +280,8 @@ var execTests = []execTest{
 
        // Booleans
        {"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},
-       {"or", "{{or 0 0}} {{or 1 0}} {{or 0 1}} {{or 1 1}}", "false true true 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 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 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 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 method, error", "{{.EPERM true}}", "", tVal, false},
        {"error method, no error", "{{.EPERM false}}", "false", tVal, true},
index 3aa9d629a81e1c83c87296cc3a15fbda7d286d57..3bf2bdd63639eb63bbb4209ab3d755326a6e96f0 100644 (file)
@@ -122,22 +122,39 @@ func index(item interface{}, indices ...interface{}) (interface{}, os.Error) {
 
 // Boolean logic.
 
-// and returns the Boolean AND of its arguments.
-func and(arg0 interface{}, args ...interface{}) (truth bool) {
-       truth, _ = isTrue(reflect.ValueOf(arg0))
-       for i := 0; truth && i < len(args); i++ {
-               truth, _ = isTrue(reflect.ValueOf(args[i]))
+func truth(a interface{}) bool {
+       t, _ := isTrue(reflect.ValueOf(a))
+       return t
+}
+
+// and computes the Boolean AND of its arguments, returning
+// the first false argument it encounters, or the last argument.
+func and(arg0 interface{}, args ...interface{}) interface{} {
+       if !truth(arg0) {
+               return arg0
+       }
+       for i := range args {
+               arg0 = args[i]
+               if !truth(arg0) {
+                       break
+               }
        }
-       return
+       return arg0
 }
 
-// or returns the Boolean OR of its arguments.
-func or(arg0 interface{}, args ...interface{}) (truth bool) {
-       truth, _ = isTrue(reflect.ValueOf(arg0))
-       for i := 0; !truth && i < len(args); i++ {
-               truth, _ = isTrue(reflect.ValueOf(args[i]))
+// 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
+       return arg0
 }
 
 // not returns the Boolean negation of its argument.