Compare commits

...

113 Commits

Author SHA1 Message Date
re e3c2a6fbb2 fix 2023-01-24 19:48:57 +03:00
Dan Markham ff555f73ed
Merge pull request #71 from moritamori/fix-readme
Readme update for alternative string values flag
2022-11-19 23:05:53 -08:00
moritamori ed2895e2a7 Readme update for alternative string values flag 2022-11-13 23:41:23 +09:00
Dan Markham 71d3edd22d
Merge pull request #69 from eleduardo/publishapplesilicon
publish the apple silicon binary
2022-10-02 13:41:22 -07:00
Eduardo Solis 49441931ac
Merge branch 'master' into publishapplesilicon 2022-09-29 08:38:53 -05:00
Eduardo Solis f8c85a7a99
publish the apple silicon binary 2022-09-29 08:37:54 -05:00
Dan Markham 6e1910cc4f
Merge pull request #68 from eleduardo/go182fix
Fixing go18.2 generation due to tools breaking
2022-09-28 16:08:07 -07:00
Eduardo Solis e79db5ce74
Fixing go18.2 generation due to tools breaking 2022-09-14 15:08:55 -05:00
Dan Markham 0f231a24f5
Merge pull request #60 from urso/bump-tools-v0.1.11
Upgrade golang.org/x/tools to v0.1.11
2022-08-16 09:02:22 -07:00
urso 98641f4fd2 Upgrade golang.org/x/tools to v0.1.11 2022-06-20 13:21:50 +02:00
Dan Markham aa45c0d477
Merge pull request #59 from smlx/bump-tools
fix: upgrade golang.org/x/tools for go 1.18 compatibility
2022-04-12 07:05:12 -07:00
Scott Leggett df780b2a0e
fix: upgrade golang.org/x/tools for go 1.18 compatibility 2022-03-28 19:27:25 +08:00
Dan Markham caff60ea13
Merge pull request #58 from dmarkham/dan/go-bump
Move to go 1.17
2022-03-23 08:59:54 -07:00
Dan Markham 881cbb24bf
MOve to go 1.17 2022-03-23 08:54:45 -07:00
Dan Markham b43356ef4a
Merge pull request #54 from mieubrisse/patch-1
Add usage for module-aware generation
2022-03-23 08:54:11 -07:00
Dan Markham 3bf002e2f3
Merge branch 'master' into patch-1 2022-03-23 08:45:49 -07:00
Dan Markham 28a1efd624
Merge pull request #56 from piiano/nhaas/support_1.18
Upgrade x/tools
2022-03-23 08:45:07 -07:00
Nir Haas af60bb2988 Upgrade x/tools 2022-02-20 15:32:40 +02:00
mieubrisse a1605fba51
Add usage for module-aware generation 2022-02-04 13:25:17 -03:00
Dan Markham 585d6b237e
Merge pull request #51 from mvrahden/feature/values
Feature/values add support for ent EnumValues interface
2021-10-26 13:00:42 -07:00
Menno 67b1febc1d fix comment 2021-10-17 14:32:26 +02:00
Menno 074b95bab8 add documentation for alternative string values flag 2021-10-17 14:32:13 +02:00
Menno f80c486834 add alternative string values method 2021-10-17 14:31:43 +02:00
Dan Markham 328a338ddb
Merge pull request #48 from dmarkham/dan/apple-m1
Adding support for Apple arm64
2021-07-26 08:00:24 -07:00
Dan Markham 367f14bcb1
Adding support for Apple arm64 2021-07-21 23:41:59 -07:00
Dan Markham 9d0b7d4c67
Merge pull request #44 from dmarkham/dan/issue-43
Return the same string passed for error
2021-07-21 23:20:05 -07:00
Dan Markham b85f109b7f
Return the same string passed for error
Fixes Issue #43
2021-07-21 23:11:39 -07:00
Dan Markham 677b61cc2c
Merge pull request #41 from dmarkham/readme-update
Readme update
2021-01-31 09:45:39 -08:00
Dan Markham be4c11f837
Move to go1.15.x 2021-01-30 23:39:52 -08:00
Dan Markham 2479605aa2
Readme update 2021-01-30 23:37:57 -08:00
Dan Markham b96c3ca7db
Merge pull request #39 from vladimiroff/gqlgen
Add flag for generating gqlgen marshaling methods
2021-01-30 23:24:15 -08:00
Kiril Vladimiroff 67e4e9619f Add flag for generating gqlgen marshaling methods 2020-09-18 16:35:44 +03:00
Dan Markham 67fb6efca7
Merge pull request #38 from dmarkham/dan-fix-case-insensitive
case insensitive bug fix
2020-08-08 21:35:08 -07:00
Dan Markham eb484e6440
case insensitive bug fix 2020-08-08 21:23:56 -07:00
Dan Markham 0a1f0e6d70
Merge pull request #36 from dmarkham/golang-bump
golang 1.14
2020-06-09 14:40:58 -07:00
Dan Markham be960ad5f1
golang 1.14 2020-06-09 13:45:55 -07:00
Dan Markham 5c8e883cf6
Merge pull request #35 from xescugc/fg-34
Fixed: Error when transformer emptied the values
2020-06-09 13:11:03 -07:00
xescugc cb6196db58 stringer: Add logic to fail if transformer empties value
If the output of the transformer is '' means that something went wrong (if it had a value before) and so
it needs to fail to not conntinue with silence errors
2020-06-08 21:31:25 +02:00
xescugc 20d9792920 golden_test: Add test for 'linecomment'
It'll fix https://github.com/dmarkham/enumer/issues/27 as it includes the golden
test for it
2020-06-08 20:16:02 +02:00
Dan Markham 9741c5ae47
Merge pull request #33 from dmarkham/sql-typeo
typeo in the template var
2020-03-16 12:27:02 -07:00
Dan Markham 017d714532
typeo in the template var 2020-03-16 10:52:02 -07:00
Dan Markham 3100ad138c
Merge pull request #32 from vladimiroff/scan-type
Implement Scan with a type switch
2020-03-15 23:18:03 -07:00
Kiril Vladimiroff 78ada3fc29
Implement Scan with a type switch
This is just a minor (and a bit opinionated) tweak in Scan. While using
the generated Scan method, realized that what's being returned from any
driver I've stumbled upon is actually []byte instead of string, thus
always causing a one failed type assertion on Scan.
2020-03-05 16:18:52 +02:00
Dan Markham d46c853929
Merge pull request #30 from dmarkham/use-constant-names
Use constant names, Help the compiler detect value changes
2020-02-23 23:11:09 -08:00
Dan Markham 8d7221cc8a
enum value change detector 2020-02-23 22:47:17 -08:00
Dan Markham 9793e421ce
use constant names 2020-02-23 15:24:20 -08:00
Dan Markham 56342fda5f
Merge pull request #29 from dmarkham/multi-prefix
Allow multiple trim prefixes
2020-02-23 13:55:50 -08:00
Dan Markham df8df69062
Update Deps 2020-02-23 13:45:14 -08:00
Dan Markham f6864bbebc
Move to go 1.13.x for default build 2020-02-23 13:30:45 -08:00
Dan Markham 49fa643993
Allow multiple trim prefixes
based on changes from @sgtsquiggs
2020-02-23 13:24:02 -08:00
Dan Markham f93c6b0e0b
Merge pull request #24 from dmarkham/port-runs-threshold-bug
Port runs threshold bug
2019-07-18 08:19:26 -07:00
Dan Markham cdbbf12521
Port fix from @ltpquang 2019-07-18 08:06:39 -07:00
Quang Le 1467a49eb3
Add test cases that make the endtoend test failed 2019-07-18 08:05:55 -07:00
Quang Le 0bc4e9e23e
Fix typos 2019-07-18 08:05:50 -07:00
Dan Markham 2440b832e4
Merge pull request #23 from dmarkham/doc
Doc updates around <Type>String(s string) Case Insensitive
2019-05-05 15:24:55 -07:00
Dan Markham 14261a8f07
Doc updates around <Type>String(s string) Case Insensitive 2019-05-05 15:07:38 -07:00
Dan Markham e080e58c1e
Merge pull request #22 from dmarkham/case-insensitive-name
Make PillString case insensitive
2019-05-05 14:51:03 -07:00
Dan Markham 2a31c850ad
Make PillString case insensitive
fixes #21
2019-05-04 15:33:34 -07:00
Dan Markham f993037eaa
Merge pull request #20 from dmarkham/docs-update
Adding in the Usage
2019-04-24 22:51:19 -07:00
Dan Markham ae561ba734
Adding in the Usage 2019-04-23 21:21:16 -07:00
Dan Markham c504b164b0
Merge pull request #19 from dmarkham/linecomment
Line comment support #18
2019-04-23 15:22:57 -07:00
Dan Markham ccf4a55cf2
Line comment support #18 2019-04-23 15:13:34 -07:00
Dan Markham 325a6e167c
Merge pull request #17 from mvrhov/patch-1
Create temporary file in same directory as the final fiel resides
2019-04-19 00:02:44 -07:00
Miha Vrhovnik ceea85e531
Create temporary file in same directory as the final fiel resides
If temp file is created on different parition, then move command will fail
2019-04-19 08:38:40 +02:00
Dan Markham 1cbec6c016
Merge pull request #15 from dmarkham/readme-updates
Add a example for go mods use
2019-04-08 00:20:15 -07:00
Dan Markham 24de023e5c
Add a example for go mods use 2019-04-07 23:56:38 -07:00
Dan Markham a6b59c2799
Merge pull request #13 from dmarkham/dmarkham-readme
Update README.md
2019-04-07 23:12:50 -07:00
Dan Markham cc772a950e
Merge branch 'master' into dmarkham-readme 2019-04-07 22:55:14 -07:00
Dan Markham 46e7802ac4
Merge pull request #14 from dmarkham/travis-dist-change
use xenial in travis
2019-04-07 22:55:03 -07:00
Dan Markham 66589be05d
use xenial in travis 2019-04-07 22:40:50 -07:00
Dan Markham 49d05009d0
Update README.md 2019-04-07 20:02:31 -07:00
Dan Markham 579c571630
Merge pull request #12 from dmarkham/readme-updates
Readme updates
2019-04-05 06:52:10 -07:00
Dan Markham 76fd2e5795
update 2019-04-05 01:57:06 -07:00
Dan Markham 04ed547ca1
Merge pull request #11 from dmarkham/coverage
Getting coverage setup
2019-04-05 01:41:58 -07:00
Dan Markham 5dff465061
Getting coverage setup 2019-04-05 01:30:06 -07:00
Dan Markham cff78b5241
Merge pull request #10 from dmarkham/travis-setup
testing and deploy with travis
2019-04-05 01:10:09 -07:00
Dan Markham a34ce5a636
testing and deploy with travis 2019-04-05 00:59:36 -07:00
Dan Markham 2d3b4cc0c7
Merge pull request #9 from dmarkham/travis-setup
testing a deploy with travis
2019-04-05 00:04:06 -07:00
Dan Markham f524145d2a
testing a deploy with travis 2019-04-04 23:54:40 -07:00
Dan Markham 988c3334e5
Merge pull request #8 from dmarkham/readme
Updates to the readme
2019-04-04 23:02:50 -07:00
Dan Markham 07dc9c9dbe
Updates to the readme 2019-04-04 22:53:44 -07:00
Dan Markham 296228769d
Merge pull request #7 from dmarkham/new-comment
Only add the comment line when there is a comment
2019-04-04 18:52:02 -07:00
Dan Markham 58249b251f
Only add the comment line when there is a comment 2019-04-04 18:48:04 -07:00
Dan Markham 610f60356d
Merge pull request #6 from dmarkham/whitespace-docs
Whitespace + docs
2019-04-04 18:03:35 -07:00
Dan Markham 107292ddbc
resolve some conflicts 2019-04-04 17:57:54 -07:00
Dan Markham 72a8443d38
Merge pull request #5 from dmarkham/serjlee
Serjlee
2019-04-04 17:15:40 -07:00
Dan Markham f8e96284fe
Merging in serjlee 2019-04-04 17:11:33 -07:00
Dan Markham 586f4733ff
adding in sum 2019-04-04 17:09:21 -07:00
Dan Markham d82b2b06c1
Merge pull request #4 from dmarkham/comments-tmpfile
Comments tmpfile
2019-04-04 16:36:31 -07:00
Dan Markham 1c1330394d
fix merge conflicts 2019-04-04 16:33:59 -07:00
Dan Markham ad406c3e36
Merge pull request #3 from dmarkham/go-modules
Go modules
2019-04-04 16:24:30 -07:00
Dan Markham ecea0f4d48
Remove vendor directory 2019-04-04 16:21:39 -07:00
amanbolat b0dd5b45a5
update to work with go modules 2019-04-04 15:57:51 -07:00
amanbolat bbb4825a38
added usage 2019-04-04 15:57:38 -07:00
amanbolat c7302601d6
remove importers 2019-04-04 15:57:37 -07:00
Dan Markham 2c68820d0e
Merge pull request #2 from dmarkham/fix-non-windows
Fix non windows
2019-04-04 15:47:42 -07:00
Dan Markham fd4c1a3913
Merge remote-tracking branch 'origin/master' into fix-non-windows 2019-04-04 15:44:34 -07:00
Dan Markham da2df55c39
Merge pull request #1 from dmarkham/travis
Adding in travis
2019-04-04 15:42:06 -07:00
Dan Markham 8d88862e90
Addwing in travis 2019-04-04 15:38:58 -07:00
Luca Osti 63cd80f057 Add method for getting a slice of strings 2019-03-22 12:56:38 +01:00
Luca Osti 188f5ebedc Add title-lower transform 2019-03-22 11:37:02 +01:00
Luca Osti d806ebd41f Add test 2019-03-22 11:36:20 +01:00
Luca Osti 5511caae23 Add prefix after transform 2019-03-22 11:36:16 +01:00
Luca Osti ea11b04142 Add withprefix flag 2019-03-22 10:54:07 +01:00
Chris Raborg fdd0a4e9d9
Merge pull request #3 from mgaffney/fix-generated-docs
Fix generated comments
2019-03-02 10:36:55 -05:00
Michael Gaffney f84898d4c3
Fix generated comments
- Add missing punctuation marks.
- Make comments more consistent with comments for similar functions
  in the standard library.
2019-03-01 15:36:43 -05:00
Chris Raborg da4a0ea77c
Merge pull request #1 from zerofox-oss/whitespace-sep
Whitespace sep
2019-02-12 12:46:45 -05:00
Xopherus 6ec30747dc Add whitespace-separated transformation 2019-02-12 12:35:47 -05:00
Chris Raborg d6fc475549
Merge pull request #2 from zerofox-oss/add-transformations
Add Transformers
2019-02-12 12:33:58 -05:00
G.J.R. Timmer 42bd8ecbf7 Merge branch 'add-transformations' into 'master'
Add Transformers

See merge request go/enumer!2
2019-01-17 13:13:07 +01:00
G.J.R. Timmer 06f7d9e03c Merge branch 'fix-non-windows' into 'master'
Fix End2End test for non-windows platforms

See merge request go/enumer!1
2019-01-17 13:12:47 +01:00
Gert-Jan Timmer 78452a952a Add Transformers
- snake-upper
- kebab-upper
- lower (Lowercase)
- upper (Uppercase)
- title (TitleCase)
- first (Use first character of string)
- first-lower (same as first only lower case)
- first-upper (same as first only upper case)
2019-01-17 13:07:52 +01:00
Gert-Jan Timmer 16ae335f48 Fix End2End test for non-windows platforms
Binary name for string was hardcoded to `.exe`
2019-01-16 18:06:03 +01:00
57 changed files with 3227 additions and 1292 deletions

7
.gitignore vendored
View File

@ -4,7 +4,7 @@
*.o *.o
*.a *.a
*.so *.so
cli
# Folders # Folders
_obj _obj
_test _test
@ -20,9 +20,12 @@ _cgo_gotypes.go
_cgo_export.* _cgo_export.*
_testmain.go _testmain.go
coverage.txt
*.exe *.exe
*.test *.test
*.prof *.prof
.idea .idea
.vscode
enumer

29
.travis.yml Normal file
View File

