From 6ee8be15d5956175a25c1bbb5c96e28e5acb7a5c Mon Sep 17 00:00:00 2001 From: Vadim Petrov Date: Wed, 8 Jun 2016 18:08:55 +0300 Subject: [PATCH 1/6] Added camel_case_functions flag which make CamelCase function names (according to default Go naming convention) --- Makefile | 6 ++- bootstrap/bootstrap.go | 14 ++++--- easyjson/main.go | 28 +++++++------ gen/decoder.go | 8 ++-- gen/encoder.go | 18 ++++---- gen/generator.go | 79 ++++++++++++++++++++++++++++------- gen/generator_test.go | 37 ++++++++++++++++ tests/basic_test.go | 1 + tests/camel_case_functions.go | 9 ++++ 9 files changed, 153 insertions(+), 47 deletions(-) create mode 100644 tests/camel_case_functions.go diff --git a/Makefile b/Makefile index 420f306..b98f8b1 100644 --- a/Makefile +++ b/Makefile @@ -20,11 +20,13 @@ generate: root build .root/bin/easyjson -stubs \ .root/src/$(PKG)/tests/snake.go \ .root/src/$(PKG)/tests/data.go \ - .root/src/$(PKG)/tests/omitempty.go + .root/src/$(PKG)/tests/omitempty.go \ + .root/src/$(PKG)/tests/camel_case_functions.go .root/bin/easyjson -all .root/src/$(PKG)/tests/data.go .root/bin/easyjson -snake_case .root/src/$(PKG)/tests/snake.go - .root/bin/easyjson -omit_empty .root/src/$(PKG)/tests/omitempty.go + .root/bin/easyjson -omit_empty .root/src/$(PKG)/tests/omitempty.go + .root/bin/easyjson -camel_case_functions .root/src/$(PKG)/tests/camel_case_functions.go .root/bin/easyjson -build_tags=use_easyjson .root/src/$(PKG)/benchmark/data.go test: generate root diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index e9a1d21..8bca39a 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -21,9 +21,10 @@ type Generator struct { PkgPath, PkgName string Types []string - NoStdMarshalers bool - SnakeCase bool - OmitEmpty bool + NoStdMarshalers bool + SnakeCaseFields bool + CamelCaseFunctions bool + OmitEmpty bool OutName string BuildTags string @@ -100,8 +101,11 @@ func (g *Generator) writeMain() (path string, err error) { if g.BuildTags != "" { fmt.Fprintf(f, " g.SetBuildTags(%q)\n", g.BuildTags) } - if g.SnakeCase { - fmt.Fprintln(f, " g.UseSnakeCase()") + if g.SnakeCaseFields { + fmt.Fprintln(f, " g.UseSnakeCaseFieldNamer()") + } + if g.CamelCaseFunctions { + fmt.Fprintln(f, " g.UseCamelCaseFunctionNamer()") } if g.OmitEmpty { fmt.Fprintln(f, " g.OmitEmpty()") diff --git a/easyjson/main.go b/easyjson/main.go index f82e3f7..e6d6689 100644 --- a/easyjson/main.go +++ b/easyjson/main.go @@ -15,7 +15,8 @@ import ( ) var buildTags = flag.String("build_tags", "", "build tags to add to generated file") -var snakeCase = flag.Bool("snake_case", false, "use snake_case names instead of CamelCase by default") +var snakeCaseFields = flag.Bool("snake_case", false, "use snake_case names instead of CamelCase by default") +var camelCaseFunctions = flag.Bool("camel_case_functions", false, "create functions with CamelCase names instead of under_score by default") var noStdMarshalers = flag.Bool("no_std_marshalers", false, "don't generate MarshalJSON/UnmarshalJSON methods") var omitEmpty = flag.Bool("omit_empty", false, "omit empty fields by default") var allStructs = flag.Bool("all", false, "generate un-/marshallers for all structs in a file") @@ -40,19 +41,20 @@ func generate(fname string) (err error) { if *specifiedName != "" { outName = *specifiedName } - + g := bootstrap.Generator{ - BuildTags: *buildTags, - PkgPath: p.PkgPath, - PkgName: p.PkgName, - Types: p.StructNames, - SnakeCase: *snakeCase, - NoStdMarshalers: *noStdMarshalers, - OmitEmpty: *omitEmpty, - LeaveTemps: *leaveTemps, - OutName: outName, - StubsOnly: *stubs, - NoFormat: *noformat, + BuildTags: *buildTags, + PkgPath: p.PkgPath, + PkgName: p.PkgName, + Types: p.StructNames, + SnakeCaseFields: *snakeCaseFields, + CamelCaseFunctions: *camelCaseFunctions, + NoStdMarshalers: *noStdMarshalers, + OmitEmpty: *omitEmpty, + LeaveTemps: *leaveTemps, + OutName: outName, + StubsOnly: *stubs, + NoFormat: *noformat, } if err := g.Run(); err != nil { diff --git a/gen/decoder.go b/gen/decoder.go index a1291fc..706f77b 100644 --- a/gen/decoder.go +++ b/gen/decoder.go @@ -14,7 +14,7 @@ import ( const minSliceBytes = 64 func (g *Generator) getStructDecoderName(t reflect.Type) string { - return g.functionName("decode_", t) + return g.functionName("decode", t) } var primitiveDecoders = map[reflect.Kind]string{ @@ -162,7 +162,7 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, tags fieldTags, i } func (g *Generator) genStructFieldDecoder(t reflect.Type, f reflect.StructField) error { - jsonName := g.namer.GetJSONFieldName(t, f) + jsonName := g.fieldNamer.GetJSONFieldName(t, f) tags := parseFieldTags(f) if tags.omit { @@ -192,7 +192,7 @@ func (g *Generator) genRequiredFieldSet(t reflect.Type, f reflect.StructField) { } func (g *Generator) genRequiredFieldCheck(t reflect.Type, f reflect.StructField) { - jsonName := g.namer.GetJSONFieldName(t, f) + jsonName := g.fieldNamer.GetJSONFieldName(t, f) tags := parseFieldTags(f) if !tags.required { @@ -334,6 +334,7 @@ func (g *Generator) genStructUnmarshaller(t reflect.Type) error { typ := g.getType(t) if !g.noStdMarshalers { + fmt.Fprintln(g.out, "// UnmarshalJSON supports json.Unmarshaler interface") fmt.Fprintln(g.out, "func (v *"+typ+") UnmarshalJSON(data []byte) error {") fmt.Fprintln(g.out, " r := jlexer.Lexer{Data: data}") fmt.Fprintln(g.out, " "+fname+"(&r, v)") @@ -341,6 +342,7 @@ func (g *Generator) genStructUnmarshaller(t reflect.Type) error { fmt.Fprintln(g.out, "}") } + fmt.Fprintln(g.out, "// UnmarshalEasyJSON supports easyjson.Unmarshaler interface") fmt.Fprintln(g.out, "func (v *"+typ+") UnmarshalEasyJSON(l *jlexer.Lexer) {") fmt.Fprintln(g.out, " "+fname+"(l, v)") fmt.Fprintln(g.out, "}") diff --git a/gen/encoder.go b/gen/encoder.go index c263c21..f860e79 100644 --- a/gen/encoder.go +++ b/gen/encoder.go @@ -11,7 +11,7 @@ import ( ) func (g *Generator) getStructEncoderName(t reflect.Type) string { - return g.functionName("encode_", t) + return g.functionName("encode", t) } var primitiveEncoders = map[reflect.Kind]string{ @@ -147,14 +147,14 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, in fmt.Fprintln(g.out, ws+" out.RawString(`null`)") fmt.Fprintln(g.out, ws+"} else {") fmt.Fprintln(g.out, ws+" out.RawByte('{')") - fmt.Fprintln(g.out, ws+" "+tmpVar+"_first := true") - fmt.Fprintln(g.out, ws+" for "+tmpVar+"_name, "+tmpVar+"_value := range "+in+" {") - fmt.Fprintln(g.out, ws+" if !"+tmpVar+"_first { out.RawByte(',') }") - fmt.Fprintln(g.out, ws+" "+tmpVar+"_first = false") - fmt.Fprintln(g.out, ws+" out.String(string("+tmpVar+"_name))") + fmt.Fprintln(g.out, ws+" "+tmpVar+"First := true") + fmt.Fprintln(g.out, ws+" for "+tmpVar+"Name, "+tmpVar+"Value := range "+in+" {") + fmt.Fprintln(g.out, ws+" if !"+tmpVar+"First { out.RawByte(',') }") + fmt.Fprintln(g.out, ws+" "+tmpVar+"First = false") + fmt.Fprintln(g.out, ws+" out.String(string("+tmpVar+"Name))") fmt.Fprintln(g.out, ws+" out.RawByte(':')") - g.genTypeEncoder(t.Elem(), tmpVar+"_value", tags, indent+2) + g.genTypeEncoder(t.Elem(), tmpVar+"Value", tags, indent+2) fmt.Fprintln(g.out, ws+" }") fmt.Fprintln(g.out, ws+" out.RawByte('}')") @@ -199,7 +199,7 @@ func (g *Generator) notEmptyCheck(t reflect.Type, v string) string { } func (g *Generator) genStructFieldEncoder(t reflect.Type, f reflect.StructField) error { - jsonName := g.namer.GetJSONFieldName(t, f) + jsonName := g.fieldNamer.GetJSONFieldName(t, f) tags := parseFieldTags(f) if tags.omit { @@ -262,6 +262,7 @@ func (g *Generator) genStructMarshaller(t reflect.Type) error { typ := g.getType(t) if !g.noStdMarshalers { + fmt.Fprintln(g.out, "// MarshalJSON supports json.Marshaler interface") fmt.Fprintln(g.out, "func (v "+typ+") MarshalJSON() ([]byte, error) {") fmt.Fprintln(g.out, " w := jwriter.Writer{}") fmt.Fprintln(g.out, " "+fname+"(&w, v)") @@ -269,6 +270,7 @@ func (g *Generator) genStructMarshaller(t reflect.Type) error { fmt.Fprintln(g.out, "}") } + fmt.Fprintln(g.out, "// MarshalEasyJSON supports easyjson.Marshaler interface") fmt.Fprintln(g.out, "func (v "+typ+") MarshalEasyJSON(w *jwriter.Writer) {") fmt.Fprintln(g.out, " "+fname+"(w, v)") fmt.Fprintln(g.out, "}") diff --git a/gen/generator.go b/gen/generator.go index 07e19fc..90d0743 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -20,6 +20,11 @@ type FieldNamer interface { GetJSONFieldName(t reflect.Type, f reflect.StructField) string } +// FuncNamer defines a policy for generating function names +type FunctionNamer interface { + GetName(keepFirst bool, parts ...string) string +} + // Generator generates the requested marshallers/unmarshallers. type Generator struct { out *bytes.Buffer @@ -27,13 +32,14 @@ type Generator struct { pkgName string pkgPath string buildTags string - funcPrefix string + hashString string varCounter int noStdMarshalers bool omitEmpty bool - namer FieldNamer + fieldNamer FieldNamer + functionNamer FunctionNamer // package path to local alias map for tracking imports imports map[string]string @@ -60,7 +66,9 @@ func NewGenerator(filename string) *Generator { pkgLexer: "jlexer", "encoding/json": "json", }, - namer: DefaultFieldNamer{}, + fieldNamer: DefaultFieldNamer{}, + functionNamer: UnderScoreFunctionNamer{}, + //functionNamer: CamelCaseFunctionNamer{}, marshallers: make(map[reflect.Type]bool), typesSeen: make(map[reflect.Type]bool), functionNames: make(map[string]reflect.Type), @@ -70,7 +78,7 @@ func NewGenerator(filename string) *Generator { // name clashes. hash := fnv.New32() hash.Write([]byte(filename)) - ret.funcPrefix = fmt.Sprintf("easyjson_%x_", hash.Sum32()) + ret.hashString = fmt.Sprintf("%x", hash.Sum32()) return ret } @@ -88,12 +96,22 @@ func (g *Generator) SetBuildTags(tags string) { // SetFieldNamer sets field naming strategy. func (g *Generator) SetFieldNamer(n FieldNamer) { - g.namer = n + g.fieldNamer = n } -// UseSnakeCase sets snake_case field naming strategy. -func (g *Generator) UseSnakeCase() { - g.namer = SnakeCaseFieldNamer{} +// UseSnakeCaseFieldNamer sets snake_case field naming strategy. +func (g *Generator) UseSnakeCaseFieldNamer() { + g.fieldNamer = SnakeCaseFieldNamer{} +} + +// SetFunctionNamer sets function naming strategy. +func (g *Generator) SetFunctionNamer(n FunctionNamer) { + g.functionNamer = n +} + +// UseCamelCaseFunctionNamer sets CamelCase function naming strategy. +func (g *Generator) UseCamelCaseFunctionNamer() { + g.functionNamer = CamelCaseFunctionNamer{} } // NoStdMarshalers instructs not to generate standard MarshalJSON/UnmarshalJSON @@ -243,7 +261,7 @@ func (g *Generator) uniqueVarName() string { // safeName escapes unsafe characters in pkg/type name and returns a string that can be used // in encoder/decoder names for the type. -func safeName(t reflect.Type) string { +func (g *Generator) safeName(t reflect.Type) string { name := t.PkgPath() if t.Name() == "" { name += "anonymous" @@ -251,15 +269,17 @@ func safeName(t reflect.Type) string { name += "." + t.Name() } - var ret []rune + parts := []string{} + part := []rune{} for _, c := range name { if unicode.IsLetter(c) || unicode.IsDigit(c) { - ret = append(ret, c) - } else { - ret = append(ret, '_') + part = append(part, c) + } else if len(part) > 0 { + parts = append(parts, string(part)) + part = []rune{} } } - return string(ret) + return g.functionNamer.GetName(false, parts...) } // functionName returns a function name for a given type with a given prefix. If a function @@ -267,8 +287,8 @@ func safeName(t reflect.Type) string { // // Method is used to track encoder/decoder names for the type. func (g *Generator) functionName(prefix string, t reflect.Type) string { - prefix = g.funcPrefix + prefix - name := prefix + safeName(t) + prefix = g.functionNamer.GetName(true, "easyjson", g.hashString, prefix) + name := g.functionNamer.GetName(true, prefix, g.safeName(t)) // Most of the names will be unique, try a shortcut first. if e, ok := g.functionNames[name]; !ok || e == t { @@ -362,3 +382,30 @@ func (SnakeCaseFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructFiel return camelToSnake(f.Name) } + +// CamelCaseFunctionNamer implements FunctionNamer interface with CamelCase format +type CamelCaseFunctionNamer struct{} + +func (CamelCaseFunctionNamer) GetName(keepFirst bool, parts ...string) string { + buf := bytes.NewBufferString("") + for i, part := range parts { + if i == 0 && keepFirst { + buf.WriteString(part) + } else { + if len(part) > 0 { + buf.WriteString(strings.ToUpper(string(part[0]))) + } + if len(part) > 1 { + buf.WriteString(part[1:]) + } + } + } + return buf.String() +} + +// UnderScoreFunctionNamer implements FunctionNamer interface with under_score format +type UnderScoreFunctionNamer struct{} + +func (UnderScoreFunctionNamer) GetName(keepFirst bool, parts ...string) string { + return strings.Join(parts, "_") +} diff --git a/gen/generator_test.go b/gen/generator_test.go index 7388bec..64e164d 100644 --- a/gen/generator_test.go +++ b/gen/generator_test.go @@ -4,6 +4,13 @@ import ( "testing" ) +type functionNamerCase struct { + keepFirst bool + parts []string + camelCaseOut string + underScoreOut string +} + func TestCamelToSnake(t *testing.T) { for i, test := range []struct { In, Out string @@ -26,5 +33,35 @@ func TestCamelToSnake(t *testing.T) { t.Errorf("[%d] camelToSnake(%s) = %s; want %s", i, test.In, got, test.Out) } } +} +func getFunctionNamerCases() []functionNamerCase { + return []functionNamerCase{ + functionNamerCase{false, []string{}, "", ""}, + functionNamerCase{false, []string{"a"}, "A", "a"}, + functionNamerCase{false, []string{"simple", "example"}, "SimpleExample", "simple_example"}, + functionNamerCase{true, []string{"first", "example"}, "firstExample", "first_example"}, + functionNamerCase{false, []string{"some", "UPPER", "case"}, "SomeUPPERCase", "some_UPPER_case"}, + functionNamerCase{false, []string{"number", "123"}, "Number123", "number_123"}, + } +} + +func TestCamelCaseFunctionNamer(t *testing.T) { + namer := CamelCaseFunctionNamer{} + for i, test := range getFunctionNamerCases() { + got := namer.GetName(test.keepFirst, test.parts...) + if got != test.camelCaseOut { + t.Errorf("[%d] CamelCaseFunctionNamer.GetName(%v) = %s; want %s", i, test.parts, got, test.camelCaseOut) + } + } +} + +func TestUnderScoreFunctionNamer(t *testing.T) { + namer := UnderScoreFunctionNamer{} + for i, test := range getFunctionNamerCases() { + got := namer.GetName(test.keepFirst, test.parts...) + if got != test.underScoreOut { + t.Errorf("[%d] UnderScoreFunctionNamer.GetName(%v) = %s; want %s", i, test.parts, got, test.underScoreOut) + } + } } diff --git a/tests/basic_test.go b/tests/basic_test.go index a6a0413..7d18e3b 100644 --- a/tests/basic_test.go +++ b/tests/basic_test.go @@ -30,6 +30,7 @@ var testCases = []struct { {&unexportedStructValue, unexportedStructString}, {&excludedFieldValue, excludedFieldString}, {&mapsValue, mapsString}, + {&camelCasesFunctionsValue, camelCasesFunctionsString}, } func TestMarshal(t *testing.T) { diff --git a/tests/camel_case_functions.go b/tests/camel_case_functions.go new file mode 100644 index 0000000..94a44e8 --- /dev/null +++ b/tests/camel_case_functions.go @@ -0,0 +1,9 @@ +package tests + +//easyjson:json +type CamelCasesFunctions struct { + Field string +} + +var camelCasesFunctionsValue = CamelCasesFunctions{Field: "test"} +var camelCasesFunctionsString = `{"Field":"test"}` From f9e323601d1d4c8ff95a1932266a4ccdffd6edc4 Mon Sep 17 00:00:00 2001 From: Vadim Petrov Date: Wed, 8 Jun 2016 18:54:07 +0300 Subject: [PATCH 2/6] Added camel_case_functions flag description to readme --- README.md | 2 ++ easyjson/main.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e990111..913777b 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ Usage of .root/bin/easyjson: use snake_case names instead of CamelCase by default -stubs only generate stubs for marshallers/unmarshallers methods + -camel_case_functions + generate functions with CamelCase names instead of under_score by default ``` Using `-all` will generate (un-)marshallers for all structs in the file. By default, structs need to have a line beginning with `easyjson:json` in their docstring, e.g.: diff --git a/easyjson/main.go b/easyjson/main.go index e6d6689..7fe83a6 100644 --- a/easyjson/main.go +++ b/easyjson/main.go @@ -16,7 +16,7 @@ import ( var buildTags = flag.String("build_tags", "", "build tags to add to generated file") var snakeCaseFields = flag.Bool("snake_case", false, "use snake_case names instead of CamelCase by default") -var camelCaseFunctions = flag.Bool("camel_case_functions", false, "create functions with CamelCase names instead of under_score by default") +var camelCaseFunctions = flag.Bool("camel_case_functions", false, "generate functions with CamelCase names instead of under_score by default") var noStdMarshalers = flag.Bool("no_std_marshalers", false, "don't generate MarshalJSON/UnmarshalJSON methods") var omitEmpty = flag.Bool("omit_empty", false, "omit empty fields by default") var allStructs = flag.Bool("all", false, "generate un-/marshallers for all structs in a file") From 1e858c72a3870f91734432258f06d825fc81b38b Mon Sep 17 00:00:00 2001 From: Vadim Petrov Date: Thu, 28 Jul 2016 12:12:41 +0300 Subject: [PATCH 3/6] Remove -camel_case_functions flag and generate CamelCase function names by default. --- Makefile | 2 -- README.md | 2 -- bootstrap/bootstrap.go | 10 +++------- easyjson/main.go | 24 +++++++++++------------- gen/generator.go | 20 +------------------- gen/generator_test.go | 10 ---------- tests/basic_test.go | 1 - tests/camel_case_functions.go | 9 --------- 8 files changed, 15 insertions(+), 63 deletions(-) delete mode 100644 tests/camel_case_functions.go diff --git a/Makefile b/Makefile index 1867f28..be2793d 100644 --- a/Makefile +++ b/Makefile @@ -22,13 +22,11 @@ generate: root build .root/src/$(PKG)/tests/data.go \ .root/src/$(PKG)/tests/omitempty.go \ .root/src/$(PKG)/tests/nothing.go \ - .root/src/$(PKG)/tests/camel_case_functions.go .root/bin/easyjson -all .root/src/$(PKG)/tests/data.go .root/bin/easyjson -all .root/src/$(PKG)/tests/nothing.go .root/bin/easyjson -snake_case .root/src/$(PKG)/tests/snake.go .root/bin/easyjson -omit_empty .root/src/$(PKG)/tests/omitempty.go - .root/bin/easyjson -camel_case_functions .root/src/$(PKG)/tests/camel_case_functions.go .root/bin/easyjson -build_tags=use_easyjson .root/src/$(PKG)/benchmark/data.go test: generate root diff --git a/README.md b/README.md index 913777b..e990111 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,6 @@ Usage of .root/bin/easyjson: use snake_case names instead of CamelCase by default -stubs only generate stubs for marshallers/unmarshallers methods - -camel_case_functions - generate functions with CamelCase names instead of under_score by default ``` Using `-all` will generate (un-)marshallers for all structs in the file. By default, structs need to have a line beginning with `easyjson:json` in their docstring, e.g.: diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index 39b706f..f9cf3b6 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -21,10 +21,9 @@ type Generator struct { PkgPath, PkgName string Types []string - NoStdMarshalers bool - SnakeCaseFields bool - CamelCaseFunctions bool - OmitEmpty bool + NoStdMarshalers bool + SnakeCaseFields bool + OmitEmpty bool OutName string BuildTags string @@ -109,9 +108,6 @@ func (g *Generator) writeMain() (path string, err error) { if g.SnakeCaseFields { fmt.Fprintln(f, " g.UseSnakeCaseFieldNamer()") } - if g.CamelCaseFunctions { - fmt.Fprintln(f, " g.UseCamelCaseFunctionNamer()") - } if g.OmitEmpty { fmt.Fprintln(f, " g.OmitEmpty()") } diff --git a/easyjson/main.go b/easyjson/main.go index 7fe83a6..abcd183 100644 --- a/easyjson/main.go +++ b/easyjson/main.go @@ -16,7 +16,6 @@ import ( var buildTags = flag.String("build_tags", "", "build tags to add to generated file") var snakeCaseFields = flag.Bool("snake_case", false, "use snake_case names instead of CamelCase by default") -var camelCaseFunctions = flag.Bool("camel_case_functions", false, "generate functions with CamelCase names instead of under_score by default") var noStdMarshalers = flag.Bool("no_std_marshalers", false, "don't generate MarshalJSON/UnmarshalJSON methods") var omitEmpty = flag.Bool("omit_empty", false, "omit empty fields by default") var allStructs = flag.Bool("all", false, "generate un-/marshallers for all structs in a file") @@ -43,18 +42,17 @@ func generate(fname string) (err error) { } g := bootstrap.Generator{ - BuildTags: *buildTags, - PkgPath: p.PkgPath, - PkgName: p.PkgName, - Types: p.StructNames, - SnakeCaseFields: *snakeCaseFields, - CamelCaseFunctions: *camelCaseFunctions, - NoStdMarshalers: *noStdMarshalers, - OmitEmpty: *omitEmpty, - LeaveTemps: *leaveTemps, - OutName: outName, - StubsOnly: *stubs, - NoFormat: *noformat, + BuildTags: *buildTags, + PkgPath: p.PkgPath, + PkgName: p.PkgName, + Types: p.StructNames, + SnakeCaseFields: *snakeCaseFields, + NoStdMarshalers: *noStdMarshalers, + OmitEmpty: *omitEmpty, + LeaveTemps: *leaveTemps, + OutName: outName, + StubsOnly: *stubs, + NoFormat: *noformat, } if err := g.Run(); err != nil { diff --git a/gen/generator.go b/gen/generator.go index fe7d4e2..9ebe4f5 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -67,8 +67,7 @@ func NewGenerator(filename string) *Generator { "encoding/json": "json", }, fieldNamer: DefaultFieldNamer{}, - functionNamer: UnderScoreFunctionNamer{}, - //functionNamer: CamelCaseFunctionNamer{}, + functionNamer: CamelCaseFunctionNamer{}, marshallers: make(map[reflect.Type]bool), typesSeen: make(map[reflect.Type]bool), functionNames: make(map[string]reflect.Type), @@ -104,16 +103,6 @@ func (g *Generator) UseSnakeCaseFieldNamer() { g.fieldNamer = SnakeCaseFieldNamer{} } -// SetFunctionNamer sets function naming strategy. -func (g *Generator) SetFunctionNamer(n FunctionNamer) { - g.functionNamer = n -} - -// UseCamelCaseFunctionNamer sets CamelCase function naming strategy. -func (g *Generator) UseCamelCaseFunctionNamer() { - g.functionNamer = CamelCaseFunctionNamer{} -} - // NoStdMarshalers instructs not to generate standard MarshalJSON/UnmarshalJSON // methods (only the custom interface). func (g *Generator) NoStdMarshalers() { @@ -414,10 +403,3 @@ func (CamelCaseFunctionNamer) GetName(keepFirst bool, parts ...string) string { } return buf.String() } - -// UnderScoreFunctionNamer implements FunctionNamer interface with under_score format -type UnderScoreFunctionNamer struct{} - -func (UnderScoreFunctionNamer) GetName(keepFirst bool, parts ...string) string { - return strings.Join(parts, "_") -} diff --git a/gen/generator_test.go b/gen/generator_test.go index 64e164d..ee77d17 100644 --- a/gen/generator_test.go +++ b/gen/generator_test.go @@ -55,13 +55,3 @@ func TestCamelCaseFunctionNamer(t *testing.T) { } } } - -func TestUnderScoreFunctionNamer(t *testing.T) { - namer := UnderScoreFunctionNamer{} - for i, test := range getFunctionNamerCases() { - got := namer.GetName(test.keepFirst, test.parts...) - if got != test.underScoreOut { - t.Errorf("[%d] UnderScoreFunctionNamer.GetName(%v) = %s; want %s", i, test.parts, got, test.underScoreOut) - } - } -} diff --git a/tests/basic_test.go b/tests/basic_test.go index 0450c67..d2eac28 100644 --- a/tests/basic_test.go +++ b/tests/basic_test.go @@ -33,7 +33,6 @@ var testCases = []struct { {&mapsValue, mapsString}, {&deepNestValue, deepNestString}, {&IntsValue, IntsString}, - {&camelCasesFunctionsValue, camelCasesFunctionsString}, } func TestMarshal(t *testing.T) { diff --git a/tests/camel_case_functions.go b/tests/camel_case_functions.go deleted file mode 100644 index 94a44e8..0000000 --- a/tests/camel_case_functions.go +++ /dev/null @@ -1,9 +0,0 @@ -package tests - -//easyjson:json -type CamelCasesFunctions struct { - Field string -} - -var camelCasesFunctionsValue = CamelCasesFunctions{Field: "test"} -var camelCasesFunctionsString = `{"Field":"test"}` From d96b409c3fb67a9a66d847adcf7e92f106d02dcd Mon Sep 17 00:00:00 2001 From: Vadim Petrov Date: Thu, 28 Jul 2016 12:24:59 +0300 Subject: [PATCH 4/6] Run golint to check generated files --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index be2793d..6fcdd70 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,8 @@ test: generate root $(PKG)/gen \ $(PKG)/buffer go test -benchmem -tags use_easyjson -bench . $(PKG)/benchmark + go get -u github.com/golang/lint/golint + golint -set_exit_status .root/src/$(PKG)/tests/*_easyjson.go bench-other: generate root @go test -benchmem -bench . $(PKG)/benchmark From 78f430884b63a1582c55dcb1d863ab675dbcc6ad Mon Sep 17 00:00:00 2001 From: Vadim Petrov Date: Thu, 28 Jul 2016 12:30:40 +0300 Subject: [PATCH 5/6] Move installing of github.com/golang/lint/golint to travis config file --- .travis.yml | 1 + Makefile | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2b3c415..3e5ac13 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,4 @@ go: install: - go get github.com/ugorji/go/codec - go get github.com/pquerna/ffjson/fflib/v1 + - go get github.com/golang/lint/golint diff --git a/Makefile b/Makefile index 6fcdd70..351f969 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,6 @@ test: generate root $(PKG)/gen \ $(PKG)/buffer go test -benchmem -tags use_easyjson -bench . $(PKG)/benchmark - go get -u github.com/golang/lint/golint golint -set_exit_status .root/src/$(PKG)/tests/*_easyjson.go bench-other: generate root From ad87fe465206bf2ce370dc77bbb209d3e0480d14 Mon Sep 17 00:00:00 2001 From: Vadim Petrov Date: Thu, 28 Jul 2016 14:24:17 +0300 Subject: [PATCH 6/6] Remove functionNamer interface --- Makefile | 2 +- bootstrap/bootstrap.go | 6 +++--- easyjson/main.go | 4 ++-- gen/generator.go | 22 ++++++---------------- gen/generator_test.go | 40 ++++++++++++++++------------------------ 5 files changed, 28 insertions(+), 46 deletions(-) diff --git a/Makefile b/Makefile index 351f969..5a95104 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ generate: root build .root/src/$(PKG)/tests/snake.go \ .root/src/$(PKG)/tests/data.go \ .root/src/$(PKG)/tests/omitempty.go \ - .root/src/$(PKG)/tests/nothing.go \ + .root/src/$(PKG)/tests/nothing.go .root/bin/easyjson -all .root/src/$(PKG)/tests/data.go .root/bin/easyjson -all .root/src/$(PKG)/tests/nothing.go diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index f9cf3b6..04aaaad 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -22,7 +22,7 @@ type Generator struct { Types []string NoStdMarshalers bool - SnakeCaseFields bool + SnakeCase bool OmitEmpty bool OutName string @@ -105,8 +105,8 @@ func (g *Generator) writeMain() (path string, err error) { if g.BuildTags != "" { fmt.Fprintf(f, " g.SetBuildTags(%q)\n", g.BuildTags) } - if g.SnakeCaseFields { - fmt.Fprintln(f, " g.UseSnakeCaseFieldNamer()") + if g.SnakeCase { + fmt.Fprintln(f, " g.UseSnakeCase()") } if g.OmitEmpty { fmt.Fprintln(f, " g.OmitEmpty()") diff --git a/easyjson/main.go b/easyjson/main.go index abcd183..8ae9223 100644 --- a/easyjson/main.go +++ b/easyjson/main.go @@ -15,7 +15,7 @@ import ( ) var buildTags = flag.String("build_tags", "", "build tags to add to generated file") -var snakeCaseFields = flag.Bool("snake_case", false, "use snake_case names instead of CamelCase by default") +var snakeCase = flag.Bool("snake_case", false, "use snake_case names instead of CamelCase by default") var noStdMarshalers = flag.Bool("no_std_marshalers", false, "don't generate MarshalJSON/UnmarshalJSON methods") var omitEmpty = flag.Bool("omit_empty", false, "omit empty fields by default") var allStructs = flag.Bool("all", false, "generate un-/marshallers for all structs in a file") @@ -46,7 +46,7 @@ func generate(fname string) (err error) { PkgPath: p.PkgPath, PkgName: p.PkgName, Types: p.StructNames, - SnakeCaseFields: *snakeCaseFields, + SnakeCase: *snakeCase, NoStdMarshalers: *noStdMarshalers, OmitEmpty: *omitEmpty, LeaveTemps: *leaveTemps, diff --git a/gen/generator.go b/gen/generator.go index 9ebe4f5..2a3ef9c 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -20,11 +20,6 @@ type FieldNamer interface { GetJSONFieldName(t reflect.Type, f reflect.StructField) string } -// FuncNamer defines a policy for generating function names -type FunctionNamer interface { - GetName(keepFirst bool, parts ...string) string -} - // Generator generates the requested marshallers/unmarshallers. type Generator struct { out *bytes.Buffer @@ -39,7 +34,6 @@ type Generator struct { noStdMarshalers bool omitEmpty bool fieldNamer FieldNamer - functionNamer FunctionNamer // package path to local alias map for tracking imports imports map[string]string @@ -67,7 +61,6 @@ func NewGenerator(filename string) *Generator { "encoding/json": "json", }, fieldNamer: DefaultFieldNamer{}, - functionNamer: CamelCaseFunctionNamer{}, marshallers: make(map[reflect.Type]bool), typesSeen: make(map[reflect.Type]bool), functionNames: make(map[string]reflect.Type), @@ -98,8 +91,8 @@ func (g *Generator) SetFieldNamer(n FieldNamer) { g.fieldNamer = n } -// UseSnakeCaseFieldNamer sets snake_case field naming strategy. -func (g *Generator) UseSnakeCaseFieldNamer() { +// UseSnakeCase sets snake_case field naming strategy. +func (g *Generator) UseSnakeCase() { g.fieldNamer = SnakeCaseFieldNamer{} } @@ -280,7 +273,7 @@ func (g *Generator) safeName(t reflect.Type) string { part = []rune{} } } - return g.functionNamer.GetName(false, parts...) + return joinFunctionNameParts(false, parts...) } // functionName returns a function name for a given type with a given prefix. If a function @@ -288,8 +281,8 @@ func (g *Generator) safeName(t reflect.Type) string { // // Method is used to track encoder/decoder names for the type. func (g *Generator) functionName(prefix string, t reflect.Type) string { - prefix = g.functionNamer.GetName(true, "easyjson", g.hashString, prefix) - name := g.functionNamer.GetName(true, prefix, g.safeName(t)) + prefix = joinFunctionNameParts(true, "easyjson", g.hashString, prefix) + name := joinFunctionNameParts(true, prefix, g.safeName(t)) // Most of the names will be unique, try a shortcut first. if e, ok := g.functionNames[name]; !ok || e == t { @@ -384,10 +377,7 @@ func (SnakeCaseFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructFiel return camelToSnake(f.Name) } -// CamelCaseFunctionNamer implements FunctionNamer interface with CamelCase format -type CamelCaseFunctionNamer struct{} - -func (CamelCaseFunctionNamer) GetName(keepFirst bool, parts ...string) string { +func joinFunctionNameParts(keepFirst bool, parts ...string) string { buf := bytes.NewBufferString("") for i, part := range parts { if i == 0 && keepFirst { diff --git a/gen/generator_test.go b/gen/generator_test.go index ee77d17..d7b6b0f 100644 --- a/gen/generator_test.go +++ b/gen/generator_test.go @@ -4,13 +4,6 @@ import ( "testing" ) -type functionNamerCase struct { - keepFirst bool - parts []string - camelCaseOut string - underScoreOut string -} - func TestCamelToSnake(t *testing.T) { for i, test := range []struct { In, Out string @@ -35,23 +28,22 @@ func TestCamelToSnake(t *testing.T) { } } -func getFunctionNamerCases() []functionNamerCase { - return []functionNamerCase{ - functionNamerCase{false, []string{}, "", ""}, - functionNamerCase{false, []string{"a"}, "A", "a"}, - functionNamerCase{false, []string{"simple", "example"}, "SimpleExample", "simple_example"}, - functionNamerCase{true, []string{"first", "example"}, "firstExample", "first_example"}, - functionNamerCase{false, []string{"some", "UPPER", "case"}, "SomeUPPERCase", "some_UPPER_case"}, - functionNamerCase{false, []string{"number", "123"}, "Number123", "number_123"}, - } -} - -func TestCamelCaseFunctionNamer(t *testing.T) { - namer := CamelCaseFunctionNamer{} - for i, test := range getFunctionNamerCases() { - got := namer.GetName(test.keepFirst, test.parts...) - if got != test.camelCaseOut { - t.Errorf("[%d] CamelCaseFunctionNamer.GetName(%v) = %s; want %s", i, test.parts, got, test.camelCaseOut) +func TestJoinFunctionNameParts(t *testing.T) { + for i, test := range []struct { + keepFirst bool + parts []string + out string + }{ + {false, []string{}, ""}, + {false, []string{"a"}, "A"}, + {false, []string{"simple", "example"}, "SimpleExample"}, + {true, []string{"first", "example"}, "firstExample"}, + {false, []string{"some", "UPPER", "case"}, "SomeUPPERCase"}, + {false, []string{"number", "123"}, "Number123"}, + } { + got := joinFunctionNameParts(test.keepFirst, test.parts...) + if got != test.out { + t.Errorf("[%d] joinFunctionNameParts(%v) = %s; want %s", i, test.parts, got, test.out) } } }