From b2dc5d83a3192cd52e1678f0e54dc67b10eefe93 Mon Sep 17 00:00:00 2001 From: Leonardo Di Donato Date: Thu, 25 Jan 2024 16:14:57 +0100 Subject: [PATCH 1/5] chore: ignore snake2camel binary Signed-off-by: Leonardo Di Donato --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 89d4bc5..427454f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ *.txt vendor/ -/removecomments \ No newline at end of file +/removecomments +/snake2camel \ No newline at end of file From f0bd047350558b96f0d7532688a92377db33e004 Mon Sep 17 00:00:00 2001 From: Leonardo Di Donato Date: Thu, 25 Jan 2024 16:15:54 +0100 Subject: [PATCH 2/5] build: use a go tool to transform snake case strings in the resulting Go file Signed-off-by: Leonardo Di Donato --- makefile | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/makefile b/makefile index df87cdc..08a1408 100644 --- a/makefile +++ b/makefile @@ -15,18 +15,24 @@ clean: .PHONY: images images: docs/urn.png +.PHONY: snake2camel +snake2camel: + @cd ./tools/snake2camel; go build -o ../../snake2camel . + .PHONY: removecomments removecomments: @cd ./tools/removecomments; go build -o ../../removecomments . machine.go: machine.go.rl +machine.go: snake2camel + machine.go: removecomments machine.go: $(RAGEL) -Z -G2 -e -o $@ $< @./removecomments $@ - $(MAKE) -s file=$@ snake2camel + @./snake2camel $@ $(GOFMT) $@ docs/urn.dot: machine.go.rl @@ -41,13 +47,5 @@ bench: *_test.go machine.go go test -bench=. -benchmem -benchtime=5s ./... .PHONY: tests -tests: *_test.go +tests: *_test.go $(GO_TEST) ./... - -.PHONY: snake2camel -snake2camel: - @awk -i inplace '{ \ - while ( match($$0, /(.*)([a-z]+[0-9]*)_([a-zA-Z0-9])(.*)/, cap) ) \ - $$0 = cap[1] cap[2] toupper(cap[3]) cap[4]; \ - print \ - }' $(file) From c41432548e4bf368c255b2e044d1591077532bda Mon Sep 17 00:00:00 2001 From: Leonardo Di Donato Date: Thu, 25 Jan 2024 16:21:35 +0100 Subject: [PATCH 3/5] build: prepare snake2camel go module Signed-off-by: Leonardo Di Donato --- tools/snake2camel/go.mod | 3 +++ tools/snake2camel/go.sum | 0 urn.go | 6 +++--- 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 tools/snake2camel/go.mod create mode 100644 tools/snake2camel/go.sum diff --git a/tools/snake2camel/go.mod b/tools/snake2camel/go.mod new file mode 100644 index 0000000..735113b --- /dev/null +++ b/tools/snake2camel/go.mod @@ -0,0 +1,3 @@ +module github.com/leodido/go-urn/tools/snake2camel + +go 1.21.6 diff --git a/tools/snake2camel/go.sum b/tools/snake2camel/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/urn.go b/urn.go index 6415386..fa9fa3a 100644 --- a/urn.go +++ b/urn.go @@ -17,8 +17,8 @@ const errInvalidURN = "invalid URN: %s" // Details at https://tools.ietf.org/html/rfc2141. type URN struct { prefix string // Static prefix. Equal to "urn" when empty. - ID string // Namespace identifier - SS string // Namespace specific string + ID string // Namespace identifier (NID) + SS string // Namespace specific string (NSS) norm string // Normalized namespace specific string } @@ -71,7 +71,7 @@ func (u URN) MarshalJSON() ([]byte, error) { return json.Marshal(u.String()) } -// MarshalJSON unmarshals a URN from JSON string form (e.g. `"urn:oid:1.2.3.4"`). +// UnmarshalJSON unmarshals a URN from JSON string form (e.g. `"urn:oid:1.2.3.4"`). func (u *URN) UnmarshalJSON(bytes []byte) error { var str string if err := json.Unmarshal(bytes, &str); err != nil { From e94e1a06315a9a1da2192e0dbd1011325d66e3d2 Mon Sep 17 00:00:00 2001 From: Leonardo Di Donato Date: Thu, 25 Jan 2024 16:21:55 +0100 Subject: [PATCH 4/5] feat: implement snake2camel go module Signed-off-by: Leonardo Di Donato --- tools/snake2camel/snake2camel.go | 69 ++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tools/snake2camel/snake2camel.go diff --git a/tools/snake2camel/snake2camel.go b/tools/snake2camel/snake2camel.go new file mode 100644 index 0000000..4dcac37 --- /dev/null +++ b/tools/snake2camel/snake2camel.go @@ -0,0 +1,69 @@ +package main + +import ( + "fmt" + "os" + "regexp" + "strings" +) + +func exitWithError(msg string) { + err := fmt.Sprintf("error: %s\n", msg) + fmt.Fprintln(os.Stderr, err) + os.Exit(1) +} + +func replaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) (string, int) { + result := "" + lastIndex := 0 + + for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) { + groups := []string{} + for i := 0; i < len(v); i += 2 { + if v[i] == -1 || v[i+1] == -1 { + groups = append(groups, "") + } else { + groups = append(groups, str[v[i]:v[i+1]]) + } + } + + result += str[lastIndex:v[0]] + repl(groups) + lastIndex = v[1] + } + + return result + str[lastIndex:], lastIndex +} + +func snake2camel(content []byte) []byte { + re := regexp.MustCompile(`(.*)([a-z]+[0-9]*)_([a-zA-Z0-9])(.*)`) + res := string(content) + last := -1 + + for last != 0 { + res, last = replaceAllStringSubmatchFunc(re, res, func(groups []string) string { + return groups[1] + groups[2] + strings.ToUpper(groups[3]) + groups[4] + }) + } + + return []byte(res) +} + +func snake2camelFile(path string) error { + content, err := os.ReadFile(path) + if err != nil { + return err + } + updated := snake2camel(content) + + return os.WriteFile(path, updated, 0) +} + +func main() { + if len(os.Args) != 2 { + exitWithError("must be called with the file path as the only argument") + } + path := os.Args[1] + if err := snake2camelFile(path); err != nil { + exitWithError(err.Error()) + } +} From 08677f70e8d0b5917af66a21053e1ed0e7bba5e3 Mon Sep 17 00:00:00 2001 From: Leonardo Di Donato Date: Thu, 25 Jan 2024 16:22:10 +0100 Subject: [PATCH 5/5] test: test snake2camel Signed-off-by: Leonardo Di Donato --- tools/snake2camel/snake2camel_test.go | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 tools/snake2camel/snake2camel_test.go diff --git a/tools/snake2camel/snake2camel_test.go b/tools/snake2camel/snake2camel_test.go new file mode 100644 index 0000000..5380704 --- /dev/null +++ b/tools/snake2camel/snake2camel_test.go @@ -0,0 +1,60 @@ +package main + +import ( + "fmt" + "testing" +) + +func TestSnake2CamelNoReplace(t *testing.T) { + txt := `const start int = 1` + + exp := `const start int = 1` + + got := snake2camel([]byte(txt)) + if string(got) != exp { + fmt.Printf("expected length: %d, got %d\n", len(exp), len(got)) + t.Fatalf("expected:\n%s\ngot:\n%s", exp, got) + } +} + +func TestSnake2CamelOneUnderscore(t *testing.T) { + txt := `const en_urn int = 5 + const en_scim int = 44 + const en_fail int = 81 + const en_main int = 1` + + exp := `const enUrn int = 5 + const enScim int = 44 + const enFail int = 81 + const enMain int = 1` + + got := snake2camel([]byte(txt)) + if string(got) != exp { + fmt.Printf("expected length: %d, got %d\n", len(exp), len(got)) + t.Fatalf("expected:\n%s\ngot:\n%s", exp, got) + } +} + +func TestSnake2CamelMoreUnderscores(t *testing.T) { + txt := `if (m.p) == (m.pe) { + goto _test_eof + } + switch m.cs { + case 1: + goto st_case_1 + }` + + exp := `if (m.p) == (m.pe) { + goto _testEof + } + switch m.cs { + case 1: + goto stCase1 + }` + + got := snake2camel([]byte(txt)) + if string(got) != exp { + fmt.Printf("expected length: %d, got %d\n", len(exp), len(got)) + t.Fatalf("expected:\n%s\ngot:\n%s", exp, got) + } +}