@ -0,0 +1,29 @@
language: go
dist: xenial
matrix:
allow_failures:
- go: master
include:
- go: 1.17.x
- go: 1.18.x
env:
global:
- GO111MODULE=on
after_success:
- make build-cli
- bash <(curl -s https://codecov.io/bash)
deploy:
provider: releases
api_key:
secure: VnwZNdY9ryTKIStuy8vJUq3QwyDQe9RVstjLB6kdSj+LE9bg6MDOSYtoN/ricdL0xqYctvYTWpWrt4TNzGOgrzRPV6EriMs0dy4JL1Q+teKWM1Q7/AwTZqINZ4SbczibX+Y66BqB39Ca5+b8Qg6ijP2wu1Yiss9ro9XIdVvNib4/tg1bas1JtDueGTJPm3wYIMexNHP+nGqo6LCSoAO1ul6aEnGb0JlHQkdUKNT05XAQXcNwzuylQ+ckfttMTeBJkeag5xl20hh0g7EYUh+JtQkfkfazyug5PqjO+nxHfdHn1EHq5CTX679UTOM/0EIXqC8LyKIux0p2+4cufAwuArsw9X0e0ui3qL0389Ac+6D3F0fC6we4/BDT79C1DBpdw+eK+wO2roWqSGRymlhbjG5sVmYERDF831OdAy8/7w+pI3NKlGL+BiYEjhRKR33ldRuwf8X82MtWJCVht67guxLHSq09HE9i774yP0aw3h4LmeI2lGdVD2tsb/awhjVnNL3jMylimU7am2qW6Kb6hGXMv8WENX5QmpgXkm0VUT2TCopKjL6fOefJYW0FpPJjb9wFrSdT7csXwu/XhoQTnNBMEKc1FDqX9pb2m/BNvHAnZdwawBS9ysLnMcORGL11Wql+p1D1xfvIGFB1rQs/xdPRJ0/pao+cS6+hLxi1fyI=
skip_cleanup: true
file:
- cli/build/enumer.linux-amd64.tar.gz
- cli/build/enumer.darwin-amd64.tar.gz
- cli/build/enumer.darwin-arm64.tar.gz
- cli/build/enumer.windows-amd64.exe.tar.gz
- cli/build/sha256sum.txt
on:
go: 1.17.x
repo: dmarkham/enumer
tags: true

26
Makefile Normal file
View File

@ -0,0 +1,26 @@
test:
go test -race -coverprofile=coverage.txt -covermode=atomic
build-cli: clean
-mkdir -p ./cli/build
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o ./cli/build/enumer.linux-amd64 .
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -a -o ./cli/build/enumer.darwin-amd64 .
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -a -o ./cli/build/enumer.darwin-arm64 .
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -a -o ./cli/build/enumer.windows-amd64.exe .
cd ./cli/build && find . -name 'enumer*' | xargs -I{} tar czf {}.tar.gz {}
cd ./cli/build && shasum -a 256 * > sha256sum.txt
cat ./cli/build/sha256sum.txt
# example: make release V=0.0.0
release:
git tag v$(V)
@read -p "Press enter to confirm and push to origin ..." && git push origin v$(V)
clean:
-rm -r ./cli/build
SHELL = /bin/bash

141
README.md
View File

@ -1,32 +1,80 @@
# Enumer [![GoDoc](https://godoc.org/github.com/alvaroloes/enumer?status.svg)](https://godoc.org/github.com/alvaroloes/enumer) [![Go Report Card](https://goreportcard.com/badge/github.com/alvaroloes/enumer)](https://goreportcard.com/report/github.com/alvaroloes/enumer) [![cover.run go](https://cover.run/go/github.com/alvaroloes/enumer.svg?tag=golang-1.10)](https://cover.run/go/github.com/alvaroloes/enumer?tag=golang-1.10) # Enumer [![GoDoc](https://godoc.org/git.internal/re/enumer?status.svg)](https://godoc.org/git.internal/re/enumer) [![Go Report Card](https://goreportcard.com/badge/git.internal/re/enumer)](https://goreportcard.com/report/git.internal/re/enumer) [![GitHub Release](https://img.shields.io/github/release/dmarkham/enumer.svg)](https://git.internal/re/enumer/releases)[![Build Status](https://travis-ci.com/dmarkham/enumer.svg?branch=master)](https://travis-ci.com/dmarkham/enumer)
Enumer is a tool to generate Go code that adds useful methods to Go enums (constants with a specific type). Enumer is a tool to generate Go code that adds useful methods to Go enums (constants with a specific type).
It started as a fork of [Rob Pikes Stringer tool](https://godoc.org/golang.org/x/tools/cmd/stringer). It started as a fork of [Rob Pikes Stringer tool](https://godoc.org/golang.org/x/tools/cmd/stringer)
maintained by [Álvaro López Espinosa](https://github.com/alvaroloes/enumer).
This was again forked here as (https://git.internal/re/enumer) picking up where Álvaro left off.
```
$ ./enumer --help
Enumer is a tool to generate Go code that adds useful methods to Go enums (constants with a specific type).
Usage of ./enumer:
Enumer [flags] -type T [directory]
Enumer [flags] -type T files... # Must be a single package
For more information, see:
http://godoc.org/git.internal/re/enumer
Flags:
-addprefix string
transform each item name by adding a prefix. Default: ""
-comment value
comments to include in generated code, can repeat. Default: ""
-gqlgen
if true, GraphQL marshaling methods for gqlgen will be generated. Default: false
-json
if true, json marshaling methods will be generated. Default: false
-linecomment
use line comment text as printed text when present
-output string
output file name; default srcdir/<type>_string.go
-sql
if true, the Scanner and Valuer interface will be implemented.
-text
if true, text marshaling methods will be generated. Default: false
-transform string
enum item name transformation method. Default: noop (default "noop")
-trimprefix string
transform each item name by removing a prefix. Default: ""
-type string
comma-separated list of type names; must be set
-values
if true, alternative string values method will be generated. Default: false
-yaml
if true, yaml marshaling methods will be generated. Default: false
```
## Generated functions and methods ## Generated functions and methods
When Enumer is applied to a type, it will generate: When Enumer is applied to a type, it will generate:
* The following basic methods/functions: - The following basic methods/functions:
- Method `String()`: returns the string representation of the enum value. This makes the enum conform
the `Stringer` interface, so whenever you print an enum value, you'll get the string name instead of a number.
- Function `<Type>String(s string)`: returns the enum value from its string representation. This is useful
when you need to read enum values from command line arguments, from a configuration file, or
from a REST API request... In short, from those places where using the real enum value (an integer) would
be almost meaningless or hard to trace or use by a human. `s` string is Case Insensitive.
- Function `<Type>Values()`: returns a slice with all the values of the enum
- Function `<Type>Strings()`: returns a slice with all the Strings of the enum
- Method `IsA<Type>()`: returns true only if the current value is among the values of the enum. Useful for validations.
- When the flag `json` is provided, two additional methods will be generated, `MarshalJSON()` and `UnmarshalJSON()`. These make
the enum conform to the `json.Marshaler` and `json.Unmarshaler` interfaces. Very useful to use it in JSON APIs.
- When the flag `text` is provided, two additional methods will be generated, `MarshalText()` and `UnmarshalText()`. These make
the enum conform to the `encoding.TextMarshaler` and `encoding.TextUnmarshaler` interfaces.
**Note:** If you use your enum values as keys in a map and you encode the map as _JSON_, you need this flag set to true to properly
convert the map keys to json (strings). If not, the numeric values will be used instead
- When the flag `yaml` is provided, two additional methods will be generated, `MarshalYAML()` and `UnmarshalYAML()`. These make
the enum conform to the `gopkg.in/yaml.v2.Marshaler` and `gopkg.in/yaml.v2.Unmarshaler` interfaces.
- When the flag `sql` is provided, the methods for implementing the `Scanner` and `Valuer` interfaces.
Useful when storing the enum in a database.
* Method `String()`: returns the string representation of the enum value. This makes the enum conform
the `Stringer` interface, so whenever you print an enum value, you'll get the string name instead of a number.
* Function `<Type>String(s string)`: returns the enum value from its string representation. This is useful
when you need to read enum values from command line arguments, from a configuration file, or
from a REST API request... In short, from those places where using the real enum value (an integer) would
be almost meaningless or hard to trace or use by a human.
* Function `<Type>Values()`: returns a slice with all the values of the enum
* Method `IsA<Type>()`: returns true only if the current value is among the values of the enum. Useful for validations.
* When the flag `json` is provided, two additional methods will be generated, `MarshalJSON()` and `UnmarshalJSON()`. These make
the enum conform to the `json.Marshaler` and `json.Unmarshaler` interfaces. Very useful to use it in JSON APIs.
* When the flag `text` is provided, two additional methods will be generated, `MarshalText()` and `UnmarshalText()`. These make
the enum conform to the `encoding.TextMarshaler` and `encoding.TextUnmarshaler` interfaces.
**Note:** If you use your enum values as keys in a map and you encode the map as _JSON_, you need this flag set to true to properly
convert the map keys to json (strings). If not, the numeric values will be used instead
* When the flag `yaml` is provided, two additional methods will be generated, `MarshalYAML()` and `UnmarshalYAML()`. These make
the enum conform to the `gopkg.in/yaml.v2.Marshaler` and `gopkg.in/yaml.v2.Unmarshaler` interfaces.
* When the flag `sql` is provided, the methods for implementing the Scanner and Valuer interfaces will be also generated.
Useful when storing the enum in a database.
For example, if we have an enum type called `Pill`, For example, if we have an enum type called `Pill`,
```go ```go
type Pill int type Pill int
@ -38,7 +86,9 @@ const (
Acetaminophen = Paracetamol Acetaminophen = Paracetamol
) )
``` ```
executing `enumer -type=Pill -json` will generate a new file with four basic methods and two extra for JSON: executing `enumer -type=Pill -json` will generate a new file with four basic methods and two extra for JSON:
```go ```go
func (i Pill) String() string { func (i Pill) String() string {
//... //...
@ -52,6 +102,10 @@ func PillValues() []Pill {
//... //...
} }
func PillStrings() []string {
//...
}
func (i Pill) IsAPill() bool { func (i Pill) IsAPill() bool {
//... //...
} }
@ -64,7 +118,9 @@ func (i *Pill) UnmarshalJSON(data []byte) error {
//... //...
} }
``` ```
From now on, we can: From now on, we can:
```go ```go
// Convert any Pill value to string // Convert any Pill value to string
var aspirinString string = Aspirin.String() var aspirinString string = Aspirin.String()
@ -72,7 +128,7 @@ var aspirinString string = Aspirin.String()
fmt.Println("I need ", Paracetamol) // Will print "I need Paracetamol" fmt.Println("I need ", Paracetamol) // Will print "I need Paracetamol"
// Convert a string with the enum name to the corresponding enum value // Convert a string with the enum name to the corresponding enum value
pill, err := PillString("Ibuprofen") pill, err := PillString("Ibuprofen") // "ibuprofen" will also work.
if err != nil { if err != nil {
fmt.Println("Unrecognized pill: ", err) fmt.Println("Unrecognized pill: ", err)
return return
@ -112,30 +168,55 @@ name := MyTypeValue.String() // name => "MyTypeValue"
Sometimes you need to use some other string representation format than CamelCase (i.e. in JSON). Sometimes you need to use some other string representation format than CamelCase (i.e. in JSON).
To transform it from CamelCase to snake_case or kebab-case, you can use the `transform` flag. To transform it from CamelCase to another format, you can use the `transform` flag.
For example, the command `enumer -type=MyType -json -transform=snake` would generate the following string representation: For example, the command `enumer -type=MyType -json -transform=snake` would generate the following string representation:
```go ```go
name := MyTypeValue.String() // name => "my_type_value" name := MyTypeValue.String() // name => "my_type_value"
``` ```
**Note**: The transformation only works form CamelCase to snake_case or kebab-case, not the other way around.
**Note**: The transformation only works from CamelCase to snake_case or kebab-case, not the other way around.
### Transformers
- snake
- snake-upper
- kebab
- kebab-upper
- lower (lowercase)
- upper (UPPERCASE)
- title (TitleCase)
- title-lower (titleCase)
- first (Use first character of string)
- first-lower (same as first only lower case)
- first-upper (same as first only upper case)
- whitespace
## How to use ## How to use
The usage of Enumer is the same as Stringer, so you can refer to the [Stringer docs](https://godoc.org/golang.org/x/tools/cmd/stringer)
for more information. For a module-aware repo with `enumer` in the `go.mod` file, generation can be called by adding the following to a `.go` source file:
```golang
//go:generate go run git.internal/re/enumer -type=YOURTYPE
```
There are four boolean flags: `json`, `text`, `yaml` and `sql`. You can use any combination of them (i.e. `enumer -type=Pill -json -text`), There are four boolean flags: `json`, `text`, `yaml` and `sql`. You can use any combination of them (i.e. `enumer -type=Pill -json -text`),
For enum string representation transformation the `transform` and `trimprefix` flags For enum string representation transformation the `transform` and `trimprefix` flags
were added (i.e. `enumer -type=MyType -json -transform=snake`). were added (i.e. `enumer -type=MyType -json -transform=snake`).
Possible transform values are `snake` and `kebab` for transformation to snake_case and kebab-case accordingly. Possible transform values are listed above in the [transformers](#transformers) section.
The default value for `transform` flag is `noop` which means no transformation will be performed. The default value for `transform` flag is `noop` which means no transformation will be performed.
If a prefix is provided via the `trimprefix` flag, it will be trimmed from the start of each name (before If a prefix is provided via the `trimprefix` flag, it will be trimmed from the start of each name (before
it is transformed). If a name doesn't have the prefix it will be passed unchanged. it is transformed). If a name doesn't have the prefix it will be passed unchanged.
If a prefix is provided via the `addprefix` flag, it will be added to the start of each name (after trimming and after transforming).
The boolean flag `values` will additionally create an alternative string values method `Values() []string` to fullfill the `EnumValues` interface of [ent](https://entgo.io/docs/schema-fields/#enum-fields).
## Inspiring projects ## Inspiring projects
* [Stringer](https://godoc.org/golang.org/x/tools/cmd/stringer)
* [jsonenums](https://github.com/campoy/jsonenums) - [Álvaro López Espinosa](https://github.com/alvaroloes/enumer)
- [Stringer](https://godoc.org/golang.org/x/tools/cmd/stringer)
- [jsonenums](https://github.com/campoy/jsonenums)

View File

@ -16,10 +16,24 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"testing" "testing"
) )
var (
// GOEXE defines the executable file name suffix (".exe" on Windows, "" on other systems).
// Must be defined here, cannot be read from ENVIRONMENT variables
GOEXE = ""
)
func init() {
// Set GOEXE for Windows platform
if runtime.GOOS == "windows" {
GOEXE = ".exe"
}
}
// This file contains a test that compiles and runs each program in testdata // This file contains a test that compiles and runs each program in testdata
// after generating the string method for its type. The rule is that for testdata/x.go // after generating the string method for its type. The rule is that for testdata/x.go
// we run stringer -type X and then compile and run the program. The resulting // we run stringer -type X and then compile and run the program. The resulting
@ -31,8 +45,9 @@ func TestEndToEnd(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
// Create stringer in temporary directory. // Create stringer in temporary directory.
stringer := filepath.Join(dir, "stringer.exe") stringer := filepath.Join(dir, fmt.Sprintf("stringer%s", GOEXE))
err = run("go", "build", "-o", stringer) err = run("go", "build", "-o", stringer)
if err != nil { if err != nil {
t.Fatalf("building stringer: %s", err) t.Fatalf("building stringer: %s", err)
@ -50,20 +65,54 @@ func TestEndToEnd(t *testing.T) {
// Generate, compile, and run the test programs. // Generate, compile, and run the test programs.
for _, name := range names { for _, name := range names {
if !strings.HasSuffix(name, ".go") { if !strings.HasSuffix(name, ".go") {
t.Errorf("%s is not a Go file", name)
continue continue
} }
if name == "cgo.go" && !build.Default.CgoEnabled { if name == "cgo.go" && !build.Default.CgoEnabled {
t.Logf("cgo is no enabled for %s", name) t.Logf("cgo is no enabled for %s", name)
continue continue
} }
// Names are known to be ASCII and long enough.
typeName := fmt.Sprintf("%c%s", name[0]+'A'-'a', name[1:len(name)-len(".go")])
transformNameMethod := "noop"
if name == "transform.go" { // Names are known to be ASCII and long enough.
typeName = "CamelCaseValue" var typeName string
var transformNameMethod string
switch name {
case "transform_snake.go":
typeName = "SnakeCaseValue"
transformNameMethod = "snake" transformNameMethod = "snake"
case "transform_snake_upper.go":
typeName = "SnakeUpperCaseValue"
transformNameMethod = "snake-upper"
case "transform_kebab.go":
typeName = "KebabCaseValue"
transformNameMethod = "kebab"
case "transform_kebab_upper.go":
typeName = "KebabUpperCaseValue"
transformNameMethod = "kebab-upper"
case "transform_upper.go":
typeName = "UpperCaseValue"
transformNameMethod = "upper"
case "transform_lower.go":
typeName = "LowerCaseValue"
transformNameMethod = "lower"
case "transform_title.go":
typeName = "TitleCaseValue"
transformNameMethod = "title"
case "transform_first.go":
typeName = "FirstCaseValue"
transformNameMethod = "first"
case "transform_first_upper.go":
typeName = "FirstUpperCaseValue"
transformNameMethod = "first-upper"
case "transform_first_lower.go":
typeName = "FirstLowerCaseValue"
transformNameMethod = "first-lower"
case "transform_whitespace.go":
typeName = "WhitespaceSeparatedValue"
transformNameMethod = "whitespace"
default:
typeName = fmt.Sprintf("%c%s", name[0]+'A'-'a', name[1:len(name)-len(".go")])
transformNameMethod = "noop"
} }
stringerCompileAndRun(t, dir, stringer, typeName, name, transformNameMethod) stringerCompileAndRun(t, dir, stringer, typeName, name, transformNameMethod)
@ -111,7 +160,14 @@ func copy(to, from string) error {
// run runs a single command and returns an error if it does not succeed. // run runs a single command and returns an error if it does not succeed.
// os/exec should have this function, to be honest. // os/exec should have this function, to be honest.
func run(name string, arg ...string) error { func run(name string, arg ...string) error {
return runInDir(".", name, arg...)
}
// runInDir runs a single command in directory dir and returns an error if
// it does not succeed.
func runInDir(dir, name string, arg ...string) error {
cmd := exec.Command(name, arg...) cmd := exec.Command(name, arg...)
cmd.Dir = dir
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
return cmd.Run() return cmd.Run()

View File

@ -10,6 +10,10 @@ func %[1]sString(s string) (%[1]s, error) {
if val, ok := _%[1]sNameToValueMap[s]; ok { if val, ok := _%[1]sNameToValueMap[s]; ok {
return val, nil return val, nil
} }
if val, ok := _%[1]sNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%%s does not belong to %[1]s values", s) return 0, fmt.Errorf("%%s does not belong to %[1]s values", s)
} }
` `
@ -22,6 +26,16 @@ func %[1]sValues() []%[1]s {
} }
` `
// Arguments to format are:
// [1]: type name
const stringsMethod = `// %[1]sStrings returns a slice of all String values of the enum
func %[1]sStrings() []string {
strs := make([]string, len(_%[1]sNames))
copy(strs, _%[1]sNames)
return strs
}
`
// Arguments to format are: // Arguments to format are:
// [1]: type name // [1]: type name
const stringBelongsMethodLoop = `// IsA%[1]s returns "true" if the value is listed in the enum definition. "false" otherwise const stringBelongsMethodLoop = `// IsA%[1]s returns "true" if the value is listed in the enum definition. "false" otherwise
@ -44,6 +58,18 @@ func (i %[1]s) IsA%[1]s() bool {
} }
` `
// Arguments to format are:
// [1]: type name
const altStringValuesMethod = `func (%[1]s) Values() []string {
return %[1]sStrings()
}
`
func (g *Generator) buildAltStringValuesMethod(typeName string) {
g.Printf("\n")
g.Printf(altStringValuesMethod, typeName)
}
func (g *Generator) buildBasicExtras(runs [][]Value, typeName string, runsThreshold int) { func (g *Generator) buildBasicExtras(runs [][]Value, typeName string, runsThreshold int) {
// At this moment, either "g.declareIndexAndNameVars()" or "g.declareNameVars()" has been called // At this moment, either "g.declareIndexAndNameVars()" or "g.declareNameVars()" has been called
@ -51,14 +77,32 @@ func (g *Generator) buildBasicExtras(runs [][]Value, typeName string, runsThresh
g.Printf("\nvar _%sValues = []%s{", typeName, typeName) g.Printf("\nvar _%sValues = []%s{", typeName, typeName)
for _, values := range runs { for _, values := range runs {
for _, value := range values { for _, value := range values {
g.Printf("\t%s, ", value.str) g.Printf("\t%s, ", value.originalName)
} }
} }
g.Printf("}\n\n") g.Printf("}\n\n")
// Print the map between name and value // Print the map between name and value
g.Printf("\nvar _%sNameToValueMap = map[string]%s{\n", typeName, typeName) g.printValueMap(runs, typeName, runsThreshold)
// Print the slice of names
g.printNamesSlice(runs, typeName, runsThreshold)
// Print the basic extra methods
g.Printf(stringNameToValueMethod, typeName)
g.Printf(stringValuesMethod, typeName)
g.Printf(stringsMethod, typeName)
if len(runs) <= runsThreshold {
g.Printf(stringBelongsMethodLoop, typeName)
} else { // There is a map of values, the code is simpler then
g.Printf(stringBelongsMethodSet, typeName)
}
}
func (g *Generator) printValueMap(runs [][]Value, typeName string, runsThreshold int) {
thereAreRuns := len(runs) > 1 && len(runs) <= runsThreshold thereAreRuns := len(runs) > 1 && len(runs) <= runsThreshold
g.Printf("\nvar _%sNameToValueMap = map[string]%s{\n", typeName, typeName)
var n int var n int
var runID string var runID string
for i, values := range runs { for i, values := range runs {
@ -70,20 +114,33 @@ func (g *Generator) buildBasicExtras(runs [][]Value, typeName string, runsThresh
} }
for _, value := range values { for _, value := range values {
g.Printf("\t_%sName%s[%d:%d]: %s,\n", typeName, runID, n, n+len(value.name), &value) g.Printf("\t_%sName%s[%d:%d]: %s,\n", typeName, runID, n, n+len(value.name), value.originalName)
g.Printf("\t_%sLowerName%s[%d:%d]: %s,\n", typeName, runID, n, n+len(value.name), value.originalName)
n += len(value.name) n += len(value.name)
} }
} }
g.Printf("}\n\n") g.Printf("}\n\n")
}
func (g *Generator) printNamesSlice(runs [][]Value, typeName string, runsThreshold int) {
thereAreRuns := len(runs) > 1 && len(runs) <= runsThreshold
g.Printf("\nvar _%sNames = []string{\n", typeName)
// Print the basic extra methods var n int
g.Printf(stringNameToValueMethod, typeName) var runID string
g.Printf(stringValuesMethod, typeName) for i, values := range runs {
if len(runs) < runsThreshold { if thereAreRuns {
g.Printf(stringBelongsMethodLoop, typeName) runID = "_" + fmt.Sprintf("%d", i)
} else { // There is a map of values, the code is simpler then n = 0
g.Printf(stringBelongsMethodSet, typeName) } else {
runID = ""
}
for _, value := range values {
g.Printf("\t_%sName%s[%d:%d],\n", typeName, runID, n, n+len(value.name))
n += len(value.name)
}
} }
g.Printf("}\n\n")
} }
// Arguments to format are: // Arguments to format are:

View File

@ -0,0 +1,8 @@
# Go Modules Sample
## Steps
1. Go get enumer `go get -u git.internal/re/enumer`
2. `go generate` This should create `pill_enumer.go`
3. `go run *.go` to see it in action
4. `go mod tidy` to remove the deps for `enumer` once your happy.

3
examples/gomods/go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/dmarkham/gomods
go 1.12

0
examples/gomods/go.sum Normal file
View File

20
examples/gomods/main.go Normal file
View File

@ -0,0 +1,20 @@
package main
import "fmt"
//go:generate go run git.internal/re/enumer -type=Pill -json
type Pill int
const (
Placebo Pill = iota
Aspirin
Ibuprofen
Paracetamol
Acetaminophen = Paracetamol
)
func main() {
fmt.Println(PillStrings())
fmt.Println(Placebo.IsAPill())
fmt.Println(Placebo)
}

13
go.mod Normal file
View File

@ -0,0 +1,13 @@
module git.internal/re/enumer
require (
github.com/pascaldekloe/name v1.0.0
golang.org/x/tools v0.1.12
)
require (
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
)
go 1.17

28
go.sum Normal file
View File

@ -0,0 +1,28 @@
github.com/pascaldekloe/name v1.0.0 h1:n7LKFgHixETzxpRv2R77YgPUFo85QHGZKrdaYm7eY5U=
github.com/pascaldekloe/name v1.0.0/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

File diff suppressed because it is too large Load Diff

26
gqlgen.go Normal file
View File

@ -0,0 +1,26 @@
package main
// Arguments to format are:
// [1]: type name
const gqlgenMethods = `
// MarshalGQL implements the graphql.Marshaler interface for %[1]s
func (i %[1]s) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(i.String()))
}
// UnmarshalGQL implements the graphql.Unmarshaler interface for %[1]s
func (i *%[1]s) UnmarshalGQL(value interface{}) error {
str, ok := value.(string)
if !ok {
return fmt.Errorf("%[1]s should be a string, got %%T", value)
}
var err error
*i, err = %[1]sString(str)
return err
}
`
func (g *Generator) buildGQLGenMethods(runs [][]Value, typeName string) {
g.Printf(gqlgenMethods, typeName)
}

View File

@ -1,16 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.9
package main
import (
"go/importer"
"go/types"
)
func defaultImporter() types.Importer {
return importer.Default()
}

View File

@ -1,16 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
package main
import (
"go/importer"
"go/types"
)
func defaultImporter() types.Importer {
return importer.For("source", nil)
}

18
sql.go
View File

@ -12,14 +12,16 @@ const scanMethod = `func (i *%[1]s) Scan(value interface{}) error {
return nil return nil
} }
str, ok := value.(string) var str string
if !ok { switch v := value.(type) {
bytes, ok := value.([]byte) case []byte:
if !ok { str = string(v)
return fmt.Errorf("value is not a byte slice") case string:
} str = v
case fmt.Stringer:
str = string(bytes[:]) str = v.String()
default:
return fmt.Errorf("invalid value of %[1]s: %%[1]T(%%[1]v)", value)
} }
val, err := %[1]sString(str) val, err := %[1]sString(str)

View File

@ -2,12 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build go1.5 // Enumer is a tool to generate Go code that adds useful methods to Go enums (constants with a specific type).
// It started as a fork of Rob Pikes Stringer tool
//Enumer is a tool to generate Go code that adds useful methods to Go enums (constants with a specific type).
//It started as a fork of Rob Pikes Stringer tool
// //
//Please visit http://github.com/alvaroloes/enumer for a comprehensive documentation // Please visit http://git.internal/re/enumer for a comprehensive documentation
package main package main
import ( import (
@ -15,10 +13,9 @@ import (
"flag" "flag"
"fmt" "fmt"
"go/ast" "go/ast"
"go/build"
exact "go/constant" exact "go/constant"
"go/format" "go/format"
"go/parser" "go/importer"
"go/token" "go/token"
"go/types" "go/types"
"io/ioutil" "io/ioutil"
@ -27,6 +24,10 @@ import (
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
"unicode"
"unicode/utf8"
"golang.org/x/tools/go/packages"
"github.com/pascaldekloe/name" "github.com/pascaldekloe/name"
) )
@ -48,9 +49,13 @@ var (
json = flag.Bool("json", false, "if true, json marshaling methods will be generated. Default: false") json = flag.Bool("json", false, "if true, json marshaling methods will be generated. Default: false")
yaml = flag.Bool("yaml", false, "if true, yaml marshaling methods will be generated. Default: false") yaml = flag.Bool("yaml", false, "if true, yaml marshaling methods will be generated. Default: false")
text = flag.Bool("text", false, "if true, text marshaling methods will be generated. Default: false") text = flag.Bool("text", false, "if true, text marshaling methods will be generated. Default: false")
gqlgen = flag.Bool("gqlgen", false, "if true, GraphQL marshaling methods for gqlgen will be generated. Default: false")
altValuesFunc = flag.Bool("values", false, "if true, alternative string values method will be generated. Default: false")
output = flag.String("output", "", "output file name; default srcdir/<type>_string.go") output = flag.String("output", "", "output file name; default srcdir/<type>_string.go")
transformMethod = flag.String("transform", "noop", "enum item name transformation method. Default: noop") transformMethod = flag.String("transform", "noop", "enum item name transformation method. Default: noop")
trimPrefix = flag.String("trimprefix", "", "transform each item name by removing a prefix. Default: \"\"") trimPrefix = flag.String("trimprefix", "", "transform each item name by removing a prefix. Default: \"\"")
addPrefix = flag.String("addprefix", "", "transform each item name by adding a prefix. Default: \"\"")
linecomment = flag.Bool("linecomment", false, "use line comment text as printed text when present")
) )
var comments arrayFlags var comments arrayFlags
@ -61,12 +66,13 @@ func init() {
// Usage is a replacement usage function for the flags package. // Usage is a replacement usage function for the flags package.
func Usage() { func Usage() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) _, _ = fmt.Fprintf(os.Stderr, "Enumer is a tool to generate Go code that adds useful methods to Go enums (constants with a specific type).\n")
fmt.Fprintf(os.Stderr, "\tenumer [flags] -type T [directory]\n") _, _ = fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
fmt.Fprintf(os.Stderr, "\tenumer [flags] -type T files... # Must be a single package\n") _, _ = fmt.Fprintf(os.Stderr, "\tEnumer [flags] -type T [directory]\n")
fmt.Fprintf(os.Stderr, "For more information, see:\n") _, _ = fmt.Fprintf(os.Stderr, "\tEnumer [flags] -type T files... # Must be a single package\n")
fmt.Fprintf(os.Stderr, "\thttps://github.com/alvaroloes/enumer\n") _, _ = fmt.Fprintf(os.Stderr, "For more information, see:\n")
fmt.Fprintf(os.Stderr, "Flags:\n") _, _ = fmt.Fprintf(os.Stderr, "\thttp://godoc.org/git.internal/re/enumer\n")
_, _ = fmt.Fprintf(os.Stderr, "Flags:\n")
flag.PrintDefaults() flag.PrintDefaults()
} }
@ -79,7 +85,7 @@ func main() {
flag.Usage() flag.Usage()
os.Exit(2) os.Exit(2)
} }
types := strings.Split(*typeNames, ",") typs := strings.Split(*typeNames, ",")
// We accept either one directory or a list of files. Which do we have? // We accept either one directory or a list of files. Which do we have?
args := flag.Args() args := flag.Args()
@ -96,31 +102,40 @@ func main() {
if len(args) == 1 && isDirectory(args[0]) { if len(args) == 1 && isDirectory(args[0]) {
dir = args[0] dir = args[0]
g.parsePackageDir(args[0]) // g.parsePackageDir(args[0])
} else { } else {
dir = filepath.Dir(args[0]) dir = filepath.Dir(args[0])
g.parsePackageFiles(args) // g.parsePackageFiles(args)
} }
g.parsePackage(args, []string{})
// Print the header and package clause. // Print the header and package clause.
g.Printf("// Code generated by \"enumer %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " ")) g.Printf("// Code generated by \"enumer %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
g.Printf("\n") g.Printf("\n")
g.Printf("// %s\n", comments.String()) if comments.String() != "" {
g.Printf("// %s\n", comments.String())
}
g.Printf("package %s", g.pkg.name) g.Printf("package %s", g.pkg.name)
g.Printf("\n") g.Printf("\n")
g.Printf("import (\n") g.Printf("import (\n")
g.Printf("\t\"fmt\"\n") g.Printf("\t\"fmt\"\n")
g.Printf("\t\"strings\"\n")
if *sql { if *sql {
g.Printf("\t\"database/sql/driver\"\n") g.Printf("\t\"database/sql/driver\"\n")
} }
if *json { if *json {
g.Printf("\t\"encoding/json\"\n") g.Printf("\t\"encoding/json\"\n")
} }
if *gqlgen {
g.Printf("\t\"io\"\n")
g.Printf("\t\"strconv\"\n")
}
g.Printf(")\n") g.Printf(")\n")
// Run generate for each type. // Run generate for each type.
for _, typeName := range types { for _, typeName := range typs {
g.generate(typeName, *json, *yaml, *sql, *text, *transformMethod, *trimPrefix) g.generate(typeName, *json, *yaml, *sql, *text, *gqlgen, *transformMethod, *trimPrefix, *addPrefix, *linecomment, *altValuesFunc)
} }
// Format the output. // Format the output.
@ -129,12 +144,12 @@ func main() {
// Figure out filename to write to // Figure out filename to write to
outputName := *output outputName := *output
if outputName == "" { if outputName == "" {
baseName := fmt.Sprintf("%s_enumer.go", types[0]) baseName := fmt.Sprintf("%s_enumer.go", typs[0])
outputName = filepath.Join(dir, strings.ToLower(baseName)) outputName = filepath.Join(dir, strings.ToLower(baseName))
} }
// Write to tmpfile first // Write to tmpfile first
tmpFile, err := ioutil.TempFile("", fmt.Sprintf("%s_enumer_", types[0])) tmpFile, err := ioutil.TempFile(dir, fmt.Sprintf("%s_enumer_", typs[0]))
if err != nil { if err != nil {
log.Fatalf("creating temporary file for output: %s", err) log.Fatalf("creating temporary file for output: %s", err)
} }
@ -171,7 +186,7 @@ type Generator struct {
// Printf prints the string to the output // Printf prints the string to the output
func (g *Generator) Printf(format string, args ...interface{}) { func (g *Generator) Printf(format string, args ...interface{}) {
fmt.Fprintf(&g.buf, format, args...) _, _ = fmt.Fprintf(&g.buf, format, args...)
} }
// File holds a single parsed file and associated data. // File holds a single parsed file and associated data.
@ -179,8 +194,10 @@ type File struct {
pkg *Package // Package to which this file belongs. pkg *Package // Package to which this file belongs.
file *ast.File // Parsed AST. file *ast.File // Parsed AST.
// These fields are reset for each type being generated. // These fields are reset for each type being generated.
typeName string // Name of the constant type. typeName string // Name of the constant type.
values []Value // Accumulator for constant values of that type. values []Value // Accumulator for constant values of that type.
trimPrefix string
lineComment bool
} }
// Package holds information about a Go package // Package holds information about a Go package
@ -192,76 +209,111 @@ type Package struct {
typesPkg *types.Package typesPkg *types.Package
} }
// parsePackageDir parses the package residing in the directory. // // parsePackageDir parses the package residing in the directory.
func (g *Generator) parsePackageDir(directory string) { // func (g *Generator) parsePackageDir(directory string) {
pkg, err := build.Default.ImportDir(directory, 0) // pkg, err := build.Default.ImportDir(directory, 0)
// if err != nil {
// log.Fatalf("cannot process directory %s: %s", directory, err)
// }
// var names []string
// names = append(names, pkg.GoFiles...)
// names = append(names, pkg.CgoFiles...)
// // TODO: Need to think about constants in test files. Maybe write type_string_test.go
// // in a separate pass? For later.
// // names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
// names = append(names, pkg.SFiles...)
// names = prefixDirectory(directory, names)
// g.parsePackage(directory, names, nil)
// }
//
// // parsePackageFiles parses the package occupying the named files.
// func (g *Generator) parsePackageFiles(names []string) {
// g.parsePackage(".", names, nil)
// }
// // prefixDirectory places the directory name on the beginning of each name in the list.
// func prefixDirectory(directory string, names []string) []string {
// if directory == "." {
// return names
// }
// ret := make([]string, len(names))
// for i, n := range names {
// ret[i] = filepath.Join(directory, n)
// }
// return ret
// }
// parsePackage analyzes the single package constructed from the patterns and tags.
// parsePackage exits if there is an error.
func (g *Generator) parsePackage(patterns []string, tags []string) {
cfg := &packages.Config{
Mode: packages.LoadSyntax,
// TODO: Need to think about constants in test files. Maybe write type_string_test.go
// in a separate pass? For later.
Tests: false,
}
pkgs, err := packages.Load(cfg, patterns...)
if err != nil { if err != nil {
log.Fatalf("cannot process directory %s: %s", directory, err) log.Fatal(err)
} }
var names []string if len(pkgs) != 1 {
names = append(names, pkg.GoFiles...) log.Fatalf("error: %d packages found", len(pkgs))
names = append(names, pkg.CgoFiles...) }
// TODO: Need to think about constants in test files. Maybe write type_string_test.go g.addPackage(pkgs[0])
// in a separate pass? For later.
// names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
names = append(names, pkg.SFiles...)
names = prefixDirectory(directory, names)
g.parsePackage(directory, names, nil)
} }
// parsePackageFiles parses the package occupying the named files. // addPackage adds a type checked Package and its syntax files to the generator.
func (g *Generator) parsePackageFiles(names []string) { func (g *Generator) addPackage(pkg *packages.Package) {
g.parsePackage(".", names, nil) g.pkg = &Package{
} name: pkg.Name,
defs: pkg.TypesInfo.Defs,
files: make([]*File, len(pkg.Syntax)),
}
// prefixDirectory places the directory name on the beginning of each name in the list. for i, file := range pkg.Syntax {
func prefixDirectory(directory string, names []string) []string { g.pkg.files[i] = &File{
if directory == "." { file: file,
return names pkg: g.pkg,
}
} }
ret := make([]string, len(names))
for i, name := range names {
ret[i] = filepath.Join(directory, name)
}
return ret
} }
// parsePackage analyzes the single package constructed from the named files. // parsePackage analyzes the single package constructed from the named files.
// If text is non-nil, it is a string to be used instead of the content of the file, // If text is non-nil, it is a string to be used instead of the content of the file,
// to be used for testing. parsePackage exits if there is an error. // to be used for testing. parsePackage exits if there is an error.
func (g *Generator) parsePackage(directory string, names []string, text interface{}) { // func (g *Generator) parsePackagee(directory string, names []string, text interface{}) {
var files []*File // var files []*File
var astFiles []*ast.File // var astFiles []*ast.File
g.pkg = new(Package) // g.pkg = new(Package)
fs := token.NewFileSet() // fs := token.NewFileSet()
for _, name := range names { // for _, n := range names {
if !strings.HasSuffix(name, ".go") { // if !strings.HasSuffix(n, ".go") {
continue // continue
} // }
parsedFile, err := parser.ParseFile(fs, name, text, 0) // parsedFile, err := parser.ParseFile(fs, n, text, 0)
if err != nil { // if err != nil {
log.Fatalf("parsing package: %s: %s", name, err) // log.Fatalf("parsing package: %s: %s", n, err)
} // }
astFiles = append(astFiles, parsedFile) // astFiles = append(astFiles, parsedFile)
files = append(files, &File{ // files = append(files, &File{
file: parsedFile, // file: parsedFile,
pkg: g.pkg, // pkg: g.pkg,
}) // })
} // }
if len(astFiles) == 0 { // if len(astFiles) == 0 {
log.Fatalf("%s: no buildable Go files", directory) // log.Fatalf("%s: no buildable Go files", directory)
} // }
g.pkg.name = astFiles[0].Name.Name // g.pkg.name = astFiles[0].Name.Name
g.pkg.files = files // g.pkg.files = files
g.pkg.dir = directory // g.pkg.dir = directory
// Type check the package. // // Type check the package.
g.pkg.check(fs, astFiles) // g.pkg.check(fs, astFiles)
} // }
// check type-checks the package. The package must be OK to proceed. // check type-checks the package. The package must be OK to proceed.
func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) { func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {
pkg.defs = make(map[*ast.Ident]types.Object) pkg.defs = make(map[*ast.Ident]types.Object)
config := types.Config{Importer: defaultImporter(), FakeImportC: true} config := types.Config{Importer: importer.Default(), FakeImportC: true}
info := &types.Info{ info := &types.Info{
Defs: pkg.defs, Defs: pkg.defs,
} }
@ -273,18 +325,76 @@ func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {
} }
func (g *Generator) transformValueNames(values []Value, transformMethod string) { func (g *Generator) transformValueNames(values []Value, transformMethod string) {
var sep rune var fn func(src string) string
switch transformMethod { switch transformMethod {
case "snake": case "snake":
sep = '_' fn = func(s string) string {
return strings.ToLower(name.Delimit(s, '_'))
}
case "snake_upper", "snake-upper":
fn = func(s string) string {
return strings.ToUpper(name.Delimit(s, '_'))
}
case "kebab": case "kebab":
sep = '-' fn = func(s string) string {
return strings.ToLower(name.Delimit(s, '-'))
}
case "kebab_upper", "kebab-upper":
fn = func(s string) string {
return strings.ToUpper(name.Delimit(s, '-'))
}
case "upper":
fn = func(s string) string {
return strings.ToUpper(s)
}
case "lower":
fn = func(s string) string {
return strings.ToLower(s)
}
case "title":
fn = func(s string) string {
return strings.Title(s)
}
case "title-lower":
fn = func(s string) string {
title := []rune(strings.Title(s))
title[0] = unicode.ToLower(title[0])
return string(title)
}
case "first":
fn = func(s string) string {
r, _ := utf8.DecodeRuneInString(s)
return string(r)
}
case "first_upper", "first-upper":
fn = func(s string) string {
r, _ := utf8.DecodeRuneInString(s)
return strings.ToUpper(string(r))
}
case "first_lower", "first-lower":
fn = func(s string) string {
r, _ := utf8.DecodeRuneInString(s)
return strings.ToLower(string(r))
}
case "whitespace":
fn = func(s string) string {
return strings.ToLower(name.Delimit(s, ' '))
}
default: default:
return return
} }
for i := range values { for i, v := range values {
values[i].name = strings.ToLower(name.Delimit(values[i].name, sep)) after := fn(v.name)
// If the original one was "" or the one before the transformation
// was "" (most commonly if linecomment defines it as empty) we
// do not care if it's empty.
// But if any of them was not empty before then it means that
// the transformed emptied the value
if v.originalName != "" && v.name != "" && after == "" {
log.Fatalf("transformation of %q (%s) got an empty result", v.name, v.originalName)
}
values[i].name = after
} }
} }
@ -295,10 +405,20 @@ func (g *Generator) trimValueNames(values []Value, prefix string) {
} }
} }
// prefixValueNames adds a prefix to each name
func (g *Generator) prefixValueNames(values []Value, prefix string) {
for i := range values {
values[i].name = prefix + values[i].name
}
}
// generate produces the String method for the named type. // generate produces the String method for the named type.
func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeSQL, includeText bool, transformMethod string, trimPrefix string) { func (g *Generator) generate(typeName string,
includeJSON, includeYAML, includeSQL, includeText, includeGQLGen bool,
transformMethod string, trimPrefix string, addPrefix string, lineComment bool, includeValuesMethod bool) {
values := make([]Value, 0, 100) values := make([]Value, 0, 100)
for _, file := range g.pkg.files { for _, file := range g.pkg.files {
file.lineComment = lineComment
// Set the state for this run of the walker. // Set the state for this run of the walker.
file.typeName = typeName file.typeName = typeName
file.values = nil file.values = nil
@ -312,10 +432,14 @@ func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeS
log.Fatalf("no values defined for type %s", typeName) log.Fatalf("no values defined for type %s", typeName)
} }
g.trimValueNames(values, trimPrefix) for _, prefix := range strings.Split(trimPrefix, ",") {
g.trimValueNames(values, prefix)
}
g.transformValueNames(values, transformMethod) g.transformValueNames(values, transformMethod)
g.prefixValueNames(values, addPrefix)
runs := splitIntoRuns(values) runs := splitIntoRuns(values)
// The decision of which pattern to use depends on the number of // The decision of which pattern to use depends on the number of
// runs in the numbers. If there's only one, it's easy. For more than // runs in the numbers. If there's only one, it's easy. For more than
@ -338,6 +462,11 @@ func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeS
default: default:
g.buildMap(runs, typeName) g.buildMap(runs, typeName)
} }
if includeValuesMethod {
g.buildAltStringValuesMethod(typeName)
}
g.buildNoOpOrderChangeDetect(runs, typeName)
g.buildBasicExtras(runs, typeName, runsThreshold) g.buildBasicExtras(runs, typeName, runsThreshold)
if includeJSON { if includeJSON {
@ -352,6 +481,9 @@ func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeS
if includeSQL { if includeSQL {
g.addValueAndScanMethod(typeName) g.addValueAndScanMethod(typeName)
} }
if includeGQLGen {
g.buildGQLGenMethods(runs, typeName)
}
} }
// splitIntoRuns breaks the values into runs of contiguous sequences. // splitIntoRuns breaks the values into runs of contiguous sequences.
@ -401,7 +533,8 @@ func (g *Generator) format() []byte {
// Value represents a declared constant. // Value represents a declared constant.
type Value struct { type Value struct {
name string // The name of the constant after transformation (i.e. camel case => snake case) originalName string // The name of the constant before transformation
name string // The name of the constant after transformation (i.e. camel case => snake case)
// The value is stored as a bit pattern alone. The boolean tells us // The value is stored as a bit pattern alone. The boolean tells us
// whether to interpret it as an int64 or a uint64; the only place // whether to interpret it as an int64 or a uint64; the only place
// this matters is when sorting. // this matters is when sorting.
@ -467,16 +600,16 @@ func (f *File) genDecl(node ast.Node) bool {
// We now have a list of names (from one line of source code) all being // We now have a list of names (from one line of source code) all being
// declared with the desired type. // declared with the desired type.
// Grab their names and actual values and store them in f.values. // Grab their names and actual values and store them in f.values.
for _, name := range vspec.Names { for _, n := range vspec.Names {
if name.Name == "_" { if n.Name == "_" {
continue continue
} }
// This dance lets the type checker find the values for us. It's a // This dance lets the type checker find the values for us. It's a
// bit tricky: look up the object declared by the name, find its // bit tricky: look up the object declared by the n, find its
// types.Const, and extract its value. // types.Const, and extract its value.
obj, ok := f.pkg.defs[name] obj, ok := f.pkg.defs[n]
if !ok { if !ok {
log.Fatalf("no value for constant %s", name) log.Fatalf("no value for constant %s", n)
} }
info := obj.Type().Underlying().(*types.Basic).Info() info := obj.Type().Underlying().(*types.Basic).Info()
if info&types.IsInteger == 0 { if info&types.IsInteger == 0 {
@ -484,22 +617,27 @@ func (f *File) genDecl(node ast.Node) bool {
} }
value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST. value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST.
if value.Kind() != exact.Int { if value.Kind() != exact.Int {
log.Fatalf("can't happen: constant is not an integer %s", name) log.Fatalf("can't happen: constant is not an integer %s", n)
} }
i64, isInt := exact.Int64Val(value) i64, isInt := exact.Int64Val(value)
u64, isUint := exact.Uint64Val(value) u64, isUint := exact.Uint64Val(value)
if !isInt && !isUint { if !isInt && !isUint {
log.Fatalf("internal error: value of %s is not an integer: %s", name, value.String()) log.Fatalf("internal error: value of %s is not an integer: %s", n, value.String())
} }
if !isInt { if !isInt {
u64 = uint64(i64) u64 = uint64(i64)
} }
v := Value{ v := Value{
name: name.Name, originalName: n.Name,
value: u64, name: n.Name,
signed: info&types.IsUnsigned == 0, value: u64,
str: value.String(), signed: info&types.IsUnsigned == 0,
str: value.String(),
} }
if c := vspec.Comment; f.lineComment && c != nil && len(c.List) == 1 {
v.name = strings.TrimSpace(c.Text())
}
f.values = append(f.values, v) f.values = append(f.values, v)
} }
} }
@ -528,13 +666,15 @@ func usize(n int) int {
func (g *Generator) declareIndexAndNameVars(runs [][]Value, typeName string) { func (g *Generator) declareIndexAndNameVars(runs [][]Value, typeName string) {
var indexes, names []string var indexes, names []string
for i, run := range runs { for i, run := range runs {
index, name := g.createIndexAndNameDecl(run, typeName, fmt.Sprintf("_%d", i)) index, n := g.createIndexAndNameDecl(run, typeName, fmt.Sprintf("_%d", i))
indexes = append(indexes, index) indexes = append(indexes, index)
names = append(names, name) names = append(names, n)
_, n = g.createLowerIndexAndNameDecl(run, typeName, fmt.Sprintf("_%d", i))
names = append(names, n)
} }
g.Printf("const (\n") g.Printf("const (\n")
for _, name := range names { for _, n := range names {
g.Printf("\t%s\n", name) g.Printf("\t%s\n", n)
} }
g.Printf(")\n\n") g.Printf(")\n\n")
g.Printf("var (") g.Printf("var (")
@ -546,9 +686,34 @@ func (g *Generator) declareIndexAndNameVars(runs [][]Value, typeName string) {
// declareIndexAndNameVar is the single-run version of declareIndexAndNameVars // declareIndexAndNameVar is the single-run version of declareIndexAndNameVars
func (g *Generator) declareIndexAndNameVar(run []Value, typeName string) { func (g *Generator) declareIndexAndNameVar(run []Value, typeName string) {
index, name := g.createIndexAndNameDecl(run, typeName, "") index, n := g.createIndexAndNameDecl(run, typeName, "")
g.Printf("const %s\n", name) g.Printf("const %s\n", n)
g.Printf("var %s\n", index) g.Printf("var %s\n", index)
index, n = g.createLowerIndexAndNameDecl(run, typeName, "")
g.Printf("const %s\n", n)
//g.Printf("var %s\n", index)
}
// createIndexAndNameDecl returns the pair of declarations for the run. The caller will add "const" and "var".
func (g *Generator) createLowerIndexAndNameDecl(run []Value, typeName string, suffix string) (string, string) {
b := new(bytes.Buffer)
indexes := make([]int, len(run))
for i := range run {
b.WriteString(strings.ToLower(run[i].name))
indexes[i] = b.Len()
}
nameConst := fmt.Sprintf("_%sLowerName%s = %q", typeName, suffix, b.String())
nameLen := b.Len()
b.Reset()
_, _ = fmt.Fprintf(b, "_%sLowerIndex%s = [...]uint%d{0, ", typeName, suffix, usize(nameLen))
for i, v := range indexes {
if i > 0 {
_, _ = fmt.Fprintf(b, ", ")
}
_, _ = fmt.Fprintf(b, "%d", v)
}
_, _ = fmt.Fprintf(b, "}")
return b.String(), nameConst
} }
// createIndexAndNameDecl returns the pair of declarations for the run. The caller will add "const" and "var". // createIndexAndNameDecl returns the pair of declarations for the run. The caller will add "const" and "var".
@ -562,14 +727,14 @@ func (g *Generator) createIndexAndNameDecl(run []Value, typeName string, suffix
nameConst := fmt.Sprintf("_%sName%s = %q", typeName, suffix, b.String()) nameConst := fmt.Sprintf("_%sName%s = %q", typeName, suffix, b.String())
nameLen := b.Len() nameLen := b.Len()
b.Reset() b.Reset()
fmt.Fprintf(b, "_%sIndex%s = [...]uint%d{0, ", typeName, suffix, usize(nameLen)) _, _ = fmt.Fprintf(b, "_%sIndex%s = [...]uint%d{0, ", typeName, suffix, usize(nameLen))
for i, v := range indexes { for i, v := range indexes {
if i > 0 { if i > 0 {
fmt.Fprintf(b, ", ") _, _ = fmt.Fprintf(b, ", ")
} }
fmt.Fprintf(b, "%d", v) _, _ = fmt.Fprintf(b, "%d", v)
} }
fmt.Fprintf(b, "}") _, _ = fmt.Fprintf(b, "}")
return b.String(), nameConst return b.String(), nameConst
} }
@ -582,6 +747,13 @@ func (g *Generator) declareNameVars(runs [][]Value, typeName string, suffix stri
} }
} }
g.Printf("\"\n") g.Printf("\"\n")
g.Printf("const _%sLowerName%s = \"", typeName, suffix)
for _, run := range runs {
for i := range run {
g.Printf("%s", strings.ToLower(run[i].name))
}
}
g.Printf("\"\n")
} }
// buildOneRun generates the variables and String method for a single run of contiguous values. // buildOneRun generates the variables and String method for a single run of contiguous values.
@ -602,9 +774,9 @@ func (g *Generator) buildOneRun(runs [][]Value, typeName string) {
} }
// Arguments to format are: // Arguments to format are:
// [1]: type name // [1]: type name
// [2]: size of index element (8 for uint8 etc.) // [2]: size of index element (8 for uint8 etc.)
// [3]: less than zero check (for signed types) // [3]: less than zero check (for signed types)
const stringOneRun = `func (i %[1]s) String() string { const stringOneRun = `func (i %[1]s) String() string {
if %[3]si >= %[1]s(len(_%[1]sIndex)-1) { if %[3]si >= %[1]s(len(_%[1]sIndex)-1) {
return fmt.Sprintf("%[1]s(%%d)", i) return fmt.Sprintf("%[1]s(%%d)", i)
@ -614,12 +786,10 @@ const stringOneRun = `func (i %[1]s) String() string {
` `
// Arguments to format are: // Arguments to format are:
// [1]: type name // [1]: type name
// [2]: lowest defined value for type, as a string // [2]: lowest defined value for type, as a string
// [3]: size of index element (8 for uint8 etc.) // [3]: size of index element (8 for uint8 etc.)
// [4]: less than zero check (for signed types) // [4]: less than zero check (for signed types)
/*
*/
const stringOneRunWithOffset = `func (i %[1]s) String() string { const stringOneRunWithOffset = `func (i %[1]s) String() string {
i -= %[2]s i -= %[2]s
if %[4]si >= %[1]s(len(_%[1]sIndex)-1) { if %[4]si >= %[1]s(len(_%[1]sIndex)-1) {
@ -672,6 +842,24 @@ func (g *Generator) buildMap(runs [][]Value, typeName string) {
g.Printf(stringMap, typeName) g.Printf(stringMap, typeName)
} }
// buildNoOpOrderChangeDetect try to let the compiler and the user know if the order/value of the ENUMS have changed.
func (g *Generator) buildNoOpOrderChangeDetect(runs [][]Value, typeName string) {
g.Printf("\n")
g.Printf(`
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
`)
g.Printf("func _%sNoOp (){ ", typeName)
g.Printf("\n var x [1]struct{}\n")
for _, values := range runs {
for _, value := range values {
g.Printf("\t_ = x[%s-(%s)]\n", value.originalName, value.str)
}
}
g.Printf("}\n\n")
}
// Argument to format is the type name. // Argument to format is the type name.
const stringMap = `func (i %[1]s) String() string { const stringMap = `func (i %[1]s) String() string {
if str, ok := _%[1]sMap[i]; ok { if str, ok := _%[1]sMap[i]; ok {

14
testdata/day.go vendored
View File

@ -30,6 +30,9 @@ func main() {
ck(Sunday, "Sunday") ck(Sunday, "Sunday")
ck(-127, "Day(-127)") ck(-127, "Day(-127)")
ck(127, "Day(127)") ck(127, "Day(127)")
ckDayString(Sunday, "Sunday")
ckDayString(Sunday, "sunday")
} }
func ck(day Day, str string) { func ck(day Day, str string) {
@ -37,3 +40,14 @@ func ck(day Day, str string) {
panic("day.go: " + str) panic("day.go: " + str)
} }
} }
func ckDayString(day Day, str string) {
d, err := DayString(str)
if err != nil {
panic("day.go: " + err.Error())
}
if d != day {
panic("day.go: " + str)
}
}

94
testdata/day.golden vendored Normal file
View File

@ -0,0 +1,94 @@
const _DayName = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _DayIndex = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
const _DayLowerName = "mondaytuesdaywednesdaythursdayfridaysaturdaysunday"
func (i Day) String() string {
if i < 0 || i >= Day(len(_DayIndex)-1) {
return fmt.Sprintf("Day(%d)", i)
}
return _DayName[_DayIndex[i]:_DayIndex[i+1]]
}
func (Day) Values() []string {
return DayStrings()
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _DayNoOp() {
var x [1]struct{}
_ = x[Monday-(0)]
_ = x[Tuesday-(1)]
_ = x[Wednesday-(2)]
_ = x[Thursday-(3)]
_ = x[Friday-(4)]
_ = x[Saturday-(5)]
_ = x[Sunday-(6)]
}
var _DayValues = []Day{Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}
var _DayNameToValueMap = map[string]Day{
_DayName[0:6]: Monday,
_DayLowerName[0:6]: Monday,
_DayName[6:13]: Tuesday,
_DayLowerName[6:13]: Tuesday,
_DayName[13:22]: Wednesday,
_DayLowerName[13:22]: Wednesday,
_DayName[22:30]: Thursday,
_DayLowerName[22:30]: Thursday,
_DayName[30:36]: Friday,
_DayLowerName[30:36]: Friday,
_DayName[36:44]: Saturday,
_DayLowerName[36:44]: Saturday,
_DayName[44:50]: Sunday,
_DayLowerName[44:50]: Sunday,
}
var _DayNames = []string{
_DayName[0:6],
_DayName[6:13],
_DayName[13:22],
_DayName[22:30],
_DayName[30:36],
_DayName[36:44],
_DayName[44:50],
}
// DayString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func DayString(s string) (Day, error) {
if val, ok := _DayNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _DayNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Day values", s)
}
// DayValues returns all values of the enum
func DayValues() []Day {
return _DayValues
}
// DayStrings returns a slice of all String values of the enum
func DayStrings() []string {
strs := make([]string, len(_DayNames))
copy(strs, _DayNames)
return strs
}
// IsADay returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Day) IsADay() bool {
for _, v := range _DayValues {
if i == v {
return true
}
}
return false
}

90
testdata/dayTrimAndPrefix.golden vendored Normal file
View File

@ -0,0 +1,90 @@
const _DayName = "NightMondayNightTuesdayNightWednesdayNightThursdayNightFridayNightSaturdayNightSunday"
var _DayIndex = [...]uint8{0, 11, 23, 37, 50, 61, 74, 85}
const _DayLowerName = "nightmondaynighttuesdaynightwednesdaynightthursdaynightfridaynightsaturdaynightsunday"
func (i Day) String() string {
if i < 0 || i >= Day(len(_DayIndex)-1) {
return fmt.Sprintf("Day(%d)", i)
}
return _DayName[_DayIndex[i]:_DayIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _DayNoOp() {
var x [1]struct{}
_ = x[DayMonday-(0)]
_ = x[DayTuesday-(1)]
_ = x[DayWednesday-(2)]
_ = x[DayThursday-(3)]
_ = x[DayFriday-(4)]
_ = x[DaySaturday-(5)]
_ = x[DaySunday-(6)]
}
var _DayValues = []Day{DayMonday, DayTuesday, DayWednesday, DayThursday, DayFriday, DaySaturday, DaySunday}
var _DayNameToValueMap = map[string]Day{
_DayName[0:11]: DayMonday,
_DayLowerName[0:11]: DayMonday,
_DayName[11:23]: DayTuesday,
_DayLowerName[11:23]: DayTuesday,
_DayName[23:37]: DayWednesday,
_DayLowerName[23:37]: DayWednesday,
_DayName[37:50]: DayThursday,
_DayLowerName[37:50]: DayThursday,
_DayName[50:61]: DayFriday,
_DayLowerName[50:61]: DayFriday,
_DayName[61:74]: DaySaturday,
_DayLowerName[61:74]: DaySaturday,
_DayName[74:85]: DaySunday,
_DayLowerName[74:85]: DaySunday,
}
var _DayNames = []string{
_DayName[0:11],
_DayName[11:23],
_DayName[23:37],
_DayName[37:50],
_DayName[50:61],
_DayName[61:74],
_DayName[74:85],
}
// DayString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func DayString(s string) (Day, error) {
if val, ok := _DayNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _DayNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Day values", s)
}
// DayValues returns all values of the enum
func DayValues() []Day {
return _DayValues
}
// DayStrings returns a slice of all String values of the enum
func DayStrings() []string {
strs := make([]string, len(_DayNames))
copy(strs, _DayNames)
return strs
}
// IsADay returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Day) IsADay() bool {
for _, v := range _DayValues {
if i == v {
return true
}
}
return false
}

90
testdata/dayWithLinecomment.golden vendored Normal file
View File

@ -0,0 +1,90 @@
const _DayName = "lunesTuesdayWednesdayThursdayviernesSaturdaySunday"
var _DayIndex = [...]uint8{0, 5, 12, 21, 29, 36, 44, 50}
const _DayLowerName = "lunestuesdaywednesdaythursdayviernessaturdaysunday"
func (i Day) String() string {
if i < 0 || i >= Day(len(_DayIndex)-1) {
return fmt.Sprintf("Day(%d)", i)
}
return _DayName[_DayIndex[i]:_DayIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _DayNoOp() {
var x [1]struct{}
_ = x[Monday-(0)]
_ = x[Tuesday-(1)]
_ = x[Wednesday-(2)]
_ = x[Thursday-(3)]
_ = x[Friday-(4)]
_ = x[Saturday-(5)]
_ = x[Sunday-(6)]
}
var _DayValues = []Day{Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}
var _DayNameToValueMap = map[string]Day{
_DayName[0:5]: Monday,
_DayLowerName[0:5]: Monday,
_DayName[5:12]: Tuesday,
_DayLowerName[5:12]: Tuesday,
_DayName[12:21]: Wednesday,
_DayLowerName[12:21]: Wednesday,
_DayName[21:29]: Thursday,
_DayLowerName[21:29]: Thursday,
_DayName[29:36]: Friday,
_DayLowerName[29:36]: Friday,
_DayName[36:44]: Saturday,
_DayLowerName[36:44]: Saturday,
_DayName[44:50]: Sunday,
_DayLowerName[44:50]: Sunday,
}
var _DayNames = []string{
_DayName[0:5],
_DayName[5:12],
_DayName[12:21],
_DayName[21:29],
_DayName[29:36],
_DayName[36:44],
_DayName[44:50],
}
// DayString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func DayString(s string) (Day, error) {
if val, ok := _DayNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _DayNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Day values", s)
}
// DayValues returns all values of the enum
func DayValues() []Day {
return _DayValues
}
// DayStrings returns a slice of all String values of the enum
func DayStrings() []string {
strs := make([]string, len(_DayNames))
copy(strs, _DayNames)
return strs
}
// IsADay returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Day) IsADay() bool {
for _, v := range _DayValues {
if i == v {
return true
}
}
return false
}

90
testdata/dayWithPrefix.golden vendored Normal file
View File

@ -0,0 +1,90 @@
const _DayName = "DayMondayDayTuesdayDayWednesdayDayThursdayDayFridayDaySaturdayDaySunday"
var _DayIndex = [...]uint8{0, 9, 19, 31, 42, 51, 62, 71}
const _DayLowerName = "daymondaydaytuesdaydaywednesdaydaythursdaydayfridaydaysaturdaydaysunday"
func (i Day) String() string {
if i < 0 || i >= Day(len(_DayIndex)-1) {
return fmt.Sprintf("Day(%d)", i)
}
return _DayName[_DayIndex[i]:_DayIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _DayNoOp() {
var x [1]struct{}
_ = x[Monday-(0)]
_ = x[Tuesday-(1)]
_ = x[Wednesday-(2)]
_ = x[Thursday-(3)]
_ = x[Friday-(4)]
_ = x[Saturday-(5)]
_ = x[Sunday-(6)]
}
var _DayValues = []Day{Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}
var _DayNameToValueMap = map[string]Day{
_DayName[0:9]: Monday,
_DayLowerName[0:9]: Monday,
_DayName[9:19]: Tuesday,
_DayLowerName[9:19]: Tuesday,
_DayName[19:31]: Wednesday,
_DayLowerName[19:31]: Wednesday,
_DayName[31:42]: Thursday,
_DayLowerName[31:42]: Thursday,
_DayName[42:51]: Friday,
_DayLowerName[42:51]: Friday,
_DayName[51:62]: Saturday,
_DayLowerName[51:62]: Saturday,
_DayName[62:71]: Sunday,
_DayLowerName[62:71]: Sunday,
}
var _DayNames = []string{
_DayName[0:9],
_DayName[9:19],
_DayName[19:31],
_DayName[31:42],
_DayName[42:51],
_DayName[51:62],
_DayName[62:71],
}
// DayString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func DayString(s string) (Day, error) {
if val, ok := _DayNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _DayNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Day values", s)
}
// DayValues returns all values of the enum
func DayValues() []Day {
return _DayValues
}
// DayStrings returns a slice of all String values of the enum
func DayStrings() []string {
strs := make([]string, len(_DayNames))
copy(strs, _DayNames)
return strs
}
// IsADay returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Day) IsADay() bool {
for _, v := range _DayValues {
if i == v {
return true
}
}
return false
}

115
testdata/gap.golden vendored Normal file
View File

@ -0,0 +1,115 @@
const (
_GapName_0 = "TwoThree"
_GapLowerName_0 = "twothree"
_GapName_1 = "FiveSixSevenEightNine"
_GapLowerName_1 = "fivesixseveneightnine"
_GapName_2 = "Eleven"
_GapLowerName_2 = "eleven"
)
var (
_GapIndex_0 = [...]uint8{0, 3, 8}
_GapIndex_1 = [...]uint8{0, 4, 7, 12, 17, 21}
_GapIndex_2 = [...]uint8{0, 6}
)
func (i Gap) String() string {
switch {
case 2 <= i && i <= 3:
i -= 2
return _GapName_0[_GapIndex_0[i]:_GapIndex_0[i+1]]
case 5 <= i && i <= 9:
i -= 5
return _GapName_1[_GapIndex_1[i]:_GapIndex_1[i+1]]
case i == 11:
return _GapName_2
default:
return fmt.Sprintf("Gap(%d)", i)
}
}
func (Gap) Values() []string {
return GapStrings()
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _GapNoOp() {
var x [1]struct{}
_ = x[Two-(2)]
_ = x[Three-(3)]
_ = x[Five-(5)]
_ = x[Six-(6)]
_ = x[Seven-(7)]
_ = x[Eight-(8)]
_ = x[Nine-(9)]
_ = x[Eleven-(11)]
}
var _GapValues = []Gap{Two, Three, Five, Six, Seven, Eight, Nine, Eleven}
var _GapNameToValueMap = map[string]Gap{
_GapName_0[0:3]: Two,
_GapLowerName_0[0:3]: Two,
_GapName_0[3:8]: Three,
_GapLowerName_0[3:8]: Three,
_GapName_1[0:4]: Five,
_GapLowerName_1[0:4]: Five,
_GapName_1[4:7]: Six,
_GapLowerName_1[4:7]: Six,
_GapName_1[7:12]: Seven,
_GapLowerName_1[7:12]: Seven,
_GapName_1[12:17]: Eight,
_GapLowerName_1[12:17]: Eight,
_GapName_1[17:21]: Nine,
_GapLowerName_1[17:21]: Nine,
_GapName_2[0:6]: Eleven,
_GapLowerName_2[0:6]: Eleven,
}
var _GapNames = []string{
_GapName_0[0:3],
_GapName_0[3:8],
_GapName_1[0:4],
_GapName_1[4:7],
_GapName_1[7:12],
_GapName_1[12:17],
_GapName_1[17:21],
_GapName_2[0:6],
}
// GapString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func GapString(s string) (Gap, error) {
if val, ok := _GapNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _GapNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Gap values", s)
}
// GapValues returns all values of the enum
func GapValues() []Gap {
return _GapValues
}
// GapStrings returns a slice of all String values of the enum
func GapStrings() []string {
strs := make([]string, len(_GapNames))
copy(strs, _GapNames)
return strs
}
// IsAGap returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Gap) IsAGap() bool {
for _, v := range _GapValues {
if i == v {
return true
}
}
return false
}

87
testdata/num.golden vendored Normal file
View File

@ -0,0 +1,87 @@
const _NumName = "m_2m_1m0m1m2"
var _NumIndex = [...]uint8{0, 3, 6, 8, 10, 12}
const _NumLowerName = "m_2m_1m0m1m2"
func (i Num) String() string {
i -= -2
if i < 0 || i >= Num(len(_NumIndex)-1) {
return fmt.Sprintf("Num(%d)", i+-2)
}
return _NumName[_NumIndex[i]:_NumIndex[i+1]]
}
func (Num) Values() []string {
return NumStrings()
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _NumNoOp() {
var x [1]struct{}
_ = x[m_2-(-2)]
_ = x[m_1-(-1)]
_ = x[m0-(0)]
_ = x[m1-(1)]
_ = x[m2-(2)]
}
var _NumValues = []Num{m_2, m_1, m0, m1, m2}
var _NumNameToValueMap = map[string]Num{
_NumName[0:3]: m_2,
_NumLowerName[0:3]: m_2,
_NumName[3:6]: m_1,
_NumLowerName[3:6]: m_1,
_NumName[6:8]: m0,
_NumLowerName[6:8]: m0,
_NumName[8:10]: m1,
_NumLowerName[8:10]: m1,
_NumName[10:12]: m2,
_NumLowerName[10:12]: m2,
}
var _NumNames = []string{
_NumName[0:3],
_NumName[3:6],
_NumName[6:8],
_NumName[8:10],
_NumName[10:12],
}
// NumString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func NumString(s string) (Num, error) {
if val, ok := _NumNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _NumNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Num values", s)
}
// NumValues returns all values of the enum
func NumValues() []Num {
return _NumValues
}
// NumStrings returns a slice of all String values of the enum
func NumStrings() []string {
strs := make([]string, len(_NumNames))
copy(strs, _NumNames)
return strs
}
// IsANum returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Num) IsANum() bool {
for _, v := range _NumValues {
if i == v {
return true
}
}
return false
}

79
testdata/offset.golden vendored Normal file
View File

@ -0,0 +1,79 @@
const _NumberName = "OneTwoThree"
var _NumberIndex = [...]uint8{0, 3, 6, 11}
const _NumberLowerName = "onetwothree"
func (i Number) String() string {
i -= 1
if i < 0 || i >= Number(len(_NumberIndex)-1) {
return fmt.Sprintf("Number(%d)", i+1)
}
return _NumberName[_NumberIndex[i]:_NumberIndex[i+1]]
}
func (Number) Values() []string {
return NumberStrings()
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _NumberNoOp() {
var x [1]struct{}
_ = x[One-(1)]
_ = x[Two-(2)]
_ = x[Three-(3)]
}
var _NumberValues = []Number{One, Two, Three}
var _NumberNameToValueMap = map[string]Number{
_NumberName[0:3]: One,
_NumberLowerName[0:3]: One,
_NumberName[3:6]: Two,
_NumberLowerName[3:6]: Two,
_NumberName[6:11]: Three,
_NumberLowerName[6:11]: Three,
}
var _NumberNames = []string{
_NumberName[0:3],
_NumberName[3:6],
_NumberName[6:11],
}
// NumberString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func NumberString(s string) (Number, error) {
if val, ok := _NumberNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _NumberNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Number values", s)
}
// NumberValues returns all values of the enum
func NumberValues() []Number {
return _NumberValues
}
// NumberStrings returns a slice of all String values of the enum
func NumberStrings() []string {
strs := make([]string, len(_NumberNames))
copy(strs, _NumberNames)
return strs
}
// IsANumber returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Number) IsANumber() bool {
for _, v := range _NumberValues {
if i == v {
return true
}
}
return false
}

127
testdata/prime.golden vendored Normal file
View File

@ -0,0 +1,127 @@
const _PrimeName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
const _PrimeLowerName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
var _PrimeMap = map[Prime]string{
2: _PrimeName[0:2],
3: _PrimeName[2:4],
5: _PrimeName[4:6],
7: _PrimeName[6:8],
11: _PrimeName[8:11],
13: _PrimeName[11:14],
17: _PrimeName[14:17],
19: _PrimeName[17:20],
23: _PrimeName[20:23],
29: _PrimeName[23:26],
31: _PrimeName[26:29],
41: _PrimeName[29:32],
43: _PrimeName[32:35],
}
func (i Prime) String() string {
if str, ok := _PrimeMap[i]; ok {
return str
}
return fmt.Sprintf("Prime(%d)", i)
}
func (Prime) Values() []string {
return PrimeStrings()
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _PrimeNoOp() {
var x [1]struct{}
_ = x[p2-(2)]
_ = x[p3-(3)]
_ = x[p5-(5)]
_ = x[p7-(7)]
_ = x[p11-(11)]
_ = x[p13-(13)]
_ = x[p17-(17)]
_ = x[p19-(19)]
_ = x[p23-(23)]
_ = x[p29-(29)]
_ = x[p37-(31)]
_ = x[p41-(41)]
_ = x[p43-(43)]
}
var _PrimeValues = []Prime{p2, p3, p5, p7, p11, p13, p17, p19, p23, p29, p37, p41, p43}
var _PrimeNameToValueMap = map[string]Prime{
_PrimeName[0:2]: p2,
_PrimeLowerName[0:2]: p2,
_PrimeName[2:4]: p3,
_PrimeLowerName[2:4]: p3,
_PrimeName[4:6]: p5,
_PrimeLowerName[4:6]: p5,
_PrimeName[6:8]: p7,
_PrimeLowerName[6:8]: p7,
_PrimeName[8:11]: p11,
_PrimeLowerName[8:11]: p11,
_PrimeName[11:14]: p13,
_PrimeLowerName[11:14]: p13,
_PrimeName[14:17]: p17,
_PrimeLowerName[14:17]: p17,
_PrimeName[17:20]: p19,
_PrimeLowerName[17:20]: p19,
_PrimeName[20:23]: p23,
_PrimeLowerName[20:23]: p23,
_PrimeName[23:26]: p29,
_PrimeLowerName[23:26]: p29,
_PrimeName[26:29]: p37,
_PrimeLowerName[26:29]: p37,
_PrimeName[29:32]: p41,
_PrimeLowerName[29:32]: p41,
_PrimeName[32:35]: p43,
_PrimeLowerName[32:35]: p43,
}
var _PrimeNames = []string{
_PrimeName[0:2],
_PrimeName[2:4],
_PrimeName[4:6],
_PrimeName[6:8],
_PrimeName[8:11],
_PrimeName[11:14],
_PrimeName[14:17],
_PrimeName[17:20],
_PrimeName[20:23],
_PrimeName[23:26],
_PrimeName[26:29],
_PrimeName[29:32],
_PrimeName[32:35],
}
// PrimeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PrimeString(s string) (Prime, error) {
if val, ok := _PrimeNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _PrimeNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Prime values", s)
}
// PrimeValues returns all values of the enum
func PrimeValues() []Prime {
return _PrimeValues
}
// PrimeStrings returns a slice of all String values of the enum
func PrimeStrings() []string {
strs := make([]string, len(_PrimeNames))
copy(strs, _PrimeNames)
return strs
}
// IsAPrime returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Prime) IsAPrime() bool {
_, ok := _PrimeMap[i]
return ok
}

140
testdata/primeGQLGen.golden vendored Normal file
View File

@ -0,0 +1,140 @@
const _PrimeName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
const _PrimeLowerName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
var _PrimeMap = map[Prime]string{
2: _PrimeName[0:2],
3: _PrimeName[2:4],
5: _PrimeName[4:6],
7: _PrimeName[6:8],
11: _PrimeName[8:11],
13: _PrimeName[11:14],
17: _PrimeName[14:17],
19: _PrimeName[17:20],
23: _PrimeName[20:23],
29: _PrimeName[23:26],
31: _PrimeName[26:29],
41: _PrimeName[29:32],
43: _PrimeName[32:35],
}
func (i Prime) String() string {
if str, ok := _PrimeMap[i]; ok {
return str
}
return fmt.Sprintf("Prime(%d)", i)
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _PrimeNoOp() {
var x [1]struct{}
_ = x[p2-(2)]
_ = x[p3-(3)]
_ = x[p5-(5)]
_ = x[p7-(7)]
_ = x[p11-(11)]
_ = x[p13-(13)]
_ = x[p17-(17)]
_ = x[p19-(19)]
_ = x[p23-(23)]
_ = x[p29-(29)]
_ = x[p37-(31)]
_ = x[p41-(41)]
_ = x[p43-(43)]
}
var _PrimeValues = []Prime{p2, p3, p5, p7, p11, p13, p17, p19, p23, p29, p37, p41, p43}
var _PrimeNameToValueMap = map[string]Prime{
_PrimeName[0:2]: p2,
_PrimeLowerName[0:2]: p2,
_PrimeName[2:4]: p3,
_PrimeLowerName[2:4]: p3,
_PrimeName[4:6]: p5,
_PrimeLowerName[4:6]: p5,
_PrimeName[6:8]: p7,
_PrimeLowerName[6:8]: p7,
_PrimeName[8:11]: p11,
_PrimeLowerName[8:11]: p11,
_PrimeName[11:14]: p13,
_PrimeLowerName[11:14]: p13,
_PrimeName[14:17]: p17,
_PrimeLowerName[14:17]: p17,
_PrimeName[17:20]: p19,
_PrimeLowerName[17:20]: p19,
_PrimeName[20:23]: p23,
_PrimeLowerName[20:23]: p23,
_PrimeName[23:26]: p29,
_PrimeLowerName[23:26]: p29,
_PrimeName[26:29]: p37,
_PrimeLowerName[26:29]: p37,
_PrimeName[29:32]: p41,
_PrimeLowerName[29:32]: p41,
_PrimeName[32:35]: p43,
_PrimeLowerName[32:35]: p43,
}
var _PrimeNames = []string{
_PrimeName[0:2],
_PrimeName[2:4],
_PrimeName[4:6],
_PrimeName[6:8],
_PrimeName[8:11],
_PrimeName[11:14],
_PrimeName[14:17],
_PrimeName[17:20],
_PrimeName[20:23],
_PrimeName[23:26],
_PrimeName[26:29],
_PrimeName[29:32],
_PrimeName[32:35],
}
// PrimeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PrimeString(s string) (Prime, error) {
if val, ok := _PrimeNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _PrimeNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Prime values", s)
}
// PrimeValues returns all values of the enum
func PrimeValues() []Prime {
return _PrimeValues
}
// PrimeStrings returns a slice of all String values of the enum
func PrimeStrings() []string {
strs := make([]string, len(_PrimeNames))
copy(strs, _PrimeNames)
return strs
}
// IsAPrime returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Prime) IsAPrime() bool {
_, ok := _PrimeMap[i]
return ok
}
// MarshalGQL implements the graphql.Marshaler interface for Prime
func (i Prime) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(i.String()))
}
// UnmarshalGQL implements the graphql.Unmarshaler interface for Prime
func (i *Prime) UnmarshalGQL(value interface{}) error {
str, ok := value.(string)
if !ok {
return fmt.Errorf("Prime should be a string, got %T", value)
}
var err error
*i, err = PrimeString(str)
return err
}

140
testdata/primeJson.golden vendored Normal file
View File

@ -0,0 +1,140 @@
const _PrimeName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
const _PrimeLowerName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
var _PrimeMap = map[Prime]string{
2: _PrimeName[0:2],
3: _PrimeName[2:4],
5: _PrimeName[4:6],
7: _PrimeName[6:8],
11: _PrimeName[8:11],
13: _PrimeName[11:14],
17: _PrimeName[14:17],
19: _PrimeName[17:20],
23: _PrimeName[20:23],
29: _PrimeName[23:26],
31: _PrimeName[26:29],
41: _PrimeName[29:32],
43: _PrimeName[32:35],
}
func (i Prime) String() string {
if str, ok := _PrimeMap[i]; ok {
return str
}
return fmt.Sprintf("Prime(%d)", i)
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _PrimeNoOp() {
var x [1]struct{}
_ = x[p2-(2)]
_ = x[p3-(3)]
_ = x[p5-(5)]
_ = x[p7-(7)]
_ = x[p11-(11)]
_ = x[p13-(13)]
_ = x[p17-(17)]
_ = x[p19-(19)]
_ = x[p23-(23)]
_ = x[p29-(29)]
_ = x[p37-(31)]
_ = x[p41-(41)]
_ = x[p43-(43)]
}
var _PrimeValues = []Prime{p2, p3, p5, p7, p11, p13, p17, p19, p23, p29, p37, p41, p43}
var _PrimeNameToValueMap = map[string]Prime{
_PrimeName[0:2]: p2,
_PrimeLowerName[0:2]: p2,
_PrimeName[2:4]: p3,
_PrimeLowerName[2:4]: p3,
_PrimeName[4:6]: p5,
_PrimeLowerName[4:6]: p5,
_PrimeName[6:8]: p7,
_PrimeLowerName[6:8]: p7,
_PrimeName[8:11]: p11,
_PrimeLowerName[8:11]: p11,
_PrimeName[11:14]: p13,
_PrimeLowerName[11:14]: p13,
_PrimeName[14:17]: p17,
_PrimeLowerName[14:17]: p17,
_PrimeName[17:20]: p19,
_PrimeLowerName[17:20]: p19,
_PrimeName[20:23]: p23,
_PrimeLowerName[20:23]: p23,
_PrimeName[23:26]: p29,
_PrimeLowerName[23:26]: p29,
_PrimeName[26:29]: p37,
_PrimeLowerName[26:29]: p37,
_PrimeName[29:32]: p41,
_PrimeLowerName[29:32]: p41,
_PrimeName[32:35]: p43,
_PrimeLowerName[32:35]: p43,
}
var _PrimeNames = []string{
_PrimeName[0:2],
_PrimeName[2:4],
_PrimeName[4:6],
_PrimeName[6:8],
_PrimeName[8:11],
_PrimeName[11:14],
_PrimeName[14:17],
_PrimeName[17:20],
_PrimeName[20:23],
_PrimeName[23:26],
_PrimeName[26:29],
_PrimeName[29:32],
_PrimeName[32:35],
}
// PrimeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PrimeString(s string) (Prime, error) {
if val, ok := _PrimeNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _PrimeNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Prime values", s)
}
// PrimeValues returns all values of the enum
func PrimeValues() []Prime {
return _PrimeValues
}
// PrimeStrings returns a slice of all String values of the enum
func PrimeStrings() []string {
strs := make([]string, len(_PrimeNames))
copy(strs, _PrimeNames)
return strs
}
// IsAPrime returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Prime) IsAPrime() bool {
_, ok := _PrimeMap[i]
return ok
}
// MarshalJSON implements the json.Marshaler interface for Prime
func (i Prime) MarshalJSON() ([]byte, error) {
return json.Marshal(i.String())
}
// UnmarshalJSON implements the json.Unmarshaler interface for Prime
func (i *Prime) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return fmt.Errorf("Prime should be a string, got %s", data)
}
var err error
*i, err = PrimeString(s)
return err
}

170
testdata/primeJsonAndSql.golden vendored Normal file
View File

@ -0,0 +1,170 @@
const _PrimeName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
const _PrimeLowerName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
var _PrimeMap = map[Prime]string{
2: _PrimeName[0:2],
3: _PrimeName[2:4],
5: _PrimeName[4:6],
7: _PrimeName[6:8],
11: _PrimeName[8:11],
13: _PrimeName[11:14],
17: _PrimeName[14:17],
19: _PrimeName[17:20],
23: _PrimeName[20:23],
29: _PrimeName[23:26],
31: _PrimeName[26:29],
41: _PrimeName[29:32],
43: _PrimeName[32:35],
}
func (i Prime) String() string {
if str, ok := _PrimeMap[i]; ok {
return str
}
return fmt.Sprintf("Prime(%d)", i)
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _PrimeNoOp() {
var x [1]struct{}
_ = x[p2-(2)]
_ = x[p3-(3)]
_ = x[p5-(5)]
_ = x[p7-(7)]
_ = x[p11-(11)]
_ = x[p13-(13)]
_ = x[p17-(17)]
_ = x[p19-(19)]
_ = x[p23-(23)]
_ = x[p29-(29)]
_ = x[p37-(31)]
_ = x[p41-(41)]
_ = x[p43-(43)]
}
var _PrimeValues = []Prime{p2, p3, p5, p7, p11, p13, p17, p19, p23, p29, p37, p41, p43}
var _PrimeNameToValueMap = map[string]Prime{
_PrimeName[0:2]: p2,
_PrimeLowerName[0:2]: p2,
_PrimeName[2:4]: p3,
_PrimeLowerName[2:4]: p3,
_PrimeName[4:6]: p5,
_PrimeLowerName[4:6]: p5,
_PrimeName[6:8]: p7,
_PrimeLowerName[6:8]: p7,
_PrimeName[8:11]: p11,
_PrimeLowerName[8:11]: p11,
_PrimeName[11:14]: p13,
_PrimeLowerName[11:14]: p13,
_PrimeName[14:17]: p17,
_PrimeLowerName[14:17]: p17,
_PrimeName[17:20]: p19,
_PrimeLowerName[17:20]: p19,
_PrimeName[20:23]: p23,
_PrimeLowerName[20:23]: p23,
_PrimeName[23:26]: p29,
_PrimeLowerName[23:26]: p29,
_PrimeName[26:29]: p37,
_PrimeLowerName[26:29]: p37,
_PrimeName[29:32]: p41,
_PrimeLowerName[29:32]: p41,
_PrimeName[32:35]: p43,
_PrimeLowerName[32:35]: p43,
}
var _PrimeNames = []string{
_PrimeName[0:2],
_PrimeName[2:4],
_PrimeName[4:6],
_PrimeName[6:8],
_PrimeName[8:11],
_PrimeName[11:14],
_PrimeName[14:17],
_PrimeName[17:20],
_PrimeName[20:23],
_PrimeName[23:26],
_PrimeName[26:29],
_PrimeName[29:32],
_PrimeName[32:35],
}
// PrimeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PrimeString(s string) (Prime, error) {
if val, ok := _PrimeNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _PrimeNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Prime values", s)
}
// PrimeValues returns all values of the enum
func PrimeValues() []Prime {
return _PrimeValues
}
// PrimeStrings returns a slice of all String values of the enum
func PrimeStrings() []string {
strs := make([]string, len(_PrimeNames))
copy(strs, _PrimeNames)
return strs
}
// IsAPrime returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Prime) IsAPrime() bool {
_, ok := _PrimeMap[i]
return ok
}
// MarshalJSON implements the json.Marshaler interface for Prime
func (i Prime) MarshalJSON() ([]byte, error) {
return json.Marshal(i.String())
}
// UnmarshalJSON implements the json.Unmarshaler interface for Prime
func (i *Prime) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return fmt.Errorf("Prime should be a string, got %s", data)
}
var err error
*i, err = PrimeString(s)
return err
}
func (i Prime) Value() (driver.Value, error) {
return i.String(), nil
}
func (i *Prime) Scan(value interface{}) error {
if value == nil {
return nil
}
var str string
switch v := value.(type) {
case []byte:
str = string(v)
case string:
str = v
case fmt.Stringer:
str = v.String()
default:
return fmt.Errorf("invalid value of Prime: %[1]T(%[1]v)", value)
}
val, err := PrimeString(str)
if err != nil {
return err
}
*i = val
return nil
}

153
testdata/primeSql.golden vendored Normal file
View File

@ -0,0 +1,153 @@
const _PrimeName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
const _PrimeLowerName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
var _PrimeMap = map[Prime]string{
2: _PrimeName[0:2],
3: _PrimeName[2:4],
5: _PrimeName[4:6],
7: _PrimeName[6:8],
11: _PrimeName[8:11],
13: _PrimeName[11:14],
17: _PrimeName[14:17],
19: _PrimeName[17:20],
23: _PrimeName[20:23],
29: _PrimeName[23:26],
31: _PrimeName[26:29],
41: _PrimeName[29:32],
43: _PrimeName[32:35],
}
func (i Prime) String() string {
if str, ok := _PrimeMap[i]; ok {
return str
}
return fmt.Sprintf("Prime(%d)", i)
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _PrimeNoOp() {
var x [1]struct{}
_ = x[p2-(2)]
_ = x[p3-(3)]
_ = x[p5-(5)]
_ = x[p7-(7)]
_ = x[p11-(11)]
_ = x[p13-(13)]
_ = x[p17-(17)]
_ = x[p19-(19)]
_ = x[p23-(23)]
_ = x[p29-(29)]
_ = x[p37-(31)]
_ = x[p41-(41)]
_ = x[p43-(43)]
}
var _PrimeValues = []Prime{p2, p3, p5, p7, p11, p13, p17, p19, p23, p29, p37, p41, p43}
var _PrimeNameToValueMap = map[string]Prime{
_PrimeName[0:2]: p2,
_PrimeLowerName[0:2]: p2,
_PrimeName[2:4]: p3,
_PrimeLowerName[2:4]: p3,
_PrimeName[4:6]: p5,
_PrimeLowerName[4:6]: p5,
_PrimeName[6:8]: p7,
_PrimeLowerName[6:8]: p7,
_PrimeName[8:11]: p11,
_PrimeLowerName[8:11]: p11,
_PrimeName[11:14]: p13,
_PrimeLowerName[11:14]: p13,
_PrimeName[14:17]: p17,
_PrimeLowerName[14:17]: p17,
_PrimeName[17:20]: p19,
_PrimeLowerName[17:20]: p19,
_PrimeName[20:23]: p23,
_PrimeLowerName[20:23]: p23,
_PrimeName[23:26]: p29,
_PrimeLowerName[23:26]: p29,
_PrimeName[26:29]: p37,
_PrimeLowerName[26:29]: p37,
_PrimeName[29:32]: p41,
_PrimeLowerName[29:32]: p41,
_PrimeName[32:35]: p43,
_PrimeLowerName[32:35]: p43,
}
var _PrimeNames = []string{
_PrimeName[0:2],
_PrimeName[2:4],
_PrimeName[4:6],
_PrimeName[6:8],
_PrimeName[8:11],
_PrimeName[11:14],
_PrimeName[14:17],
_PrimeName[17:20],
_PrimeName[20:23],
_PrimeName[23:26],
_PrimeName[26:29],
_PrimeName[29:32],
_PrimeName[32:35],
}
// PrimeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PrimeString(s string) (Prime, error) {
if val, ok := _PrimeNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _PrimeNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Prime values", s)
}
// PrimeValues returns all values of the enum
func PrimeValues() []Prime {
return _PrimeValues
}
// PrimeStrings returns a slice of all String values of the enum
func PrimeStrings() []string {
strs := make([]string, len(_PrimeNames))
copy(strs, _PrimeNames)
return strs
}
// IsAPrime returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Prime) IsAPrime() bool {
_, ok := _PrimeMap[i]
return ok
}
func (i Prime) Value() (driver.Value, error) {
return i.String(), nil
}
func (i *Prime) Scan(value interface{}) error {
if value == nil {
return nil
}
var str string
switch v := value.(type) {
case []byte:
str = string(v)
case string:
str = v
case fmt.Stringer:
str = v.String()
default:
return fmt.Errorf("invalid value of Prime: %[1]T(%[1]v)", value)
}
val, err := PrimeString(str)
if err != nil {
return err
}
*i = val
return nil
}

135
testdata/primeText.golden vendored Normal file
View File

@ -0,0 +1,135 @@
const _PrimeName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
const _PrimeLowerName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
var _PrimeMap = map[Prime]string{
2: _PrimeName[0:2],
3: _PrimeName[2:4],
5: _PrimeName[4:6],
7: _PrimeName[6:8],
11: _PrimeName[8:11],
13: _PrimeName[11:14],
17: _PrimeName[14:17],
19: _PrimeName[17:20],
23: _PrimeName[20:23],
29: _PrimeName[23:26],
31: _PrimeName[26:29],
41: _PrimeName[29:32],
43: _PrimeName[32:35],
}
func (i Prime) String() string {
if str, ok := _PrimeMap[i]; ok {
return str
}
return fmt.Sprintf("Prime(%d)", i)
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _PrimeNoOp() {
var x [1]struct{}
_ = x[p2-(2)]
_ = x[p3-(3)]
_ = x[p5-(5)]
_ = x[p7-(7)]
_ = x[p11-(11)]
_ = x[p13-(13)]
_ = x[p17-(17)]
_ = x[p19-(19)]
_ = x[p23-(23)]
_ = x[p29-(29)]
_ = x[p37-(31)]
_ = x[p41-(41)]
_ = x[p43-(43)]
}
var _PrimeValues = []Prime{p2, p3, p5, p7, p11, p13, p17, p19, p23, p29, p37, p41, p43}
var _PrimeNameToValueMap = map[string]Prime{
_PrimeName[0:2]: p2,
_PrimeLowerName[0:2]: p2,
_PrimeName[2:4]: p3,
_PrimeLowerName[2:4]: p3,
_PrimeName[4:6]: p5,
_PrimeLowerName[4:6]: p5,
_PrimeName[6:8]: p7,
_PrimeLowerName[6:8]: p7,
_PrimeName[8:11]: p11,
_PrimeLowerName[8:11]: p11,
_PrimeName[11:14]: p13,
_PrimeLowerName[11:14]: p13,
_PrimeName[14:17]: p17,
_PrimeLowerName[14:17]: p17,
_PrimeName[17:20]: p19,
_PrimeLowerName[17:20]: p19,
_PrimeName[20:23]: p23,
_PrimeLowerName[20:23]: p23,
_PrimeName[23:26]: p29,
_PrimeLowerName[23:26]: p29,
_PrimeName[26:29]: p37,
_PrimeLowerName[26:29]: p37,
_PrimeName[29:32]: p41,
_PrimeLowerName[29:32]: p41,
_PrimeName[32:35]: p43,
_PrimeLowerName[32:35]: p43,
}
var _PrimeNames = []string{
_PrimeName[0:2],
_PrimeName[2:4],
_PrimeName[4:6],
_PrimeName[6:8],
_PrimeName[8:11],
_PrimeName[11:14],
_PrimeName[14:17],
_PrimeName[17:20],
_PrimeName[20:23],
_PrimeName[23:26],
_PrimeName[26:29],
_PrimeName[29:32],
_PrimeName[32:35],
}
// PrimeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PrimeString(s string) (Prime, error) {
if val, ok := _PrimeNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _PrimeNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Prime values", s)
}
// PrimeValues returns all values of the enum
func PrimeValues() []Prime {
return _PrimeValues
}
// PrimeStrings returns a slice of all String values of the enum
func PrimeStrings() []string {
strs := make([]string, len(_PrimeNames))
copy(strs, _PrimeNames)
return strs
}
// IsAPrime returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Prime) IsAPrime() bool {
_, ok := _PrimeMap[i]
return ok
}
// MarshalText implements the encoding.TextMarshaler interface for Prime
func (i Prime) MarshalText() ([]byte, error) {
return []byte(i.String()), nil
}
// UnmarshalText implements the encoding.TextUnmarshaler interface for Prime
func (i *Prime) UnmarshalText(text []byte) error {
var err error
*i, err = PrimeString(string(text))
return err
}

140
testdata/primeYaml.golden vendored Normal file
View File

@ -0,0 +1,140 @@
const _PrimeName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
const _PrimeLowerName = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
var _PrimeMap = map[Prime]string{
2: _PrimeName[0:2],
3: _PrimeName[2:4],
5: _PrimeName[4:6],
7: _PrimeName[6:8],
11: _PrimeName[8:11],
13: _PrimeName[11:14],
17: _PrimeName[14:17],
19: _PrimeName[17:20],
23: _PrimeName[20:23],
29: _PrimeName[23:26],
31: _PrimeName[26:29],
41: _PrimeName[29:32],
43: _PrimeName[32:35],
}
func (i Prime) String() string {
if str, ok := _PrimeMap[i]; ok {
return str
}
return fmt.Sprintf("Prime(%d)", i)
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _PrimeNoOp() {
var x [1]struct{}
_ = x[p2-(2)]
_ = x[p3-(3)]
_ = x[p5-(5)]
_ = x[p7-(7)]
_ = x[p11-(11)]
_ = x[p13-(13)]
_ = x[p17-(17)]
_ = x[p19-(19)]
_ = x[p23-(23)]
_ = x[p29-(29)]
_ = x[p37-(31)]
_ = x[p41-(41)]
_ = x[p43-(43)]
}
var _PrimeValues = []Prime{p2, p3, p5, p7, p11, p13, p17, p19, p23, p29, p37, p41, p43}
var _PrimeNameToValueMap = map[string]Prime{
_PrimeName[0:2]: p2,
_PrimeLowerName[0:2]: p2,
_PrimeName[2:4]: p3,
_PrimeLowerName[2:4]: p3,
_PrimeName[4:6]: p5,
_PrimeLowerName[4:6]: p5,
_PrimeName[6:8]: p7,
_PrimeLowerName[6:8]: p7,
_PrimeName[8:11]: p11,
_PrimeLowerName[8:11]: p11,
_PrimeName[11:14]: p13,
_PrimeLowerName[11:14]: p13,
_PrimeName[14:17]: p17,
_PrimeLowerName[14:17]: p17,
_PrimeName[17:20]: p19,
_PrimeLowerName[17:20]: p19,
_PrimeName[20:23]: p23,
_PrimeLowerName[20:23]: p23,
_PrimeName[23:26]: p29,
_PrimeLowerName[23:26]: p29,
_PrimeName[26:29]: p37,
_PrimeLowerName[26:29]: p37,
_PrimeName[29:32]: p41,
_PrimeLowerName[29:32]: p41,
_PrimeName[32:35]: p43,
_PrimeLowerName[32:35]: p43,
}
var _PrimeNames = []string{
_PrimeName[0:2],
_PrimeName[2:4],
_PrimeName[4:6],
_PrimeName[6:8],
_PrimeName[8:11],
_PrimeName[11:14],
_PrimeName[14:17],
_PrimeName[17:20],
_PrimeName[20:23],
_PrimeName[23:26],
_PrimeName[26:29],
_PrimeName[29:32],
_PrimeName[32:35],
}
// PrimeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PrimeString(s string) (Prime, error) {
if val, ok := _PrimeNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _PrimeNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Prime values", s)
}
// PrimeValues returns all values of the enum
func PrimeValues() []Prime {
return _PrimeValues
}
// PrimeStrings returns a slice of all String values of the enum
func PrimeStrings() []string {
strs := make([]string, len(_PrimeNames))
copy(strs, _PrimeNames)
return strs
}
// IsAPrime returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Prime) IsAPrime() bool {
_, ok := _PrimeMap[i]
return ok
}
// MarshalYAML implements a YAML Marshaler for Prime
func (i Prime) MarshalYAML() (interface{}, error) {
return i.String(), nil
}
// UnmarshalYAML implements a YAML Unmarshaler for Prime
func (i *Prime) UnmarshalYAML(unmarshal func(interface{}) error) error {
var s string
if err := unmarshal(&s); err != nil {
return err
}
var err error
*i, err = PrimeString(s)
return err
}

47
testdata/thresholdeq.go vendored Normal file
View File

@ -0,0 +1,47 @@
package main
import "fmt"
type Thresholdeq int
const (
req1 Thresholdeq = 2
req2 Thresholdeq = 4
req3 Thresholdeq = 6
req4 Thresholdeq = 8
req5 Thresholdeq = 10
req6 Thresholdeq = 12
req7 Thresholdeq = 14
req8 Thresholdeq = 16
req9 Thresholdeq = 18
req10 Thresholdeq = 20
)
func main() {
ck(1, "Thresholdeq(1)")
ck(req1, "req1")
ck(3, "Thresholdeq(3)")
ck(req2, "req2")
ck(5, "Thresholdeq(5)")
ck(req3, "req3")
ck(7, "Thresholdeq(7)")
ck(req4, "req4")
ck(9, "Thresholdeq(9)")
ck(req5, "req5")
ck(11, "Thresholdeq(11)")
ck(req6, "req6")
ck(13, "Thresholdeq(13)")
ck(req7, "req7")
ck(15, "Thresholdeq(15)")
ck(req8, "req8")
ck(17, "Thresholdeq(17)")
ck(req9, "req9")
ck(19, "Thresholdeq(19)")
ck(req10, "req10")
}
func ck(thresholdeq Thresholdeq, str string) {
if fmt.Sprint(thresholdeq) != str {
panic("thresholdeq.go: " + str)
}
}

50
testdata/thresholdgt.go vendored Normal file
View File

@ -0,0 +1,50 @@
package main
import "fmt"
type Thresholdgt int
const (
rgt1 Thresholdgt = 2
rgt2 Thresholdgt = 4
rgt3 Thresholdgt = 6
rgt4 Thresholdgt = 8
rgt5 Thresholdgt = 10
rgt6 Thresholdgt = 12
rgt7 Thresholdgt = 14
rgt8 Thresholdgt = 16
rgt9 Thresholdgt = 18
rgt10 Thresholdgt = 20
rgt11 Thresholdgt = 22
)
func main() {
ck(1, "Thresholdgt(1)")
ck(rgt1, "rgt1")
ck(3, "Thresholdgt(3)")
ck(rgt2, "rgt2")
ck(5, "Thresholdgt(5)")
ck(rgt3, "rgt3")
ck(7, "Thresholdgt(7)")
ck(rgt4, "rgt4")
ck(9, "Thresholdgt(9)")
ck(rgt5, "rgt5")
ck(11, "Thresholdgt(11)")
ck(rgt6, "rgt6")
ck(13, "Thresholdgt(13)")
ck(rgt7, "rgt7")
ck(15, "Thresholdgt(15)")
ck(rgt8, "rgt8")
ck(17, "Thresholdgt(17)")
ck(rgt9, "rgt9")
ck(19, "Thresholdgt(19)")
ck(rgt10, "rgt10")
ck(21, "Thresholdgt(21)")
ck(rgt11, "rgt11")
}
func ck(thresholdgt Thresholdgt, str string) {
if fmt.Sprint(thresholdgt) != str {
panic("thresholdgt.go: " + str)
}
}

44
testdata/thresholdlt.go vendored Normal file
View File

@ -0,0 +1,44 @@
package main
import "fmt"
type Thresholdlt int
const (
rlt1 Thresholdlt = 2
rlt2 Thresholdlt = 4
rlt3 Thresholdlt = 6
rlt4 Thresholdlt = 8
rlt5 Thresholdlt = 10
rlt6 Thresholdlt = 12
rlt7 Thresholdlt = 14
rlt8 Thresholdlt = 16
rlt9 Thresholdlt = 18
)
func main() {
ck(1, "Thresholdlt(1)")
ck(rlt1, "rlt1")
ck(3, "Thresholdlt(3)")
ck(rlt2, "rlt2")
ck(5, "Thresholdlt(5)")
ck(rlt3, "rlt3")
ck(7, "Thresholdlt(7)")
ck(rlt4, "rlt4")
ck(9, "Thresholdlt(9)")
ck(rlt5, "rlt5")
ck(11, "Thresholdlt(11)")
ck(rlt6, "rlt6")
ck(13, "Thresholdlt(13)")
ck(rlt7, "rlt7")
ck(15, "Thresholdlt(15)")
ck(rlt8, "rlt8")
ck(17, "Thresholdlt(17)")
ck(rlt9, "rlt9")
}
func ck(thresholdlt Thresholdlt, str string) {
if fmt.Sprint(thresholdlt) != str {
panic("thresholdlt.go: " + str)
}
}

25
testdata/transform.go vendored
View File

@ -1,25 +0,0 @@
package main
import "fmt"
type CamelCaseValue int
const (
CamelCaseValueOne CamelCaseValue = iota
CamelCaseValueTwo
CamelCaseValueThree
)
func main() {
ck(CamelCaseValueOne, "camel_case_value_one")
ck(CamelCaseValueTwo, "camel_case_value_two")
ck(CamelCaseValueThree, "camel_case_value_three")
ck(-127, "CamelCaseValue(-127)")
ck(127, "CamelCaseValue(127)")
}
func ck(value CamelCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform.go: " + str)
}
}

25
testdata/transform_first.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type FirstCaseValue int
const (
Male FirstCaseValue = iota
Female
unknown
)
func main() {
ck(Male, "M")
ck(Female, "F")
ck(unknown, "u")
ck(-127, "FirstCaseValue(-127)")
ck(127, "FirstCaseValue(127)")
}
func ck(value FirstCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_first.go: " + str)
}
}

25
testdata/transform_first_lower.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type FirstLowerCaseValue int
const (
Male FirstLowerCaseValue = iota
Female
Unknown
)
func main() {
ck(Male, "m")
ck(Female, "f")
ck(Unknown, "u")
ck(-127, "FirstLowerCaseValue(-127)")
ck(127, "FirstLowerCaseValue(127)")
}
func ck(value FirstLowerCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_first_lower.go: " + str)
}
}

25
testdata/transform_first_upper.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type FirstUpperCaseValue int
const (
male FirstUpperCaseValue = iota
female
unknown
)
func main() {
ck(male, "M")
ck(female, "F")
ck(unknown, "U")
ck(-127, "FirstUpperCaseValue(-127)")
ck(127, "FirstUpperCaseValue(127)")
}
func ck(value FirstUpperCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_first_upper.go: " + str)
}
}

25
testdata/transform_kebab.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type KebabCaseValue int
const (
KebabCaseValueOne KebabCaseValue = iota
KebabCaseValueTwo
KebabCaseValueThree
)
func main() {
ck(KebabCaseValueOne, "kebab-case-value-one")
ck(KebabCaseValueTwo, "kebab-case-value-two")
ck(KebabCaseValueThree, "kebab-case-value-three")
ck(-127, "KebabCaseValue(-127)")
ck(127, "KebabCaseValue(127)")
}
func ck(value KebabCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_kebab.go: " + str)
}
}

