diff --git a/camel.go b/camel.go index 4aab39a..bd55a1d 100644 --- a/camel.go +++ b/camel.go @@ -32,28 +32,18 @@ import ( // Converts a string to CamelCase func toCamelInitCase(s string, initCase bool) string { s = addWordBoundariesToNumbers(s) - s = strings.Trim(s, " ") n := "" capNext := initCase for _, v := range s { - if v >= 'A' && v <= 'Z' { + if capNext && v >= 'a' && v <= 'z' { + v = int32(strings.ToUpper(string(v))[0]) + } + if (v >= 'A' && v <= 'Z') || + (v >= 'a' && v <= 'z') || + (v >= '0' && v <= '9') { n += string(v) } - if v >= '0' && v <= '9' { - n += string(v) - } - if v >= 'a' && v <= 'z' { - if capNext { - n += strings.ToUpper(string(v)) - } else { - n += string(v) - } - } - if v == '_' || v == ' ' || v == '-' || v == '.' { - capNext = true - } else { - capNext = false - } + capNext = v == '_' || v == ' ' || v == '-' || v == '.' } return n } @@ -73,8 +63,7 @@ func ToLowerCamel(s string) string { } if uppercaseAcronym[s] { s = strings.ToLower(s) - } - if r := rune(s[0]); r >= 'A' && r <= 'Z' { + } else if r := s[0]; r >= 'A' && r <= 'Z' { s = strings.ToLower(string(r)) + s[1:] } return toCamelInitCase(s, false) diff --git a/camel_test.go b/camel_test.go index c5a0101..bacf8f7 100644 --- a/camel_test.go +++ b/camel_test.go @@ -47,7 +47,7 @@ func toCamel(tb testing.TB) { out := i[1] result := ToCamel(in) if result != out { - tb.Error("'" + result + "' != '" + out + "'") + tb.Errorf("%q (%q != %q)", in, result, out) } } } @@ -74,7 +74,7 @@ func toLowerCamel(tb testing.TB) { out := i[1] result := ToLowerCamel(in) if result != out { - tb.Error("'" + result + "' != '" + out + "'") + tb.Errorf("%q (%q != %q)", in, result, out) } } } diff --git a/snake.go b/snake.go index 8e8867b..30223f4 100644 --- a/snake.go +++ b/snake.go @@ -31,11 +31,10 @@ import ( // ToSnake converts a string to snake_case func ToSnake(s string) string { - return ToDelimited(s, '_') } -func ToSnakeWithIgnore(s string, ignore uint8) string { +func ToSnakeWithIgnore(s string, ignore uint8) string { return ToScreamingDelimited(s, '_', ignore, false) } @@ -70,37 +69,34 @@ func ToScreamingDelimited(s string, delimiter uint8, ignore uint8, screaming boo n := "" for i, v := range s { // treat acronyms as words, eg for JSONData -> JSON is a whole word - nextCaseIsChanged := false if i+1 < len(s) { next := s[i+1] vIsCap := v >= 'A' && v <= 'Z' vIsLow := v >= 'a' && v <= 'z' nextIsCap := next >= 'A' && next <= 'Z' nextIsLow := next >= 'a' && next <= 'z' + // add underscore if next letter case type is changed if (vIsCap && nextIsLow) || (vIsLow && nextIsCap) { - nextCaseIsChanged = true - } - if ignore > 0 && i-1 >= 0 && s[i-1] == ignore && nextCaseIsChanged { - nextCaseIsChanged = false + if prevIgnore := ignore > 0 && i > 0 && s[i-1] == ignore; !prevIgnore { + if i > 0 && vIsCap && nextIsLow { + if prevDelim := len(n) > 0 && n[len(n)-1] == delimiter; !prevDelim { + n += string(delimiter) + } + } + n += string(v) + if vIsLow { + n += string(delimiter) + } + continue + } } } - if i > 0 && n[len(n)-1] != delimiter && nextCaseIsChanged { - // add underscore if next letter case type is changed - if v >= 'A' && v <= 'Z' { - n += string(delimiter) + string(v) - } else if v >= 'a' && v <= 'z' { - n += string(v) + string(delimiter) - } - } else if v == ' ' || v == '_' || v == '-' { - // replace spaces/underscores with delimiters - if uint8(v) == ignore { - n += string(v) - } else { - n += string(delimiter) - } + if (v == ' ' || v == '_' || v == '-') && uint8(v) != ignore { + // replace space/underscore/hyphen with delimiter + n += string(delimiter) } else { - n = n + string(v) + n += string(v) } } diff --git a/snake_test.go b/snake_test.go index fbdb29e..7f89e4b 100644 --- a/snake_test.go +++ b/snake_test.go @@ -54,7 +54,7 @@ func toSnake(tb testing.TB) { out := i[1] result := ToSnake(in) if result != out { - tb.Error("'" + in + "'('" + result + "' != '" + out + "')") + tb.Errorf("%q (%q != %q)", in, result, out) } } } @@ -82,8 +82,8 @@ func toSnakeWithIgnore(tb testing.TB) { {"AnyKind of_string", "any_kind_of_string"}, {"numbers2and55with000", "numbers_2_and_55_with_000"}, {"JSONData", "json_data"}, - {"AwesomeAcitvity.UserID", "awesome_acitvity.user_id", "."}, - {"AwesomeAcitvity.User.Id", "awesome_acitvity.user.id", "."}, + {"AwesomeActivity.UserID", "awesome_activity.user_id", "."}, + {"AwesomeActivity.User.Id", "awesome_activity.user.id", "."}, {"AwesomeUsername@Awesome.Com", "awesome_username@awesome._com", "@"}, } for _, i := range cases { @@ -95,7 +95,11 @@ func toSnakeWithIgnore(tb testing.TB) { } result := ToSnakeWithIgnore(in, ignore) if result != out { - tb.Error("'" + in + "'('" + result + "' != '" + out + "')") + istr := "" + if len(i) == 3 { + istr = " ignoring '" + i[2] + "'" + } + tb.Errorf("%q (%q != %q%s)", in, result, out, istr) } } } @@ -132,7 +136,7 @@ func toDelimited(tb testing.TB) { out := i[1] result := ToDelimited(in, '@') if result != out { - tb.Error("'" + in + "' ('" + result + "' != '" + out + "')") + tb.Errorf("%q (%q != %q)", in, result, out) } } } @@ -152,7 +156,7 @@ func toScreamingSnake(tb testing.TB) { out := i[1] result := ToScreamingSnake(in) if result != out { - tb.Error("'" + result + "' != '" + out + "'") + tb.Errorf("%q (%q != %q)", in, result, out) } } } @@ -172,7 +176,7 @@ func toKebab(tb testing.TB) { out := i[1] result := ToKebab(in) if result != out { - tb.Error("'" + result + "' != '" + out + "'") + tb.Errorf("%q (%q != %q)", in, result, out) } } } @@ -192,7 +196,7 @@ func toScreamingKebab(tb testing.TB) { out := i[1] result := ToScreamingKebab(in) if result != out { - tb.Error("'" + result + "' != '" + out + "'") + tb.Errorf("%q (%q != %q)", in, result, out) } } } @@ -212,7 +216,7 @@ func toScreamingDelimited(tb testing.TB) { out := i[1] result := ToScreamingDelimited(in, '.', 0, true) if result != out { - tb.Error("'" + result + "' != '" + out + "'") + tb.Errorf("%q (%q != %q)", in, result, out) } } } @@ -230,11 +234,15 @@ func toScreamingDelimitedWithIgnore(tb testing.TB) { for _, i := range cases { in := i[0] out := i[1] - delimiter := uint8(i[2][0]) - ignore := uint8(i[3][0]) + delimiter := i[2][0] + ignore := i[3][0] result := ToScreamingDelimited(in, delimiter, ignore, true) if result != out { - tb.Error("'" + result + "' != '" + out + "'") + istr := "" + if len(i) == 4 { + istr = " ignoring '" + i[3] + "'" + } + tb.Errorf("%q (%q != %q%s)", in, result, out, istr) } } }