Enumer generates Go code that adds useful methods to enums (constants with a specific type).
Given this:
//go:generate go run github.com/dmarkham/enumer@latest -type=Pill -json
type Pill int
const (
Placebo Pill = iota
Aspirin
Ibuprofen
Paracetamol
Acetaminophen = Paracetamol
)go generate writes pill_enumer.go and you can do this:
fmt.Println(Aspirin) // Aspirin
p, err := PillString("ibuprofen") // p == Ibuprofen (case-insensitive)
PillValues() // [Placebo Aspirin Ibuprofen Paracetamol]
PillStrings() // [Placebo Aspirin Ibuprofen Paracetamol]
Pill(42).IsAPill() // false
json.Marshal(Aspirin) // "Aspirin"Enumer is a drop-in replacement for stringer.
It generates the same String() method plus the extras below, so existing code keeps working.
Enumer needs Go 1.25 or newer.
The recommended setup pins enumer in go.mod as a tool dependency, so go generate works on a
fresh clone with no separate install:
go get -tool github.com/dmarkham/enumer@latest//go:generate go tool enumer -type=Pillexamples/gomods is a runnable module set up this way.
Two other options:
# Run on demand from go:generate without touching go.mod.
//go:generate go run github.com/dmarkham/enumer@latest -type=Pill
# Install a binary on your PATH.
go install github.com/dmarkham/enumer@latestPrebuilt binaries for Linux, macOS, and Windows are on the releases page.
enumer [flags] -type T [directory]
enumer [flags] -type T files... # files must be in a single package
-type is required and takes a comma-separated list of type names. Everything else is optional.
Output goes to <type>_enumer.go in the source directory, lowercased, unless you pass -output.
| Name | What it does |
|---|---|
func (i T) String() string |
Name of the value. Unknown values print as T(42). |
func TString(s string) (T, error) |
Value from its name. Matches exact name first, then lowercase. |
func TValues() []T |
All values, in declaration order. Aliases are skipped. |
func TStrings() []string |
All names, in declaration order. |
func (i T) IsAT() bool |
True if the value is one of the declared constants. |
Each flag adds the methods for one encoding. Combine as many as you need.
| Flag | Methods added | Interface |
|---|---|---|
-json |
MarshalJSON, UnmarshalJSON |
encoding/json |
-text |
MarshalText, UnmarshalText |
encoding |
-yaml |
MarshalYAML, UnmarshalYAML |
gopkg.in/yaml.v2 style, also accepted by yaml.v3 |
-sql |
Value, Scan |
database/sql/driver |
-gqlgen |
MarshalGQL, UnmarshalGQL |
gqlgen |
All of them store the enum as its string name. Unmarshaling an unknown name returns an error.
Use -text if the enum is a map key you encode as JSON. Without it, encoding/json writes the
numeric value as the key.
Scan accepts string, []byte, or any fmt.Stringer. A nil value leaves the receiver unchanged.
| Flag | What it does |
|---|---|
-values |
Adds Values() []string, which ent uses for enum fields. |
-validate |
Adds Validate() error, which returns an error when the value is not a declared constant. |
-flag.value |
Adds Set(string) error so the type satisfies flag.Value. |
-pflag.value |
Adds Set and Type() string so the type satisfies pflag.Value. Type returns all names joined by |. |
-typederrors |
Wraps conversion errors with enumerrs.ErrValueInvalid. See Typed errors. |
-linecomment |
Uses the constant's trailing line comment as its name. |
-comment |
Adds a comment line to the top of the generated file. Repeatable. |
-output |
Output file name. |
By default the string name is the Go identifier. Three flags adjust it, applied in this order:
-trimprefixremoves a prefix. Pass a comma-separated list to try several. Names without the prefix are left alone.-transformrewrites the case. See the table below.-addprefixprepends a string.
The result is what String() returns, what TString() accepts, and what every encoding uses.
Given a constant named MyTypeValue:
-transform |
Result |
|---|---|
noop (default) |
MyTypeValue |
snake |
my_type_value |
snake-upper |
MY_TYPE_VALUE |
kebab |
my-type-value |
kebab-upper |
MY-TYPE-VALUE |
dot |
my.type.value |
dot-upper |
MY.TYPE.VALUE |
whitespace |
my type value |
lower |
mytypevalue |
upper |
MYTYPEVALUE |
title |
MyTypeValue (first letter uppercased, rest unchanged) |
title-lower |
myTypeValue (first letter lowercased, rest unchanged) |
first |
M |
first-upper |
M |
first-lower |
m |
Word splitting only works from CamelCase. snake_upper, kebab_upper, dot_upper, first_upper,
and first_lower are accepted as aliases of the hyphenated names.
With -linecomment, a constant's trailing comment replaces its name. Constants without one keep
their identifier.
const (
Monday Day = iota // lunes
Tuesday
Friday // viernes
)Monday.String() returns lunes, Tuesday.String() returns Tuesday.
With -typederrors, TString(), Validate() and the unmarshal methods return an error that matches
enumerrs.ErrValueInvalid under errors.Is. The message still names the bad input.
import "github.com/dmarkham/enumer/enumerrs"
p, err := PillString("Vitamin")
if errors.Is(err, enumerrs.ErrValueInvalid) {
// "Vitamin does not belong to Pill values"
}This makes github.com/dmarkham/enumer a runtime dependency of your module, since the generated
code imports enumerrs.
Snake-case JSON for an API:
enumer -type=Status -json -transform=snakeStrip a Go-style prefix and store in a database:
enumer -type=Color -trimprefix=Color -sql -textSeveral types at once with a custom file name:
enumer -type=Pill,Day -output=enums_gen.goEnumer started as a fork of Rob Pike's stringer, was extended by Álvaro López Espinosa, and continues here. jsonenums inspired the JSON support.