25
testdata/transform_kebab_upper.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type KebabUpperCaseValue int
const (
KebabUpperCaseValueOne KebabUpperCaseValue = iota
KebabUpperCaseValueTwo
KebabUpperCaseValueThree
)
func main() {
ck(KebabUpperCaseValueOne, "KEBAB-UPPER-CASE-VALUE-ONE")
ck(KebabUpperCaseValueTwo, "KEBAB-UPPER-CASE-VALUE-TWO")
ck(KebabUpperCaseValueThree, "KEBAB-UPPER-CASE-VALUE-THREE")
ck(-127, "KebabUpperCaseValue(-127)")
ck(127, "KebabUpperCaseValue(127)")
}
func ck(value KebabUpperCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_kebab_upper.go: " + str)
}
}

25
testdata/transform_lower.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type LowerCaseValue int
const (
LowerCaseValueOne LowerCaseValue = iota
LowerCaseValueTwo
LowerCaseValueThree
)
func main() {
ck(LowerCaseValueOne, "lowercasevalueone")
ck(LowerCaseValueTwo, "lowercasevaluetwo")
ck(LowerCaseValueThree, "lowercasevaluethree")
ck(-127, "LowerCaseValue(-127)")
ck(127, "LowerCaseValue(127)")
}
func ck(value LowerCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_lower.go: " + str)
}
}

