forked from mirror/enumer
add -trimprefix and -autotrimprefix
This commit is contained in:
parent
fbb114e61f
commit
51d23ad531
10
README.md
10
README.md
|
@ -104,10 +104,16 @@ 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 `transform` flag was added (i.e. `enumer -type=MyType -json -transform=snake`).
|
||||
Possible values are `snake` and `kebab` for transformation to snake_case and kebab-case accordingly.
|
||||
For enum string representation transformation the `transform`, `trimprefix` and `autotrimprefix` 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.
|
||||
|
||||
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)
|
||||
|
|
|
@ -33,7 +33,7 @@ func TestEndToEnd(t *testing.T) {
|
|||
defer os.RemoveAll(dir)
|
||||
// Create stringer in temporary directory.
|
||||
stringer := filepath.Join(dir, "stringer.exe")
|
||||
err = run("go", "build", "-o", stringer, "enumer.go", "sql.go", "stringer.go", "transformer.go")
|
||||
err = run("go", "build", "-o", stringer, "enumer.go", "sql.go", "stringer.go", "transformer.go", "trim.go")
|
||||
if err != nil {
|
||||
t.Fatalf("building stringer: %s", err)
|
||||
}
|
||||
|
|
|
@ -759,7 +759,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", "", false)
|
||||
got := string(g.format())
|
||||
if got != test.output {
|
||||
t.Errorf("%s: got\n====\n%s====\nexpected\n====%s", test.name, got, test.output)
|
||||
|
|
12
stringer.go
12
stringer.go
|
@ -87,6 +87,8 @@ var (
|
|||
yaml = flag.Bool("yaml", false, "if true, yaml marshaling methods will be generated. Default: false")
|
||||
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.
|
||||
|
@ -149,7 +151,7 @@ func main() {
|
|||
|
||||
// Run generate for each type.
|
||||
for _, typeName := range types {
|
||||
g.generate(typeName, *json, *yaml, *sql, *transformMethod)
|
||||
g.generate(typeName, *json, *yaml, *sql, *transformMethod, *trimPrefix, *autoTrimPrefix)
|
||||
}
|
||||
|
||||
// Format the output.
|
||||
|
@ -301,7 +303,7 @@ func (g *Generator) transformValueNames(values []Value, transformMethod string)
|
|||
}
|
||||
|
||||
// generate produces the String method for the named type.
|
||||
func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeSQL bool, transformMethod string) {
|
||||
func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeSQL bool, transformMethod string, trimPrefix string, autoTrimPrefix bool) {
|
||||
values := make([]Value, 0, 100)
|
||||
for _, file := range g.pkg.files {
|
||||
// Set the state for this run of the walker.
|
||||
|
@ -317,6 +319,12 @@ func (g *Generator) generate(typeName string, includeJSON, includeYAML, includeS
|
|||
log.Fatalf("no values defined for type %s", typeName)
|
||||
}
|
||||
|
||||
g.trimValueNames(values, trimPrefix)
|
||||
|
||||
if autoTrimPrefix {
|
||||
g.autoTrimValueNames(values)
|
||||
}
|
||||
|
||||
g.transformValueNames(values, transformMethod)
|
||||
|
||||
runs := splitIntoRuns(values)
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
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)
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
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