From f35f8da02f23797ef28e525f15e1b88d5b5e288e Mon Sep 17 00:00:00 2001 From: Vojtech Vitek Date: Tue, 5 Mar 2019 18:59:47 -0500 Subject: [PATCH] Implement CamelCase via new state machine --- helpers.go | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ helpers_test.go | 25 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 helpers.go create mode 100644 helpers_test.go diff --git a/helpers.go b/helpers.go new file mode 100644 index 0000000..c8f47ef --- /dev/null +++ b/helpers.go @@ -0,0 +1,64 @@ +package goose + +import ( + "strings" + "unicode" + "unicode/utf8" +) + +type camelSnakeStateMachine int + +const ( + begin camelSnakeStateMachine = iota // 0 + firstAlphaNum // 1 + alphaNum // 2 + delimiter // 3 +) + +func (s camelSnakeStateMachine) next(r rune) camelSnakeStateMachine { + switch s { + case begin: + if isAlphaNum(r) { + return firstAlphaNum + } + case firstAlphaNum: + if isAlphaNum(r) { + return alphaNum + } else { + return delimiter + } + case alphaNum: + if !isAlphaNum(r) { + return delimiter + } + case delimiter: + if isAlphaNum(r) { + return firstAlphaNum + } else { + return begin + } + } + return s +} + +func lowerCamelCase(str string) string { + var b strings.Builder + + stateMachine := begin + for i := 0; i < len(str); { + r, size := utf8.DecodeRuneInString(str[i:]) + i += size + stateMachine = stateMachine.next(r) + switch stateMachine { + case firstAlphaNum: + b.WriteRune(unicode.ToUpper(r)) + case alphaNum: + b.WriteRune(unicode.ToLower(r)) + } + } + return b.String() +} + +func isAlphaNum(r rune) bool { + return unicode.IsLetter(r) || unicode.IsNumber(r) +} diff --git a/helpers_test.go b/helpers_test.go new file mode 100644 index 0000000..bf8a3d7 --- /dev/null +++ b/helpers_test.go @@ -0,0 +1,25 @@ +package goose + +import ( + "testing" +) + +func TestCamelSnake(t *testing.T) { + tt := []struct { + in string + camel string + snake string + }{ + {in: "Add updated_at to users table", camel: "addUpdatedAtToUsersTable", snake: "add_updated_at_to_users_table"}, + {in: "$()&^%(_--crazy__--input$)", camel: "crazyInput", snake: "crazy_input"}, + } + + for _, test := range tt { + if got := lowerCamelCase(test.in); got != test.camel { + t.Errorf("unexpected lower camel for input(%q), got %q, want %q", test.in, got, test.camel) + } + // if got := snake(test.in); got != test.snake { + // t.Error("unexpected snake for input(%q), got %q, want %q", test.in, got, test.snake) + // } + } +}