25
testdata/transform_snake.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type SnakeCaseValue int
const (
SnakeCaseValueOne SnakeCaseValue = iota
SnakeCaseValueTwo
SnakeCaseValueThree
)
func main() {
ck(SnakeCaseValueOne, "snake_case_value_one")
ck(SnakeCaseValueTwo, "snake_case_value_two")
ck(SnakeCaseValueThree, "snake_case_value_three")
ck(-127, "SnakeCaseValue(-127)")
ck(127, "SnakeCaseValue(127)")
}
func ck(value SnakeCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_snake.go: " + str)
}
}

25
testdata/transform_snake_upper.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type SnakeUpperCaseValue int
const (
SnakeUpperCaseValueOne SnakeUpperCaseValue = iota
SnakeUpperCaseValueTwo
SnakeUpperCaseValueThree
)
func main() {
ck(SnakeUpperCaseValueOne, "SNAKE_UPPER_CASE_VALUE_ONE")
ck(SnakeUpperCaseValueTwo, "SNAKE_UPPER_CASE_VALUE_TWO")
ck(SnakeUpperCaseValueThree, "SNAKE_UPPER_CASE_VALUE_THREE")
ck(-127, "SnakeUpperCaseValue(-127)")
ck(127, "SnakeUpperCaseValue(127)")
}
func ck(value SnakeUpperCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_snake_upper.go: " + str)
}
}

