Very often I use the stringer command to generate lists of enumerated values, which is great btw.
But one thing that I see myself also writing after this is a Parse method or function to validate strings that are received.
The
use case is that I have a list of possible values for a controlled
field in a RESTful API. I receive and deliver string values from the API
by I have a tight control inside the API itself.
I declare a
new type (generally an uint8 alias) and then declare a bunch of auto
incremental constants, starting with the zero value that I always set to
"Invalid" which is used as a control value.
The stringer
command makes the dull work but immediately after I write a Parse
function or method. The following is a full example:
//go:generate stringer -linecomment -output=enum_string.go -type=MyEnum
package enum
type MyEnum uint8
const (
// Reserved for internal use
MyEnumInvalid MyEnum = iota // Invalid
MyEnumValue1 // Value #1
MyEnumValue2 // Value #2
MyEnumValue3 // Value #3
MyEnumValue4 // Value #4
MyEnumValue5 // Value #5
)
func (e *MyEnum) Parse(value string) MyEnum {
for lenIdx, lenVal, i := len(_MyEnum_index), uint8(len(value)), 1; i < lenIdx; i++ {
if _MyEnum_index[i]-_MyEnum_index[i-1] == lenVal && // Maybe too small optimization to be perceptible/useful(?)
_MyEnum_name[_MyEnum_index[i-1]:_MyEnum_index[i]] == value {
*e = MyEnum(i - 1)
return *e
}
}
return MyEnum(0)
}
So this couples a lot to my workflow, of course. This way I can do something like:
receivedVal = new(MyEnum).Parse(receivedStr)
Or:
var val *MyEnum
for _, strVal := range strValues {
if val.Parse(strVal) == MyEnumInvalid {
return fmt.Errorf("Invalid value for enum: %v", strVal)
}
}
So
I started to write this function within the stringer command, which I
modified to do so. So I don't know if this is for some use to the
community. I know that in order for it to be useful to everyone it
should be more general. So I'm looking at alternatives and, of course,
if it's worth working on that. I it would be of some use there are two
alternatives where this could live:
- As an option to the stringer command
- As
a separate command (because it would exceed the stringer interface and
would be misleading, since "Parse" is not part of the "Stringer"
interface)
And I'm only using here the stringer command to
create series of consecutive numbers, so I would need to write extra
code to fulfill the sparsiness of values (cases where stringer creates
up to 10 different slices and after that just creates a map). It
wouldn't be much work, actually, just read the code in the command.
And
instead of writing a new method for the type (breaking the idea of the
"stringer" interface), I thought it could just be a "ParseT" function.
Thoughts? Comments? Should I keep it for myself (hahaha)?