From 60b8bcfe44cd6b465ce46693bb6988105ed2e482 Mon Sep 17 00:00:00 2001 From: Brad Reed Date: Sun, 18 Jun 2017 20:24:19 +0100 Subject: [PATCH 1/5] Add lower camel case --- bootstrap/bootstrap.go | 4 ++++ easyjson/main.go | 2 ++ gen/generator.go | 25 +++++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index 0322511..4729d18 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -24,6 +24,7 @@ type Generator struct { NoStdMarshalers bool SnakeCase bool + LowerCamelCase bool OmitEmpty bool OutName string @@ -110,6 +111,9 @@ func (g *Generator) writeMain() (path string, err error) { if g.SnakeCase { fmt.Fprintln(f, " g.UseSnakeCase()") } + if g.SnakeCase { + fmt.Fprintln(f, " g.UseLowerCamelCase()") + } if g.OmitEmpty { fmt.Fprintln(f, " g.OmitEmpty()") } diff --git a/easyjson/main.go b/easyjson/main.go index 6287926..1c39497 100644 --- a/easyjson/main.go +++ b/easyjson/main.go @@ -18,6 +18,7 @@ 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 lowerCamelCase = flag.Bool("lower_camel_case", false, "use lowerCamelCase names instead of CamelCase by default") var noStdMarshalers = flag.Bool("no_std_marshalers", false, "don't generate MarshalJSON/UnmarshalJSON funcs") var omitEmpty = flag.Bool("omit_empty", false, "omit empty fields by default") var allStructs = flag.Bool("all", false, "generate marshaler/unmarshalers for all structs in a file") @@ -59,6 +60,7 @@ func generate(fname string) (err error) { PkgName: p.PkgName, Types: p.StructNames, SnakeCase: *snakeCase, + LowerCamelCase: *lowerCamelCase, NoStdMarshalers: *noStdMarshalers, OmitEmpty: *omitEmpty, LeaveTemps: *leaveTemps, diff --git a/gen/generator.go b/gen/generator.go index 988a3a5..4e8c5b8 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" "unicode" + "unicode/utf8" ) const pkgWriter = "github.com/mailru/easyjson/jwriter" @@ -99,6 +100,11 @@ func (g *Generator) UseSnakeCase() { g.fieldNamer = SnakeCaseFieldNamer{} } +// UseLowerCamelCase sets lowerCamelCase field naming strategy. +func (g *Generator) UseLowerCamelCase() { + g.fieldNamer = LowerCamelCaseFieldNamer{} +} + // NoStdMarshalers instructs not to generate standard MarshalJSON/UnmarshalJSON // methods (only the custom interface). func (g *Generator) NoStdMarshalers() { @@ -374,6 +380,25 @@ func (DefaultFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructField) } } +// LowerCamelCaseFieldNamer +type LowerCamelCaseFieldNamer struct {} +func lowerFirst(s string) string { + if s == "" { + return "" + } + r, n := utf8.DecodeRuneInString(s) + return string(unicode.ToLower(r)) + s[n:] +} + +func (LowerCamelCaseFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructField) string { + jsonName := strings.Split(f.Tag.Get("json"), ",")[0] + if jsonName != "" { + return jsonName + } else { + return lowerFirst(f.Name) + } +} + // SnakeCaseFieldNamer implements CamelCase to snake_case conversion for fields names. type SnakeCaseFieldNamer struct{} From 0ff8e2bbb17f09dd906777aabe1e4a6a2e6ed9f5 Mon Sep 17 00:00:00 2001 From: Brad Reed Date: Sun, 18 Jun 2017 20:41:21 +0100 Subject: [PATCH 2/5] Use lower camel case in code --- bootstrap/bootstrap.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index 4729d18..3c20e09 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -111,7 +111,7 @@ func (g *Generator) writeMain() (path string, err error) { if g.SnakeCase { fmt.Fprintln(f, " g.UseSnakeCase()") } - if g.SnakeCase { + if g.LowerCamelCase { fmt.Fprintln(f, " g.UseLowerCamelCase()") } if g.OmitEmpty { From a85f348fff95e77b846a1175ff030bb32024b7e9 Mon Sep 17 00:00:00 2001 From: Brad Reed Date: Mon, 19 Jun 2017 22:15:04 +0100 Subject: [PATCH 3/5] Test and improved, non-stupid camel case conversion --- gen/generator.go | 54 ++++++++++++++++++++++++++++++++++++++++--- gen/generator_test.go | 22 ++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/gen/generator.go b/gen/generator.go index 4e8c5b8..cae11b6 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -11,7 +11,6 @@ import ( "strconv" "strings" "unicode" - "unicode/utf8" ) const pkgWriter = "github.com/mailru/easyjson/jwriter" @@ -382,12 +381,61 @@ func (DefaultFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructField) // LowerCamelCaseFieldNamer type LowerCamelCaseFieldNamer struct {} + +func isLower(b byte) bool { + return b <= 122 && b >= 97 +} + +func isUpper(b byte) bool { + return b >= 65 && b <= 90 +} + +func isNumeric(b byte) bool { + return b >= 48 && b <= 57 +} +// convert HTTPRestClient to httpRestClient func lowerFirst(s string) string { if s == "" { return "" } - r, n := utf8.DecodeRuneInString(s) - return string(unicode.ToLower(r)) + s[n:] + + str := "" + strlen := len(s) + + /** + Loop each char + If is uppercase: + If is first char, LOWER it + If the following char is lower, LEAVE it + If the following char is upper OR numeric, LOWER it + If is the end of string, LEAVE it + Else lowercase + */ + + foundLower := false + for i := range s { + ch := s[i] + if isUpper(ch) { + if i == 0 { + str += string(ch + 32) + } else if !foundLower { // Currently just a stream of capitals, eg JSONRESTS[erver] + if strlen > (i+1) && isLower(s[i+1]) { + // Next char is lower, keep this a capital + str += string(ch) + } else { + // Either at end of string or next char is capital + str += string(ch + 32) + } + } else { + str += string(ch) + } + } else { + foundLower = true + str += string(ch) + } + } + + return str } func (LowerCamelCaseFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructField) string { diff --git a/gen/generator_test.go b/gen/generator_test.go index 62c03f0..0c9d278 100644 --- a/gen/generator_test.go +++ b/gen/generator_test.go @@ -28,6 +28,28 @@ func TestCamelToSnake(t *testing.T) { } } +func TestCamelToLowerCamel(t *testing.T) { + for i, test := range []struct { + In, Out string + }{ + {"", ""}, + {"A", "a"}, + {"SimpleExample", "simpleExample"}, + {"internalField", "internalField"}, + + {"SomeHTTPStuff", "someHTTPStuff"}, + {"WriteJSON", "writeJSON"}, + {"HTTP2Server", "http2Server"}, + + {"JSONHTTPRPCServer", "jsonhttprpcServer"}, // nothing can be done here without a dictionary + } { + got := lowerFirst(test.In) + if got != test.Out { + t.Errorf("[%d] lowerFirst(%s) = %s; want %s", i, test.In, got, test.Out) + } + } +} + func TestJoinFunctionNameParts(t *testing.T) { for i, test := range []struct { keepFirst bool From e5d2669ceb1f0379bba6a7fdd38677ed78839a8b Mon Sep 17 00:00:00 2001 From: Brad Reed Date: Thu, 22 Jun 2017 09:46:32 +0100 Subject: [PATCH 4/5] Update Readme.md for lowerCamelCase --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9cb8845..33b21cf 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ Usage of easyjson: process the whole package instead of just the given file -snake_case use snake_case names instead of CamelCase by default + --lower-camel-case + use lowerCamelCase instead of CamelCase by default -stubs only generate stubs for marshaler/unmarshaler funcs ``` From db1280d62a3125e93eee91cb866a3bc2cfaf8b10 Mon Sep 17 00:00:00 2001 From: Brad Reed Date: Thu, 22 Jun 2017 09:47:48 +0100 Subject: [PATCH 5/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33b21cf..a33b5b0 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Usage of easyjson: process the whole package instead of just the given file -snake_case use snake_case names instead of CamelCase by default - --lower-camel-case + -lower_camel_case use lowerCamelCase instead of CamelCase by default -stubs only generate stubs for marshaler/unmarshaler funcs