25
testdata/transform_title.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type TitleCaseValue int
const (
titlecasevalueone TitleCaseValue = iota
titlecasevaluetwo
titlecasevaluethree
)
func main() {
ck(titlecasevalueone, "Titlecasevalueone")
ck(titlecasevaluetwo, "Titlecasevaluetwo")
ck(titlecasevaluethree, "Titlecasevaluethree")
ck(-127, "TitleCaseValue(-127)")
ck(127, "TitleCaseValue(127)")
}
func ck(value TitleCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_title.go: " + str)
}
}

25
testdata/transform_upper.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type UpperCaseValue int
const (
UpperCaseValueOne UpperCaseValue = iota
UpperCaseValueTwo
UpperCaseValueThree
)
func main() {
ck(UpperCaseValueOne, "UPPERCASEVALUEONE")
ck(UpperCaseValueTwo, "UPPERCASEVALUETWO")
ck(UpperCaseValueThree, "UPPERCASEVALUETHREE")
ck(-127, "UpperCaseValue(-127)")
ck(127, "UpperCaseValue(127)")
}
func ck(value UpperCaseValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_upper.go: " + str)
}
}

25
testdata/transform_whitespace.go vendored Normal file
View File

@ -0,0 +1,25 @@
package main
import "fmt"
type WhitespaceSeparatedValue int
const (
WhitespaceSeparatedValueOne WhitespaceSeparatedValue = iota
WhitespaceSeparatedValueTwo
WhitespaceSeparatedValueThree
)
func main() {
ck(WhitespaceSeparatedValueOne, "whitespace separated value one")
ck(WhitespaceSeparatedValueTwo, "whitespace separated value two")
ck(WhitespaceSeparatedValueThree, "whitespace separated value three")
ck(-127, "WhitespaceSeparatedValue(-127)")
ck(127, "WhitespaceSeparatedValue(127)")
}
func ck(value WhitespaceSeparatedValue, str string) {
if fmt.Sprint(value) != str {
panic("transform_whitespace.go: " + str)
}
}

