From 01758f99b915f34fe7ca4621e4d1ee09efe385b1 Mon Sep 17 00:00:00 2001 From: Joe Mooring Date: Thu, 27 May 2021 08:34:49 -0700 Subject: [PATCH] Add math.Max and math.Min Closes #8583 --- docs/content/en/functions/math.md | 8 ++-- tpl/math/init.go | 18 ++++++- tpl/math/math.go | 37 ++++++++++++--- tpl/math/math_test.go | 78 +++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 12 deletions(-) diff --git a/docs/content/en/functions/math.md b/docs/content/en/functions/math.md index 58cc5d5db..99b8cf34f 100644 --- a/docs/content/en/functions/math.md +++ b/docs/content/en/functions/math.md @@ -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}}` → `true` | | `math.Ceil` | Returns the least integer value greater than or equal to the given number. | `{{math.Ceil 2.1}}` → `3` | | `math.Floor` | Returns the greatest integer value less than or equal to the given number. | `{{math.Floor 1.9}}` → `1` | -| `math.Round` | Returns the nearest integer, rounding half away from zero. | `{{math.Round 1.5}}` → `2` | | `math.Log` | Returns the natural logarithm of the given number. | `{{math.Log 42}}` → `3.737` | -| `math.Sqrt` | Returns the square root of the given number. | `{{math.Sqrt 81}}` → `9` | +| `math.Max` | Returns the greater of two numbers. | `{{math.Max 1 2}}` → `2` | +| `math.Min` | Returns the smaller of two numbers. | `{{math.Min 1 2}}` → `1` | | `math.Pow` | Returns the first number raised to the power of the second number. | `{{math.Pow 2 3}}` → `8` | +| `math.Round` | Returns the nearest integer, rounding half away from zero. | `{{math.Round 1.5}}` → `2` | +| `math.Sqrt` | Returns the square root of the given number. | `{{math.Sqrt 81}}` → `9` | diff --git a/tpl/math/init.go b/tpl/math/init.go index ddbd2fc73..4d8a23fde 100644 --- a/tpl/math/init.go +++ b/tpl/math/init.go @@ -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{ diff --git a/tpl/math/math.go b/tpl/math/math.go index badc189c8..d70a3f833 100644 --- a/tpl/math/math.go +++ b/tpl/math/math.go @@ -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, '-') diff --git a/tpl/math/math_test.go b/tpl/math/math_test.go index da59d7938..45f28e093 100644 --- a/tpl/math/math_test.go +++ b/tpl/math/math_test.go @@ -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) + } +}