abice / go-enum Goto Github PK
View Code? Open in Web Editor NEWAn enum generator for go
License: MIT License
An enum generator for go
License: MIT License
I have the following code:
// ENUM(v1 = 1)
type Version int
The full name of the version is actually x/v1
, which if used directly is kind of ugly, especially since the special characters cannot be part of the variable name.
While I can use string based enum to get around it:
// ENUM(v1 = x/v1)
type Version string
I'd love to be able to provide a string representation override to the int
version with a flag like --stringOverride='v1:x/v1'
or semantics inside the comment block itself.
You can use //go:generate go-enum -f=$GOFILE
$GOFILE
replaced by the current file name where this command is written.
For an enum like the following:
// ENUM(
// Foo1 (X),
// Foo2 (Y),
// ).
type Example string
The generated code reads:
const (
// ExampleFoo1X is a Example of type Foo1 (X.
ExampleFoo1X Example = "Foo1 (X"
// ExampleFoo2Y is a Example of type Foo2 (Y.
ExampleFoo2Y Example = "Foo2 (Y"
)
Could the issue be in that trimAllTheThings
removes )
and all subsequent characters?
While trying to transfer over some API defined ENUMs, I discovered that negative enum values are not supported:
// ENUM(Unknown = -1, Good, Bad)
type Status int
failed parsing the data part of enum value 'Unknown = -1': strconv.ParseUint: parsing "-1": invalid syntax
this is the generic definetion in the generate file.
type client interface {
kernel.Client | bootnode.Client | upgrade.Client | media.Client
}
when i use go-enum -f xxx.go
, returns this error:
Error=generate: error parsing input file 'dbc.go': dbc.go:13:16: expected ';', found '|' (and 1 more errors)
Context: a performant way to implement a set of integer enum values is to combine all the values in a single int. For example, let's say we want to implement a set of colours:
type Colour int32
const (
ColourRed Colour = 1 << iota
ColourGreen
ColourBlue
)
func main() {
colourSet := ColourRed | ColourGreen
printColours(colourSet)
}
func printColours(colourSet Colour) {
if colourSet&ColourRed != 0 {
fmt.Println("Red")
}
if colourSet&ColourGreen != 0 {
fmt.Println("Green")
}
if colourSet&ColourBlue != 0 {
fmt.Println("Blue")
}
}
It would be great to use this technique with enums generated by go-enum. However, by default the enum values are always strictly incrementing in value, rather than incrementing the bit position. I'm not sure if there is any way to override the default way that values are generated but still use the other features of the package?
When attempting to run go-enum against something that contains 2+ hyphens, it errors out. (i.e. test-multi-hyphen
) I noticed that there's a test for a trailing hyphen, but this particular case seems to be different. Example and output here.
When adhering to godot linter rules, I must add a trailing .
to the end of the ENUM(...)
. But this will result in ).
to be added to the string name:
// ENUM(1).
type Test int8
generates
const (
// Test1 is a Test of type 1)..
Test1 Test = iota
)
const _TestName = "1)."
But even worse, on a multiline variant, it will add an empty item, colliding with the type:
// ENUM(
// X
// Y
// Z
// ).
type Test int8
generates
const (
// TestX is a Test of type X.
TestX Test = iota
// TestY is a Test of type Y.
TestY
// TestZ is a Test of type Z.
TestZ
// Test is a Test of type )..
Test
)
const _TestName = "XYZ)."
I tried (to no avail) to disable godot for the ENUM line, since I find it a bit pointless. However, this does mean that it's also not possible to add some text behind the closing )
which may be useful. Especially considering ENUM(...values...)
kinda implies that parsing stops at )
Wont work always, some linux distros are having aarch64 isntead of arm64 for the uname -m
curl -fsSL "https://github.com/abice/go-enum/releases/download/$(GO_ENUM_VERSION)/go-enum_$(uname -s)_$(uname -m)" -o go-enum
*_enum.go:38:23:warning: unnecessary conversion (unconvert)
func ParseABC(name string) (ABC, error) {
if x, ok := _ABCValue[name]; ok {
return ABC(x), nil // <--
}
return ABC(0), fmt.Errorf("%s is not a valid ABC", name)
}
When I have a file foos_test.go
with:
//go:generate go-enum --marshal
package trygoenum
// ENUM(bob, alice, john, sally)
type People int
and I run go generate ./...
go-enum creates foos_test_enum.go
.
This causes go build ./...
to fail:
$ go build ./...
# try-go-enum.invalid
./foos_test_enum.go:16:12: undefined: People
./foos_test_enum.go:29:22: undefined: People
./foos_test_enum.go:37:9: undefined: People
./foos_test_enum.go:44:31: undefined: People
./foos_test_enum.go:52:32: undefined: People
./foos_test_enum.go:56:9: undefined: People
./foos_test_enum.go:60:9: undefined: People
./foos_test_enum.go:65:10: undefined: People
I would say ideally go-enum should put enums for _test.go
files in _enum_test.go
files.
Hi. I like the project. I'm wondering if you have considered or would like to have a contribution where the enum definitions are in a config file instead of in a code stub?
I think it would be quite interesting to have them defined in something similar to how go-swagger or sqlc does it.
An idea of a possible configuration file:
version: 1
enums:
- package: animal
target: internal/animal
name: Animal
type: int
alias:
"+": Plus
"#": Sharp
values:
cat:
dog:
fish:
fish++:
fish#:
- package: color
target: internal/color
name: Color
type: int
values:
Black:
White:
Red:
Green:
- value: 33
comment: Green starts with 33
Blue:
grey:
yellow:
blue-green:
red-orange:
yellow_green:
red-orange-blue:
generate:
marshal: true
lower: true
pointer: true
mustparse: true
Two questions about empty strings:
Could you please provide an "official" multi-arch docker image to use this tool? It can be simply deployed to the ghcr.io, for example. Use case - a more simple installation in the docker context, like:
COPY --from=abice/go-enum:v0.5.5 /usr/local/bin/go-enum /bin/go-enum
If you need help with it, I can make a PR with the required changes.
When using a blank value _
, the stringer output doesn't match what the actual stringer command does. Need to fix output to match.
I'm parsing an xml file format that has a lot of different enumerations and have been using go-enum with quite good success. I'm wondering if you would accept a pull request to tidy up EnumValue.Name even more?
Specifically I would like to strip out some common separators that are invalid in go identifiers like -
Currently EnumValue.Name is run through strings.Title, I think it would be relatively trivial to also strip out non-go-identifier characters at the same time.
// ParseFoo attempts to convert a string to a Foo
func ParseFoo(name string) (Foo, error) {
There should be proper punctuation here.
How do I define ENUM to achieve this?
const(
xxxDataSwap = iota
xxxBootNode
)
__Name="dataswapbootnode"
Also, can I ignore Parse's error like this:
ParseXXX(name)Type{
//return a default value
}
Hello there!
Just started to use your library and I’m missing something like —forceupper
option.
I believe many people prefer enums to have string values in uppercase, but if I put THING
in the enum comment I receive ugly SomeTHING
constant.
I see, that option forcelower
works in the way I need, but in the opposite direction.
ParseColor("chartreuse") returns Black.. that's not good. You could start the enum with like ColorNone, but that's ugly. Better to just have ParseColor return (Color, error).
// SearchPropertyType search property type
// ENUM(
// Apartment = 1
// Room
// House
// Plot
// Commercial
// Development
// )
type SearchPropertyType int32
produces error: Error=generate: error formatting code domain:358:59: expected ';', found 'IDENT' SearchPropertyType (and 4 more errors)
generated code:
const (
// SearchPropertyTypeApartment is a SearchPropertyType of type Apartment
SearchPropertyTypeApartment SearchPropertyType = iota SearchPropertyType = iota + 1
// SearchPropertyTypeRoom is a SearchPropertyType of type Room
SearchPropertyTypeRoom SearchPropertyType = iota + 1
problematic code is here: https://github.com/abice/go-enum/blob/master/generator/enum.tmpl#L17
workaround for that is to add underscore as first value:
// SearchPropertyType search property type
// ENUM(
// _
// Apartment = 1
// Room
// House
// Plot
// Commercial
// Development
// )
type SearchPropertyType int32
but it will be great if it works without the workaround
The final generated code now looks like this:
const (
// ColorBlack is a Color of type Black.
ColorBlack Color = iota
// ColorWhite is a Color of type White.
ColorWhite
// ColorRed is a Color of type Red.
ColorRed
// ColorGreen is a Color of type Green.
// Green starts with 33
ColorGreen Color = iota + 30
// ColorBlue is a Color of type Blue.
ColorBlue
// ColorGrey is a Color of type Grey.
ColorGrey
// ColorYellow is a Color of type Yellow.
ColorYellow
// ColorBlueGreen is a Color of type Blue-Green.
ColorBlueGreen
// ColorRedOrange is a Color of type Red-Orange.
ColorRedOrange
// ColorYellowGreen is a Color of type Yellow_green.
ColorYellowGreen
// ColorRedOrangeBlue is a Color of type Red-Orange-Blue.
ColorRedOrangeBlue
)
const _ColorName = "BlackWhiteRedGreenBluegreyyellowblue-greenred-orangeyellow_greenred-orange-blue"
var _ColorMap = map[Color]string{
0: _ColorName[0:5],
1: _ColorName[5:10],
2: _ColorName[10:13],
33: _ColorName[13:18],
34: _ColorName[18:22],
35: _ColorName[22:26],
36: _ColorName[26:32],
37: _ColorName[32:42],
38: _ColorName[42:52],
39: _ColorName[52:64],
40: _ColorName[64:79],
}
var _ColorValue = map[string]Color{
_ColorName[0:5]: 0,
strings.ToLower(_ColorName[0:5]): 0,
_ColorName[5:10]: 1,
strings.ToLower(_ColorName[5:10]): 1,
_ColorName[10:13]: 2,
strings.ToLower(_ColorName[10:13]): 2,
_ColorName[13:18]: 33,
strings.ToLower(_ColorName[13:18]): 33,
_ColorName[18:22]: 34,
strings.ToLower(_ColorName[18:22]): 34,
_ColorName[22:26]: 35,
strings.ToLower(_ColorName[22:26]): 35,
_ColorName[26:32]: 36,
strings.ToLower(_ColorName[26:32]): 36,
_ColorName[32:42]: 37,
strings.ToLower(_ColorName[32:42]): 37,
_ColorName[42:52]: 38,
strings.ToLower(_ColorName[42:52]): 38,
_ColorName[52:64]: 39,
strings.ToLower(_ColorName[52:64]): 39,
_ColorName[64:79]: 40,
strings.ToLower(_ColorName[64:79]): 40,
}
where the numbers are not very easy to read
I think it would be easier to read if it could look like the following:
var _ColorMap = map[Color]string{
ColorBlack: _ColorName[0:5],
ColorWhite: _ColorName[5:10],
...
}
var _ColorValue = map[string]Color{
_ColorName[0:5]: ColorBlack,
strings.ToLower(_ColorName[0:5]): ColorBlack,
_ColorName[5:10]: ColorWhite,
strings.ToLower(_ColorName[5:10]): ColorWhite,
...
Thanks for this handy tool. Do you think it is reasonable to implement the following interface so that it can be used as a Flag.
// Value is the interface to the dynamic value stored in a flag.
// (The default value is represented as a string.)
type Value interface {
String() string
Set(string) error
Type() string
}
Currently I am manually implementing this.
I want to be able to slap all my enumerations into a single folder and use a file like gen.go
to generate them. Perhaps there's something I'm missing regarding generation. But the best idea I had was to use file globbing to select all the files in the current folder for the tool. However, it does not appear to support it.
go-enum started. file: *.go
2021/03/09 15:16:59 failed generating enums
InputFile=C:\path\to\project\enums\*.go
Error=generate: error parsing input file 'C:\path\to\project\enums\*.go': open C:\path\to\project\enums\*.go: The filename, directory name, or volume label syntax is incorrect.
project\enums\gen.go:1: running "go-enum": exit status 1
Example go generate command in the enum file: go:generate go-enum -f=$GOFILE --names --nocase --noprefix --prefix=Sample
Rerunning go generate ./...
when there are no changes in that file provides a diff that wipes from of the go-enum metadata. Here is the diff:
-// Version: 0.4.0
-// Revision: 7e2e8bcd629be550028ecfcdc51cc0199ca124ad
-// Build Date: 2022-03-21T16:28:18Z
-// Built By: goreleaser
+// Version:
+// Revision:
+// Build Date:
+// Built By:
The following is an example of what is currently generated:
// ParseFoo attempts to convert a string to a Foo
func ParseFoo(name string) (Foo, error) {
if x, ok := _FooValue[name]; ok {
return x, nil
}
return Foo(0), fmt.Errorf("%s is not a valid Foo", name)
}
To ease in a common use case of wanting to panic on an error, consider also generating (behind a flag -must
?) the following:
// MustParseFoo attempts to convert a string to a Foo, panicking if unknown.
func MustParseFoo(name string) Foo {
x, err := ParseFoo(name)
if err != nil {
panic(err)
}
return x
}
--names
adds ...Names()
to get a list of enum names, but I would like to just get a list of enum values instead. I can kind of achieve the same thing by using MustParse...()
with values from ...Names()
but I would still be more comfortable just having ...Values()
.
Mainly making this issue to see how you feel about the request or if there may already be a way to do it that I don't know of.
Just tonight I am getting errors similar to
Failed writing enum data for enum: "AssociationType": template: generator:306:32: executing "stringer" at : wrong number of args for stringify: want 2 got 1
go 1.15
go-enum 0.3.10
My Makefile simply states
go get -u github.com/abice/go-enum
go generate ./...
That generates the errors as it is using V0.3.10
if I do
go get -u github.com/abice/[email protected]
go generate ./...
Then it all works as expected
Hello,
it appears v0.311 silently fails and generates no output at all with
type uint64
constant values > maxint32
First of all thanks so much for creating and maintaining this great tool!
I hope I did not just overlook this in the docs but it would be nice to have the option to change the suffix of the generated files.
So instead of <filename>_enum.go
being able change the pattern to <filename>_enum_gen.go
Maybe via an --output-suffix
flag.
I recently changed one of my enums from string
to int
and discovered that the .IsValid()
method was no longer available. It looks like it's only included in enum_string.tmpl
:
Would you be open to a PR that added it to enum.tmpl
as well?
我已经用在项目中了,特别好用!谢谢!
Looks like there's a problem with parsing when the enum is defined with /*
style comments instead of //
I have a lot of enums which need to be mapped to arbitrary strings that don't match the enum name. Am I missing a good way to handle this in the library already?
Would you be open to a PR adding optional mapping to symbols/aliases?
var _{{.enum.Name}}Symbols = map[string]{{.enum.Name}}{
{{- $vars := dict "lastoffset" 0 -}}
{{ range $rIndex, $value := .enum.Values }}
{{- $lastOffset := pluck "lastoffset" $vars | first }}{{ $offset := sub $value.Value $rIndex }}
{{- if $value.Comment}}
"{{$value.Comment}}": {{$rIndex}},
{{- end}}
{{- end}}
}
func Parse{{.enum.Name}}Symbol(bs []byte) ({{.enum.Name}}, error) {
s := string(bs)
if s == " " {
s = "SPACE"
}
if val, ok := _{{.enum.Name}}Symbols[s]; ok {
return val, nil
}
return {{.enum.Name}}(0), fmt.Errorf("'%s' is not a valid {{.enum.Name}}", string(bs))
}
/*
ENUM(
AlphaNumeric // A/N
Numeric // N
Misc // SPACE
)
*/
type FieldType int
var _FieldTypeSymbols = map[string]FieldType{
"A/N": 0,
"N": 1,
"SPACE": 2,
}
func ParseFieldTypeSymbol(bs []byte) (FieldType, error) {
s := string(bs)
if s == " " {
s = "SPACE"
}
if val, ok := _FieldTypeSymbols[s]; ok {
return val, nil
}
return FieldType(0), fmt.Errorf("'%s' is not a valid FieldType", string(bs))
}
curl -fsSL "https://github.com/abice/go-enum/releases/download/0.5.6/go-enum" -o go-enum
curl: (22) The requested URL returned error: 404
xxxx.go:1: running "go-enum": exec: "go-enum": executable file not found in $PATH
[macos monterey]
When each enum value is generated, it has a comment like so:
// ColorBlack is a Color of type Black
// My personalized comment.
ColorBlack Color = iota
However, sometimes IDEs will concatenate comments together, so that when hovering over a symbol, you see the following:
ColorBlack is a Color of type Black My personalized comment.
This is not a problem with the IDE.
The blog post Godoc: documenting Go code states:
The convention is simple: to document a type, variable, constant, function, or even a package, write a regular comment directly preceding its declaration, with no intervening blank line.
// Fprint formats using the default formats for its operands and writes to w.
Notice this comment is a complete sentence that begins with the name of the element it describes. This important convention allows us to generate documentation in a variety of formats, from plain text to HTML to UNIX man pages, and makes it read better when tools truncate it for brevity, such as when they extract the first line or sentence.
And the Contribution Guide states:
Write in complete sentences with correct punctuation, just like for your comments in Go.
The first line comment generated by go-enum should include punctuation.
The first example would become:
// ColorBlack is a Color of type Black.
// My personalized comment.
ColorBlack Color = iota
And the IDE would show:
ColorBlack is a Color of type Black. My personalized comment.
Is it possible to specify custom value for enum string ? Like this for example:
/* ENUM(
PROD = "https://prod",
DEV = "http://dev"
)
*/
type Environment string
Which could generate this
const (
PROD Environment = "https://prod"
DEV Environment = "http://dev"
)
It is necessary to use types in structures that are populated through a database
Now I'm writing this code, but it can be generated like Marshal/UnmarshalText
// ENUM(...)
type TimesheetStatus int
// Scan implements the Scanner interface.
func (x *TimesheetStatus) Scan(value interface{}) error {
var name string
switch v := value.(type) {
case string:
name = v
case []byte:
name = string(v)
case nil:
return errors.New("destination pointer is nil")
}
tmp, err := ParseTimesheetStatus(name)
if err != nil {
return err
}
*x = tmp
return nil
}
// Value implements the driver Valuer interface.
func (x TimesheetStatus) Value() (driver.Value, error) {
return x.String(), nil
}
I'm using go-enum v0.5.0 Linux x86_64
I've created an enum as such:
//go:generate go-enum -f=$GOFILE --marshal --names --nocamel --prefix TokenTypeEnum_
package tokens
/*
ENUM(
AD_HOC_USER = 1
APP_USER
OTHER
RFID
)
*/
type TokenTypeEnum uint8
By default, the --nocamel
flag gives me TokenTypeEnum<name>
but I want the constants to be named TokenTypeEnum_<name>
for readability but instead I'm getting TokenTypeEnum_TokenTypeEnum<name>
The README suggests the --prefix
flag should be replacing the existing prefix but it's not.
--noprefix
removes both prefixes
▶ go get github.com/abice/go-enum@v0.2.3
# github.com/Bowery/prompt
../../../Go/pkg/mod/github.com/!bowery/prompt@v0.0.0-20190916142128-fa8279994f75/ioctl_unix.go:25:28: undefined: unix.SYS_IOCTL
../../../Go/pkg/mod/github.com/!bowery/prompt@v0.0.0-20190916142128-fa8279994f75/ioctl_unix.go:38:28: undefined: unix.SYS_IOCTL
../../../Go/pkg/mod/github.com/!bowery/prompt@v0.0.0-20190916142128-fa8279994f75/ioctl_unix.go:55:28: undefined: unix.SYS_IOCTL
Like
ENUM(
active,
inactive, // no confirmed jobs in last 90 days
invited,
applicant,
deleted,
declined
)
Your package is not go-get-able if you don't check in your vendor directory. This is what happens right now if I try to go get your package:
go get github.com/abice/go-enum
# github.com/Masterminds/sprig
../../Masterminds/sprig/crypto.go:35:37: multiple-value uuid.NewV4() in single-value context
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.