90
testdata/trimPrefix.golden vendored Normal file
View File

@ -0,0 +1,90 @@
const _DayName = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _DayIndex = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
const _DayLowerName = "mondaytuesdaywednesdaythursdayfridaysaturdaysunday"
func (i Day) String() string {
if i < 0 || i >= Day(len(_DayIndex)-1) {
return fmt.Sprintf("Day(%d)", i)
}
return _DayName[_DayIndex[i]:_DayIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _DayNoOp() {
var x [1]struct{}
_ = x[DayMonday-(0)]
_ = x[DayTuesday-(1)]
_ = x[DayWednesday-(2)]
_ = x[DayThursday-(3)]
_ = x[DayFriday-(4)]
_ = x[DaySaturday-(5)]
_ = x[DaySunday-(6)]
}
var _DayValues = []Day{DayMonday, DayTuesday, DayWednesday, DayThursday, DayFriday, DaySaturday, DaySunday}
var _DayNameToValueMap = map[string]Day{
_DayName[0:6]: DayMonday,
_DayLowerName[0:6]: DayMonday,
_DayName[6:13]: DayTuesday,
_DayLowerName[6:13]: DayTuesday,
_DayName[13:22]: DayWednesday,
_DayLowerName[13:22]: DayWednesday,
_DayName[22:30]: DayThursday,
_DayLowerName[22:30]: DayThursday,
_DayName[30:36]: DayFriday,
_DayLowerName[30:36]: DayFriday,
_DayName[36:44]: DaySaturday,
_DayLowerName[36:44]: DaySaturday,
_DayName[44:50]: DaySunday,
_DayLowerName[44:50]: DaySunday,
}
var _DayNames = []string{
_DayName[0:6],
_DayName[6:13],
_DayName[13:22],
_DayName[22:30],
_DayName[30:36],
_DayName[36:44],
_DayName[44:50],
}
// DayString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func DayString(s string) (Day, error) {
if val, ok := _DayNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _DayNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Day values", s)
}
// DayValues returns all values of the enum
func DayValues() []Day {
return _DayValues
}
// DayStrings returns a slice of all String values of the enum
func DayStrings() []string {
strs := make([]string, len(_DayNames))
copy(strs, _DayNames)
return strs
}
// IsADay returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Day) IsADay() bool {
for _, v := range _DayValues {
if i == v {
return true
}
}
return false
}

90
testdata/trimPrefixMultiple.golden vendored Normal file
View File

@ -0,0 +1,90 @@
const _DayName = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _DayIndex = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
const _DayLowerName = "mondaytuesdaywednesdaythursdayfridaysaturdaysunday"
func (i Day) String() string {
if i < 0 || i >= Day(len(_DayIndex)-1) {
return fmt.Sprintf("Day(%d)", i)
}
return _DayName[_DayIndex[i]:_DayIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _DayNoOp() {
var x [1]struct{}
_ = x[DayMonday-(0)]
_ = x[NightTuesday-(1)]
_ = x[DayWednesday-(2)]
_ = x[NightThursday-(3)]
_ = x[DayFriday-(4)]
_ = x[NightSaturday-(5)]
_ = x[DaySunday-(6)]
}
var _DayValues = []Day{DayMonday, NightTuesday, DayWednesday, NightThursday, DayFriday, NightSaturday, DaySunday}
var _DayNameToValueMap = map[string]Day{
_DayName[0:6]: DayMonday,
_DayLowerName[0:6]: DayMonday,
_DayName[6:13]: NightTuesday,
_DayLowerName[6:13]: NightTuesday,
_DayName[13:22]: DayWednesday,
_DayLowerName[13:22]: DayWednesday,
_DayName[22:30]: NightThursday,
_DayLowerName[22:30]: NightThursday,
_DayName[30:36]: DayFriday,
_DayLowerName[30:36]: DayFriday,
_DayName[36:44]: NightSaturday,
_DayLowerName[36:44]: NightSaturday,
_DayName[44:50]: DaySunday,
_DayLowerName[44:50]: DaySunday,
}
var _DayNames = []string{
_DayName[0:6],
_DayName[6:13],
_DayName[13:22],
_DayName[22:30],
_DayName[30:36],
_DayName[36:44],
_DayName[44:50],
}
// DayString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func DayString(s string) (Day, error) {
if val, ok := _DayNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _DayNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Day values", s)
}
// DayValues returns all values of the enum
func DayValues() []Day {
return _DayValues
}
// DayStrings returns a slice of all String values of the enum
func DayStrings() []string {
strs := make([]string, len(_DayNames))
copy(strs, _DayNames)
return strs
}
// IsADay returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Day) IsADay() bool {
for _, v := range _DayValues {
if i == v {
return true
}
}
return false
}

