Add math.Max and math.Min
authorJoe Mooring <joe.mooring@veriphor.com>
Thu, 27 May 2021 15:34:49 +0000 (08:34 -0700)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 28 May 2021 18:38:45 +0000 (20:38 +0200)
Closes #8583

docs/content/en/functions/math.md
tpl/math/init.go
tpl/math/math.go
tpl/math/math_test.go

index 58cc5d5db6ea41c5540fe362085ec2056c56b9a6..99b8cf34f8c9d740d97bb80fee3088de17d7daeb 100644 (file)
@@ -1,6 +1,6 @@
 ---
 title: Math
-description: Hugo provides nine mathematical operators in templates.
+description: Hugo provides mathematical operators in templates.
 godocref:
 date: 2017-02-01
 publishdate: 2017-02-01
@@ -35,7 +35,9 @@ aliases: []
 | `modBool`    | Boolean of modulus of two integers. Evaluates to `true` if result equals 0. | `{{modBool 15 3}}` &rarr; `true` |
 | `math.Ceil`  | Returns the least integer value greater than or equal to the given number.  | `{{math.Ceil 2.1}}` &rarr; `3`   |
 | `math.Floor` | Returns the greatest integer value less than or equal to the given number.  | `{{math.Floor 1.9}}` &rarr; `1`  |
-| `math.Round` | Returns the nearest integer, rounding half away from zero.                  | `{{math.Round 1.5}}` &rarr; `2`  |
 | `math.Log`   | Returns the natural logarithm of the given number.                          | `{{math.Log 42}}` &rarr; `3.737` |
-| `math.Sqrt`  | Returns the square root of the given number.                                | `{{math.Sqrt 81}}` &rarr; `9`    |
+| `math.Max`   | Returns the greater of two numbers.                                         | `{{math.Max 1 2}}` &rarr; `2`    |
+| `math.Min`   | Returns the smaller of two numbers.                                         | `{{math.Min 1 2}}` &rarr; `1`    |
 | `math.Pow`   | Returns the first number raised to the power of the second number.          | `{{math.Pow 2 3}}` &rarr; `8`    |
+| `math.Round` | Returns the nearest integer, rounding half away from zero.                  | `{{math.Round 1.5}}` &rarr; `2`  |
+| `math.Sqrt`  | Returns the square root of the given number.                                | `{{math.Sqrt 81}}` &rarr; `9`    |
index ddbd2fc730b673fc6729c8476b0667086cde9f59..4d8a23fde56a731d0b5204f08e01edcd4aa9063d 100644 (file)
@@ -64,10 +64,17 @@ func init() {
                        },
                )
 
-               ns.AddMethodMapping(ctx.Sqrt,
+               ns.AddMethodMapping(ctx.Max,
                        nil,
                        [][2]string{
-                               {"{{math.Sqrt 81}}", "9"},
+                               {"{{math.Max 1 2 }}", "2"},
+                       },
+               )
+
+               ns.AddMethodMapping(ctx.Min,
+                       nil,
+                       [][2]string{
+                               {"{{math.Min 1 2 }}", "1"},
                        },
                )
 
@@ -106,6 +113,13 @@ func init() {
                        },
                )
 
