From 55c0ce764cea5f00f90baf55b9b6c19e5b91df71 Mon Sep 17 00:00:00 2001 From: razonyang Date: Sun, 2 Jun 2024 22:24:18 +0800 Subject: [PATCH] tpl/inflect: Add the SI function to format numbers with SI notation --- tpl/inflect/inflect.go | 19 +++++++++++++++++++ tpl/inflect/inflect_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/tpl/inflect/inflect.go b/tpl/inflect/inflect.go index ef12e1bc0f3..bc3d52d8e5c 100644 --- a/tpl/inflect/inflect.go +++ b/tpl/inflect/inflect.go @@ -18,6 +18,7 @@ import ( "strconv" "strings" + _humanize "github.com/dustin/go-humanize" _inflect "github.com/gobuffalo/flect" "github.com/spf13/cast" ) @@ -73,3 +74,21 @@ func (ns *Namespace) Singularize(v any) (string, error) { return _inflect.Singularize(word), nil } + +// SI formats numbers with SI notation. +func (ns *Namespace) SI(v any, args ...any) (string, error) { + number, err := cast.ToFloat64E(v) + if err != nil { + return "", err + } + + unit := "" + if len(args) > 0 { + unit, err = cast.ToStringE(args[0]) + if err != nil { + return "", err + } + } + + return strings.TrimSuffix(_humanize.SI(number, unit), " "), nil +} diff --git a/tpl/inflect/inflect_test.go b/tpl/inflect/inflect_test.go index 083e7da4e96..9f025b15401 100644 --- a/tpl/inflect/inflect_test.go +++ b/tpl/inflect/inflect_test.go @@ -47,3 +47,38 @@ func TestInflect(t *testing.T) { c.Assert(result, qt.Equals, test.expect) } } + +func TestSI(t *testing.T) { + t.Parallel() + c := qt.New(t) + + ns := New() + + for _, test := range []struct { + in any + args []any + expect any + }{ + {12, []any{}, "12"}, + {"123", []any{}, "123"}, + {1234, []any{}, "1.234 k"}, + {"2345", []any{}, "2.345 k"}, + {1234000, []any{}, "1.234 M"}, + {"2345000", []any{}, "2.345 M"}, + {"0.00000000223", []any{"M"}, "2.23 nM"}, + {"1000000", []any{"B"}, "1 MB"}, + {"2.2345e-12", []any{"F"}, "2.2345 pF"}, + {"invalid-number", []any{}, false}, + } { + + result, err := ns.SI(test.in, test.args...) + + 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) + } +}