97
testdata/unum.golden vendored Normal file
View File

@ -0,0 +1,97 @@
const (
_UnumName_0 = "m0m1m2"
_UnumLowerName_0 = "m0m1m2"
_UnumName_1 = "m_2m_1"
_UnumLowerName_1 = "m_2m_1"
)
var (
_UnumIndex_0 = [...]uint8{0, 2, 4, 6}
_UnumIndex_1 = [...]uint8{0, 3, 6}
)
func (i Unum) String() string {
switch {
case 0 <= i && i <= 2:
return _UnumName_0[_UnumIndex_0[i]:_UnumIndex_0[i+1]]
case 253 <= i && i <= 254:
i -= 253
return _UnumName_1[_UnumIndex_1[i]:_UnumIndex_1[i+1]]
default:
return fmt.Sprintf("Unum(%d)", i)
}
}
func (Unum) Values() []string {
return UnumStrings()
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _UnumNoOp() {
var x [1]struct{}
_ = x[m0-(0)]
_ = x[m1-(1)]
_ = x[m2-(2)]
_ = x[m_2-(253)]
_ = x[m_1-(254)]
}
var _UnumValues = []Unum{m0, m1, m2, m_2, m_1}
var _UnumNameToValueMap = map[string]Unum{
_UnumName_0[0:2]: m0,
_UnumLowerName_0[0:2]: m0,
_UnumName_0[2:4]: m1,
_UnumLowerName_0[2:4]: m1,
_UnumName_0[4:6]: m2,
_UnumLowerName_0[4:6]: m2,
_UnumName_1[0:3]: m_2,
_UnumLowerName_1[0:3]: m_2,
_UnumName_1[3:6]: m_1,
_UnumLowerName_1[3:6]: m_1,
}
var _UnumNames = []string{
_UnumName_0[0:2],
_UnumName_0[2:4],
_UnumName_0[4:6],
_UnumName_1[0:3],
_UnumName_1[3:6],
}
// UnumString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func UnumString(s string) (Unum, error) {
if val, ok := _UnumNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _UnumNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Unum values", s)
}
// UnumValues returns all values of the enum
func UnumValues() []Unum {
return _UnumValues
}
// UnumStrings returns a slice of all String values of the enum
func UnumStrings() []string {
strs := make([]string, len(_UnumNames))
copy(strs, _UnumNames)
return strs
}
// IsAUnum returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Unum) IsAUnum() bool {
for _, v := range _UnumValues {
if i == v {
return true
}
}
return false
}

View File

@ -54,7 +54,7 @@ Outer:
for n, test := range splitTests { for n, test := range splitTests {
values := make([]Value, len(test.input)) values := make([]Value, len(test.input))
for i, v := range test.input { for i, v := range test.input {
values[i] = Value{"", v, test.signed, fmt.Sprint(v)} values[i] = Value{"", "", v, test.signed, fmt.Sprint(v)}
} }
runs := splitIntoRuns(values) runs := splitIntoRuns(values)
if len(runs) != len(test.output) { if len(runs) != len(test.output) {

View File

@ -1,3 +0,0 @@
To the extent possible under law, Pascal S. de Kloe has waived all
copyright and related or neighboring rights to Colfer. This work is
published from The Netherlands.

View File

@ -1,6 +0,0 @@
[![GoDoc](https://godoc.org/github.com/pascaldekloe/name?status.svg)](https://godoc.org/github.com/pascaldekloe/name)
Naming convention library for the Go programming language (golang).
This is free and unencumbered software released into the
[public domain](http://creativecommons.org/publicdomain/zero/1.0).

View File

@ -1,112 +0,0 @@
// Package name implements naming conventions.
package name
import "unicode"
// CamelCase returns the medial capitals form of word sequence s.
// The input can be any case or even just a bunch of words.
// Upper case abbreviations are preserved.
// Argument upper sets the casing for the first rune.
func CamelCase(s string, upper bool) string {
if s == "" {
return ""
}
out := make([]rune, 1, len(s)+5)
for i, r := range s {
if i == 0 {
if upper {
r = unicode.ToUpper(r)
}
out[0] = r
continue
}
if i == 1 {
if !upper && unicode.Is(unicode.Lower, r) {
out[0] = unicode.ToLower(out[0])
}
upper = false
}
switch {
case unicode.IsLetter(r):
if upper {
r = unicode.ToUpper(r)
}
fallthrough
case unicode.IsNumber(r):
upper = false
out = append(out, r)
default:
upper = true
}
}
return string(out)
}
// SnakeCase is an alias for Delimit(s, '_').
func SnakeCase(s string) string {
return Delimit(s, '_')
}
// DotSeparated is an alias for Delimit(s, '.').
func DotSeparated(s string) string {
return Delimit(s, '.')
}
// Delimit returns word sequence s delimited with sep.
// The input can be any case or even just a bunch of words.
// Upper case abbreviations are preserved. Use strings.ToLower
// and strings.ToUpper to enforce a letter case.
func Delimit(s string, sep rune) string {
out := make([]rune, 0, len(s)+5)
for _, r := range s {
switch {
case unicode.IsUpper(r):
if last := len(out) - 1; last >= 0 && unicode.IsLower(out[last]) {
out = append(out, sep)
}
case unicode.IsLetter(r):
if i := len(out) - 1; i >= 0 {
if last := out[i]; unicode.IsUpper(last) {
out = out[:i]
if i > 0 && out[i-1] != sep {
out = append(out, sep)
}
out = append(out, unicode.ToLower(last))
}
}
case !unicode.IsNumber(r):
if i := len(out); i != 0 && out[i-1] != sep {
out = append(out, sep)
}
continue
}
out = append(out, r)
}
if len(out) == 0 {
return ""
}
// trim tailing separator
if i := len(out) - 1; out[i] == sep {
out = out[:i]
}
if len(out) == 1 {
out[0] = unicode.ToLower(out[0])
}
return string(out)
}

View File

@ -1,103 +0,0 @@
package name
import (
"testing"
)
type goldenCase struct {
snake, lowerCamel, upperCamel string
}
var goldenCases = []goldenCase{
{"", "", ""},
{"i", "i", "I"},
{"name", "name", "Name"},
{"ID", "ID", "ID"},
{"wi_fi", "wiFi", "WiFi"},
// single outer abbreviation
{"vitamin_C", "vitaminC", "VitaminC"},
{"T_cell", "TCell", "TCell"},
// double outer abbreviation
{"master_DB", "masterDB", "MasterDB"},
{"IO_bounds", "IOBounds", "IOBounds"},
// tripple outer abbreviation
{"main_API", "mainAPI", "MainAPI"},
{"TCP_conn", "TCPConn", "TCPConn"},
// inner abbreviation
{"raw_URL_query", "rawURLQuery", "RawURLQuery"},
// numbers
{"4x4", "4x4", "4x4"},
{"no5", "no5", "No5"},
{"DB2", "DB2", "DB2"},
{"3M", "3M", "3M"},
{"7_up", "7Up", "7Up"},
{"20th", "20th", "20th"},
}
func TestSnakeToSnake(t *testing.T) {
for _, golden := range goldenCases {
s := golden.snake
if got := SnakeCase(s); got != s {
t.Errorf("%q: got %q", s, got)
}
}
}
func TestLowerCamelToLowerCamel(t *testing.T) {
for _, golden := range goldenCases {
s := golden.lowerCamel
if got := CamelCase(s, false); got != s {
t.Errorf("%q: got %q", s, got)
}
}
}
func TestUpperCamelToUpperCamel(t *testing.T) {
for _, golden := range goldenCases {
s := golden.upperCamel
if got := CamelCase(s, true); got != s {
t.Errorf("%q: got %q", s, got)
}
}
}
func TestSnakeToLowerCamel(t *testing.T) {
for _, golden := range goldenCases {
snake, want := golden.snake, golden.lowerCamel
if got := CamelCase(snake, false); got != want {
t.Errorf("%q: got %q, want %q", snake, got, want)
}
}
}
func TestSnakeToUpperCamel(t *testing.T) {
for _, golden := range goldenCases {
snake, want := golden.snake, golden.upperCamel
if got := CamelCase(snake, true); got != want {
t.Errorf("%q: got %q, want %q", snake, got, want)
}
}
}
func TestLowerCamelToSnake(t *testing.T) {
for _, golden := range goldenCases {
camel, want := golden.lowerCamel, golden.snake
if got := SnakeCase(camel); got != want {
t.Errorf("%q: got %q, want %q", camel, got, want)
}
}
}
func TestUpperCamelToSnake(t *testing.T) {
for _, golden := range goldenCases {
camel, want := golden.upperCamel, golden.snake
if got := SnakeCase(camel); got != want {
t.Errorf("%q: got %q, want %q", camel, got, want)
}
}
}

View File

@ -1,27 +0,0 @@
package name_test
import (
"fmt"
"github.com/pascaldekloe/name"
)
func ExampleCamelCase() {
fmt.Println(name.CamelCase("pascal case", true))
fmt.Println(name.CamelCase("snake_to_camel AND CamelToCamel?", false))
// Output:
// PascalCase
// snakeToCamelANDCamelToCamel
}
func ExampleDelimit() {
// Garbage to Lisp-case:
fmt.Println(name.Delimit("* All Hype is aGoodThing (TM)", '-'))
// Builds a Java property key:
fmt.Println(name.DotSeparated("WebCrawler#socketTimeout"))
// Output:
// all-hype-is-a-good-thing-TM
// web.crawler.socket.timeout
}