+               ns.AddMethodMapping(ctx.Sqrt,
+                       nil,
+                       [][2]string{
+                               {"{{math.Sqrt 81}}", "9"},
+                       },
+               )
+
                ns.AddMethodMapping(ctx.Sub,
                        []string{"sub"},
                        [][2]string{
index badc189c8c6abacd4aa311d31054acd91363da38..d70a3f8332f8d17926d737180d3d8849781f1dfd 100644 (file)
@@ -71,15 +71,28 @@ func (ns *Namespace) Log(a interface{}) (float64, error) {
        return math.Log(af), nil
 }
 
-// Sqrt returns the square root of a number.
-// NOTE: will return for NaN for negative values of a
-func (ns *Namespace) Sqrt(a interface{}) (float64, error) {
-       af, err := cast.ToFloat64E(a)
-       if err != nil {
-               return 0, errors.New("Sqrt operator can't be used with non integer or float value")
+// Max returns the greater of two numbers.
+func (ns *Namespace) Max(a, b interface{}) (float64, error) {
+       af, erra := cast.ToFloat64E(a)
+       bf, errb := cast.ToFloat64E(b)
+
+       if erra != nil || errb != nil {
+               return 0, errors.New("Max operator can't be used with non-float value")
        }
 
-       return math.Sqrt(af), nil
+       return math.Max(af, bf), nil
+}
+
+// Min returns the smaller of two numbers.
+func (ns *Namespace) Min(a, b interface{}) (float64, error) {
+       af, erra := cast.ToFloat64E(a)
+       bf, errb := cast.ToFloat64E(b)
+
+       if erra != nil || errb != nil {
+               return 0, errors.New("Min operator can't be used with non-float value")
+       }
+
+       return math.Min(af, bf), nil
 }
 
 // Mod returns a % b.
@@ -135,6 +148,16 @@ func (ns *Namespace) Round(x interface{}) (float64, error) {
        return _round(xf), nil
 }
 
+// Sqrt returns the square root of a number.
+func (ns *Namespace) Sqrt(a interface{}) (float64, error) {
+       af, err := cast.ToFloat64E(a)
+       if err != nil {
+               return 0, errors.New("Sqrt operator can't be used with non integer or float value")
+       }
+
+       return math.Sqrt(af), nil
+}
+
 // Sub subtracts two numbers.
 func (ns *Namespace) Sub(a, b interface{}) (interface{}, error) {
        return _math.DoArithmetic(a, b, '-')
index da59d7938c986346d27b839b050b890b75f30c45..45f28e0939f18998bc45d0cf8dd0de13342f6143 100644 (file)
@@ -357,3 +357,81 @@ func TestPow(t *testing.T) {
                c.Assert(result, qt.Equals, test.expect)
        }
 }
+
+func TestMax(t *testing.T) {
+       t.Parallel()
+       c := qt.New(t)
+
+       ns := New()
+
+       for _, test := range []struct {
+               a      interface{}
+               b      interface{}
+               expect interface{}
+       }{
+               {-1, -1, float64(-1)},
+               {-1, 0, float64(0)},
+               {-1, 1, float64(1)},
+               {0, -1, float64(0)},
+               {0, 0, float64(0)},
+               {0, 1, float64(1)},
+               {1, -1, float64(1)},
+               {1, 0, float64(1)},
+               {1, 1, float64(1)},
+               {1.2, 1.23, float64(1.23)},
+               {-1.2, -1.23, float64(-1.2)},
+               {0, "a", false},
+               {"a", 0, false},
+               {"a", "b", false},
+       } {
+
+               result, err := ns.Max(test.a, test.b)
+
+               if b, ok := test.expect.(bool); ok && !b {
+                       c.Assert(err, qt.Not(qt.IsNil))
+                       continue
+               }
+
+               c.Assert(err, qt.IsNil)
+               c.Assert(result, qt.Equals, test.expect)
+       }
+}
+
+func TestMin(t *testing.T) {
+       t.Parallel()
+       c := qt.New(t)
+
+       ns := New()
+
+       for _, test := range []struct {
+               a      interface{}
+               b      interface{}
+               expect interface{}
+       }{
+               {-1, -1, float64(-1)},
+               {-1, 0, float64(-1)},
+               {-1, 1, float64(-1)},
+               {0, -1, float64(-1)},
+               {0, 0, float64(0)},
+               {0, 1, float64(0)},
+               {1, -1, float64(-1)},
+               {1, 0, float64(0)},
+               {1, 1, float64(1)},
+               {1.2, 1.23, float64(1.2)},
+               {-1.2, -1.23, float64(-1.23)},
+               {0, "a", false},
+               {"a", 0, false},
+               {"a", "b", false},
+       } {
+
+               result, err := ns.Min(test.a, test.b)
+
+               if b, ok := test.expect.(bool); ok && !b {
+                       c.Assert(err, qt.Not(qt.IsNil))
+                       continue
+               }
+
+               c.Assert(err, qt.IsNil)
+               c.Assert(result, qt.Equals, test.expect)
+       }
+}