Remove autotrimprefix option; add basic tests for -trimprefix.

This commit is contained in:
Steve Atkins 2018-02-05 16:48:43 -08:00
parent e1f9d08449
commit bd9938fa86
5 changed files with 36 additions and 96 deletions

View File

@ -104,7 +104,7 @@ the JSON related methods will be generated. Similarly if the yaml flag is set to
the YAML related methods will be generated. And if the sql flag is set to true, the Scanner and Valuer interface will
be implemented to seamlessly use the enum in a database model.
For enum string representation transformation the `transform`, `trimprefix` and `autotrimprefix` flags
For enum string representation transformation the `transform` and `trimprefix` flags
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.
The default value for `transform` flag is `noop` which means no transformation will be performed.
@ -112,8 +112,6 @@ The default value for `transform` flag is `noop` which means no transformation w
If a prefix is provided via the `trimprefix` flag that 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.
If the `autotrimprefix` flag is set then if all the names in an enum have a common prefix that prefix will be removed.
## Inspiring projects
* [Stringer](https://godoc.org/golang.org/x/tools/cmd/stringer)
* [jsonenums](https://github.com/campoy/jsonenums)

View File

@ -46,6 +46,10 @@ var goldenJSONAndSQL = []Golden{
{"prime", prime_json_and_sql_in, prime_json_and_sql_out},
}
var goldenPrefix = []Golden{
{"prefix", prefix_in, day_out},
}
// Each example starts with "type XXX [u]int", with a single space separating them.
// Simple test: enumeration of type int starting at 0.
@ -751,25 +755,40 @@ func (i *Prime) Scan(value interface{}) error {
}
`
const prefix_in = `type Day int
const (
DayMonday Day = iota
DayTuesday
DayWednesday
DayThursday
DayFriday
DaySaturday
DaySunday
)
`
func TestGolden(t *testing.T) {
for _, test := range golden {
runGoldenTest(t, test, false, false, false)
runGoldenTest(t, test, false, false, false, "")
}
for _, test := range goldenJSON {
runGoldenTest(t, test, true, false, false)
runGoldenTest(t, test, true, false, false, "")
}
for _, test := range goldenYAML {
runGoldenTest(t, test, false, true, false)
runGoldenTest(t, test, false, true, false, "")
}
for _, test := range goldenSQL {
runGoldenTest(t, test, false, false, true)
runGoldenTest(t, test, false, false, true, "")
}
for _, test := range goldenJSONAndSQL {
runGoldenTest(t, test, true, false, true)
runGoldenTest(t, test, true, false, true, "")
}
for _, test := range goldenPrefix {
runGoldenTest(t, test, false, false, false, "Day")
}
}
func runGoldenTest(t *testing.T, test Golden, generateJSON, generateYAML, generateSQL bool) {
func runGoldenTest(t *testing.T, test Golden, generateJSON, generateYAML, generateSQL bool, prefix string) {
var g Generator
input := "package test\n" + test.input
file := test.name + ".go"
@ -779,7 +798,7 @@ func runGoldenTest(t *testing.T, test Golden, generateJSON, generateYAML, genera
if len(tokens) != 3 {
t.Fatalf("%s: need type declaration on first line", test.name)
}
g.generate(tokens[1], generateJSON, generateYAML, generateSQL, "noop")
g.generate(tokens[1], generateJSON, generateYAML, generateSQL, "noop", prefix)
got := string(g.format())
if got != test.output {
t.Errorf("%s: got\n====\n%s====\nexpected\n====%s", test.name, got, test.output)

View File

@ -94,7 +94,6 @@ var (
output = flag.String("output", "", "output file name; default srcdir/<type>_string.go")
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: \"\"")
autoTrimPrefix = flag.Bool("autotrimprefix", false, "if true, remove a common prefix from each item name. Default: false")
)
// Usage is a replacement usage function for the flags package.
@ -157,7 +156,7 @@ func main() {
// Run generate for each type.
for _, typeName := range types {
g.generate(typeName, *json, *yaml, *sql, *transformMethod, *trimPrefix, *autoTrimPrefix)
g.generate(typeName, *json, *yaml, *sql, *transformMethod, *trimPrefix)
}
// Format the output.
@ -308,8 +307,15 @@ func (g *Generator) transformValueNames(values []Value, transformMethod string)
}
}
// trimValueNames removes a prefix from each name
func (g *Generator) trimValueNames(values []Value, prefix string) {
for i := range values {
values[i].name = strings.TrimPrefix(values[i].name, prefix)
}
}
// generate produces the String method for the named type.
func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeSQL bool, transformMethod string, trimPrefix string, autoTrimPrefix bool) {
func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeSQL bool, transformMethod string, trimPrefix string) {
values := make([]Value, 0, 100)
for _, file := range g.pkg.files {
// Set the state for this run of the walker.
@ -327,10 +333,6 @@ func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeS
g.trimValueNames(values, trimPrefix)
if autoTrimPrefix {
g.autoTrimValueNames(values)
}
g.transformValueNames(values, transformMethod)
runs := splitIntoRuns(values)

47
trim.go
View File

@ -1,47 +0,0 @@
package main
import "strings"
func longestCommonPrefix(values []Value) string {
// LCP of min and max (lexigraphically)
// is the LCP of the whole set.
min := values[0].name
max := min
for _, s := range values[1:] {
switch {
case s.name < min:
min = s.name
case s.name > max:
max = s.name
}
}
for i := 0; i < len(min) && i < len(max); i++ {
if min[i] != max[i] {
return min[:i]
}
}
// If all the bytes are equal but the lengths aren't then
// min is a prefix of max, and hence the lcp
return min
}
func autoPrefix(values []Value) string {
// Can't trim a single value
if len(values) < 2 {
return ""
}
prefix := longestCommonPrefix(values)
return prefix
}
func (g *Generator) trimValueNames(values []Value, prefix string) {
for i := range values {
values[i].name = strings.TrimPrefix(values[i].name, prefix)
}
}
func (g *Generator) autoTrimValueNames(values []Value) {
prefix := autoPrefix(values)
g.trimValueNames(values, prefix)
}

View File

@ -1,32 +0,0 @@
package main
import "testing"
var lcpTests = []struct {
expected string
in []string
}{
{"Proto", []string{"ProtoOne", "ProtoTwo", "ProtoThree"}},
// An empty string is OK when one value is the prefix
{"Proto", []string{"Proto", "ProtoLonger"}},
{"", []string{}},
{"", []string{"aardvark"}},
{"", []string{"abc", "def", "deg"}},
{"ab", []string{"ab", "abc", "abcd"}},
}
// TestLcp checks that the longest common prefix is generated correctly
func TestLcp(t *testing.T) {
for _, tt := range lcpTests {
values := make([]Value, len(tt.in))
for i := range tt.in {
values[i] = Value{
name: tt.in[i],
}
}
prefix := autoPrefix(values)
if prefix != tt.expected {
t.Errorf("%q => %s, expected %s", tt.in, tt.expected, prefix)
}
}
}