mirror of https://github.com/mum4k/termdash.git
Use variadic args for Value factory options
Signed-off-by: Xabier Larrakoetxea <slok69@gmail.com>
This commit is contained in:
parent
a8931e2820
commit
c1bf776dba
|
@ -73,7 +73,7 @@ type YProperties struct {
|
|||
// ScaleMode determines how the Y axis scales.
|
||||
ScaleMode YScaleMode
|
||||
// ValueFormatter is the formatter used to format numeric values to string representation.
|
||||
ValueFormatter valueFormatter
|
||||
ValueFormatter func(float64) string
|
||||
}
|
||||
|
||||
// NewYDetails retrieves details about the Y axis required to draw it on a
|
||||
|
|
|
@ -213,8 +213,8 @@ func TestY(t *testing.T) {
|
|||
End: image.Point{1, 2},
|
||||
Scale: mustNewYScale(0, 3, 2, nonZeroDecimals, YScaleModeAnchored, testValueFormatter),
|
||||
Labels: []*Label{
|
||||
{NewFormattedValue(0, nonZeroDecimals, testValueFormatter), image.Point{0, 1}},
|
||||
{NewFormattedValue(1.72, nonZeroDecimals, testValueFormatter), image.Point{0, 0}},
|
||||
{NewValue(0, nonZeroDecimals, ValueFormatter(testValueFormatter)), image.Point{0, 1}},
|
||||
{NewValue(1.72, nonZeroDecimals, ValueFormatter(testValueFormatter)), image.Point{0, 0}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -69,7 +69,7 @@ type YScale struct {
|
|||
|
||||
// valueFormatter is the value formatter used for the labels
|
||||
// represented by the values on the scale.
|
||||
valueFormatter valueFormatter
|
||||
valueFormatter func(float64) string
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
|
@ -82,7 +82,7 @@ func (ys *YScale) String() string {
|
|||
// calculated scale, see NewValue for details.
|
||||
// Max must be greater or equal to min. The graphHeight must be a positive
|
||||
// number.
|
||||
func NewYScale(min, max float64, graphHeight, nonZeroDecimals int, mode YScaleMode, valueFormatter valueFormatter) (*YScale, error) {
|
||||
func NewYScale(min, max float64, graphHeight, nonZeroDecimals int, mode YScaleMode, valueFormatter func(float64) string) (*YScale, error) {
|
||||
if max < min {
|
||||
return nil, fmt.Errorf("max(%v) cannot be less than min(%v)", max, min)
|
||||
}
|
||||
|
@ -199,12 +199,13 @@ func (ys *YScale) CellLabel(y int) (*Value, error) {
|
|||
// yScaleNewValue is a helper method to get new values for the y scale
|
||||
// that selects the correct value factory method depending on the passed
|
||||
// arguments.
|
||||
func yScaleNewValue(value float64, nonZeroDecimals int, valueFormatter valueFormatter) *Value {
|
||||
func yScaleNewValue(value float64, nonZeroDecimals int, valueFormatter func(float64) string) *Value {
|
||||
opts := []ValueOption{}
|
||||
if valueFormatter != nil {
|
||||
return NewFormattedValue(value, nonZeroDecimals, valueFormatter)
|
||||
opts = append(opts, ValueFormatter(valueFormatter))
|
||||
}
|
||||
|
||||
return NewValue(value, nonZeroDecimals)
|
||||
return NewValue(value, nonZeroDecimals, opts...)
|
||||
}
|
||||
|
||||
// XScale is the scale of the X axis.
|
||||
|
|
|
@ -22,8 +22,8 @@ import (
|
|||
)
|
||||
|
||||
// mustNewYScale returns a new YScale or panics.
|
||||
func mustNewYScale(min, max float64, graphHeight, nonZeroDecimals int, mode YScaleMode, formatter valueFormatter) *YScale {
|
||||
s, err := NewYScale(min, max, graphHeight, nonZeroDecimals, mode, formatter)
|
||||
func mustNewYScale(min, max float64, graphHeight, nonZeroDecimals int, mode YScaleMode, valueFormatter func(float64) string) *YScale {
|
||||
s, err := NewYScale(min, max, graphHeight, nonZeroDecimals, mode, valueFormatter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -23,7 +23,30 @@ import (
|
|||
"github.com/mum4k/termdash/internal/numbers"
|
||||
)
|
||||
|
||||
type valueFormatter = func(float64) string
|
||||
// ValueOption is used to provide options to the NewValue function.
|
||||
type ValueOption interface {
|
||||
// set sets the provided option.
|
||||
set(*valueOptions)
|
||||
}
|
||||
|
||||
type valueOptions struct {
|
||||
formatter func(v float64) string
|
||||
}
|
||||
|
||||
// valueOption implements ValueOption.
|
||||
type valueOption func(opts *valueOptions)
|
||||
|
||||
// set implements ValueOption.set.
|
||||
func (vo valueOption) set(opts *valueOptions) {
|
||||
vo(opts)
|
||||
}
|
||||
|
||||
// ValueFormatter sets a custom formatter for the value.
|
||||
func ValueFormatter(formatter func(float64) string) ValueOption {
|
||||
return valueOption(func(opts *valueOptions) {
|
||||
opts.formatter = formatter
|
||||
})
|
||||
}
|
||||
|
||||
// Value represents one value.
|
||||
type Value struct {
|
||||
|
@ -38,10 +61,10 @@ type Value struct {
|
|||
// NonZeroDecimals indicates the rounding precision used, it is provided on
|
||||
// a call to newValue.
|
||||
NonZeroDecimals int
|
||||
// Formatter will format value to a string representation of the value,
|
||||
// if Formatter is not present it will fallback to default format.
|
||||
Formatter valueFormatter
|
||||
|
||||
// formatter will format value to a string representation of the value,
|
||||
// if Formatter is not present it will fallback to default format.
|
||||
formatter func(float64) string
|
||||
// text value if this value was constructed using NewTextValue.
|
||||
text string
|
||||
}
|
||||
|
@ -53,20 +76,19 @@ func (v *Value) String() string {
|
|||
|
||||
// NewValue returns a new instance representing the provided value, rounding
|
||||
// the value up to the specified number of non-zero decimal places.
|
||||
func NewValue(v float64, nonZeroDecimals int) *Value {
|
||||
return NewFormattedValue(v, nonZeroDecimals, nil)
|
||||
}
|
||||
func NewValue(v float64, nonZeroDecimals int, opts ...ValueOption) *Value {
|
||||
opt := &valueOptions{}
|
||||
for _, o := range opts {
|
||||
o.set(opt)
|
||||
}
|
||||
|
||||
// NewFormattedValue returns a new instance representing the provided value,
|
||||
// using a value formatter.
|
||||
func NewFormattedValue(v float64, nonZeroDecimals int, formatter valueFormatter) *Value {
|
||||
r, zd := numbers.RoundToNonZeroPlaces(v, nonZeroDecimals)
|
||||
return &Value{
|
||||
Value: v,
|
||||
Rounded: r,
|
||||
ZeroDecimals: zd,
|
||||
NonZeroDecimals: nonZeroDecimals,
|
||||
Formatter: formatter,
|
||||
formatter: opt.formatter,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,19 +107,19 @@ func (v *Value) Text() string {
|
|||
return v.text
|
||||
}
|
||||
|
||||
if v.Formatter != nil {
|
||||
return v.Formatter(v.Value)
|
||||
if v.formatter != nil {
|
||||
return v.formatter(v.Value)
|
||||
}
|
||||
|
||||
return v.defaultFormatter(v.Rounded)
|
||||
return defaultFormatter(v.Rounded, v.NonZeroDecimals, v.ZeroDecimals)
|
||||
}
|
||||
|
||||
func (v *Value) defaultFormatter(value float64) string {
|
||||
func defaultFormatter(value float64, nonZeroDecimals, zeroDecimals int) string {
|
||||
if math.Ceil(value) == value {
|
||||
return fmt.Sprintf("%.0f", value)
|
||||
}
|
||||
|
||||
format := fmt.Sprintf("%%.%df", v.NonZeroDecimals+v.ZeroDecimals)
|
||||
format := fmt.Sprintf("%%.%df", nonZeroDecimals+zeroDecimals)
|
||||
t := fmt.Sprintf(format, value)
|
||||
if len(t) > 10 {
|
||||
t = fmt.Sprintf("%.2e", value)
|
||||
|
|
|
@ -22,10 +22,13 @@ import (
|
|||
)
|
||||
|
||||
func TestValue(t *testing.T) {
|
||||
formatter := func(float64) string { return "test" }
|
||||
|
||||
tests := []struct {
|
||||
desc string
|
||||
float float64
|
||||
nonZeroDecimals int
|
||||
formatter func(float64) string
|
||||
want *Value
|
||||
}{
|
||||
{
|
||||
|
@ -61,11 +64,24 @@ func TestValue(t *testing.T) {
|
|||
NonZeroDecimals: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "formatter value when value formatter as option",
|
||||
float: 1.01234,
|
||||
nonZeroDecimals: 0,
|
||||
formatter: formatter,
|
||||
want: &Value{
|
||||
Value: 1.01234,
|
||||
Rounded: 1.01234,
|
||||
ZeroDecimals: 1,
|
||||
NonZeroDecimals: 0,
|
||||
formatter: formatter,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
got := NewValue(tc.float, tc.nonZeroDecimals)
|
||||
got := NewValue(tc.float, tc.nonZeroDecimals, ValueFormatter(tc.formatter))
|
||||
if diff := pretty.Compare(tc.want, got); diff != "" {
|
||||
t.Errorf("NewValue => unexpected diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
|
@ -124,16 +140,3 @@ func TestNewTextValue(t *testing.T) {
|
|||
t.Errorf("v.Text => got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormattedValue(t *testing.T) {
|
||||
const (
|
||||
value = 42
|
||||
want = "test"
|
||||
)
|
||||
|
||||
v := NewFormattedValue(value, 2, func(float64) string { return "test" })
|
||||
got := v.Text()
|
||||
if got != want {
|
||||
t.Errorf("v.Text => got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue