forked from mirror/enumer
Remove autotrimprefix option; add basic tests for -trimprefix.
This commit is contained in:
parent
e1f9d08449
commit
bd9938fa86
|
@ -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
|
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.
|
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`).
|
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 `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.
|
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
|
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.
|
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
|
## Inspiring projects
|
||||||
* [Stringer](https://godoc.org/golang.org/x/tools/cmd/stringer)
|
* [Stringer](https://godoc.org/golang.org/x/tools/cmd/stringer)
|
||||||
* [jsonenums](https://github.com/campoy/jsonenums)
|
* [jsonenums](https://github.com/campoy/jsonenums)
|
||||||
|
|
|
@ -46,6 +46,10 @@ var goldenJSONAndSQL = []Golden{
|
||||||
{"prime", prime_json_and_sql_in, prime_json_and_sql_out},
|
{"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.
|
// Each example starts with "type XXX [u]int", with a single space separating them.
|
||||||
|
|
||||||
// Simple test: enumeration of type int starting at 0.
|
// 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) {
|
func TestGolden(t *testing.T) {
|
||||||
for _, test := range golden {
|
for _, test := range golden {
|
||||||
runGoldenTest(t, test, false, false, false)
|
runGoldenTest(t, test, false, false, false, "")
|
||||||
}
|
}
|
||||||
for _, test := range goldenJSON {
|
for _, test := range goldenJSON {
|
||||||
runGoldenTest(t, test, true, false, false)
|
runGoldenTest(t, test, true, false, false, "")
|
||||||
}
|
}
|
||||||
for _, test := range goldenYAML {
|
for _, test := range goldenYAML {
|
||||||
runGoldenTest(t, test, false, true, false)
|
runGoldenTest(t, test, false, true, false, "")
|
||||||
}
|
}
|
||||||
for _, test := range goldenSQL {
|
for _, test := range goldenSQL {
|
||||||
runGoldenTest(t, test, false, false, true)
|
runGoldenTest(t, test, false, false, true, "")
|
||||||
}
|
}
|
||||||
for _, test := range goldenJSONAndSQL {
|
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
|
var g Generator
|
||||||
input := "package test\n" + test.input
|
input := "package test\n" + test.input
|
||||||
file := test.name + ".go"
|
file := test.name + ".go"
|
||||||
|
@ -779,7 +798,7 @@ func runGoldenTest(t *testing.T, test Golden, generateJSON, generateYAML, genera
|
||||||
if len(tokens) != 3 {
|
if len(tokens) != 3 {
|
||||||
t.Fatalf("%s: need type declaration on first line", test.name)
|
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())
|
got := string(g.format())
|
||||||
if got != test.output {
|
if got != test.output {
|
||||||
t.Errorf("%s: got\n====\n%s====\nexpected\n====%s", test.name, got, test.output)
|
t.Errorf("%s: got\n====\n%s====\nexpected\n====%s", test.name, got, test.output)
|
||||||
|
|
16
stringer.go
16
stringer.go
|
@ -94,7 +94,6 @@ var (
|
||||||
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: \"\"")
|
||||||
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.
|
// Usage is a replacement usage function for the flags package.
|
||||||
|
@ -157,7 +156,7 @@ func main() {
|
||||||
|
|
||||||
// Run generate for each type.
|
// Run generate for each type.
|
||||||
for _, typeName := range types {
|
for _, typeName := range types {
|
||||||
g.generate(typeName, *json, *yaml, *sql, *transformMethod, *trimPrefix, *autoTrimPrefix)
|
g.generate(typeName, *json, *yaml, *sql, *transformMethod, *trimPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format the output.
|
// 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.
|
// 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)
|
values := make([]Value, 0, 100)
|
||||||
for _, file := range g.pkg.files {
|
for _, file := range g.pkg.files {
|
||||||
// Set the state for this run of the walker.
|
// 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)
|
g.trimValueNames(values, trimPrefix)
|
||||||
|
|
||||||
if autoTrimPrefix {
|
|
||||||
g.autoTrimValueNames(values)
|
|
||||||
}
|
|
||||||
|
|
||||||
g.transformValueNames(values, transformMethod)
|
g.transformValueNames(values, transformMethod)
|
||||||
|
|
||||||
runs := splitIntoRuns(values)
|
runs := splitIntoRuns(values)
|
||||||
|
|
47
trim.go
47
trim.go
|
@ -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)
|
|
||||||
}
|
|
32
trim_test.go
32
trim_test.go
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue